diff --git a/README.rst b/README.rst
index d45b6ea6e..a8377c82e 100644
--- a/README.rst
+++ b/README.rst
@@ -8,7 +8,7 @@ Documentation
xCAT documentation is available at: http://xcat-docs.readthedocs.io/en/latest/
-|docs_latest| |docs_2136| |docs_2135| |docs_2134| |docs_2133| |docs_2132| |docs_2131| |docs_2130| |docs_212|
+|docs_latest| |docs_2137| |docs_2136| |docs_2135| |docs_2134| |docs_2133| |docs_2132| |docs_2131| |docs_2130| |docs_212|
Open Source License
-------------------
@@ -22,6 +22,11 @@ Developers
Developers and prospective contributors are encouraged to read the `Developers Guide `_
In particular the `GitHub `_ related subsection.
+.. |docs_2137| image:: https://readthedocs.org/projects/xcat-docs/badge/?version=2.13.7
+ :alt: 2.13.7 documentation status
+ :scale: 100%
+ :target: http://xcat-docs.readthedocs.io/en/2.13.7/
+
.. |docs_2136| image:: https://readthedocs.org/projects/xcat-docs/badge/?version=2.13.6
:alt: 2.13.6 documentation status
:scale: 100%
diff --git a/Version b/Version
index ea55a03fa..c38dd67f3 100644
--- a/Version
+++ b/Version
@@ -1 +1 @@
-2.13.7
+2.13.8
diff --git a/docs/source/advanced/hamn/setup_ha_mgmt_node_with_shared_data.rst b/docs/source/advanced/hamn/setup_ha_mgmt_node_with_shared_data.rst
index 3eff968e6..5a2d7ae3f 100644
--- a/docs/source/advanced/hamn/setup_ha_mgmt_node_with_shared_data.rst
+++ b/docs/source/advanced/hamn/setup_ha_mgmt_node_with_shared_data.rst
@@ -33,13 +33,13 @@ Configuration Requirements
#. Setting up HAMN can be done at any time during the life of the cluster, in this documentation we assume the HAMN setup is done from the very beginning of the xCAT cluster setup, there will be some minor differences if the HAMN setup is done from the middle of the xCAT cluster setup.
-The example given in this document is for RHEL 6. The same approach can be applied to SLES, but the specific commands might be slightly different. The examples in this documentation are based on the following cluster environment:
+The example given in this document is for RHEL 6/7. The same approach can be applied to SLES, but the specific commands might be slightly different. The examples in this documentation are based on the following cluster environment:
-Virtual IP Alias Address: 9.114.47.97
+Virtual IP Alias Address: 9.114.47.97, hostname is rhmn
-Primary Management Node: rhmn1(9.114.47.103), netmask is 255.255.255.192, hostname is rhmn1, running RHEL 6.
+Primary Management Node: rhmn1(9.114.47.103), netmask is 255.255.255.192, hostname is rhmn1, running RHEL 7.
-Standby Management Node: rhmn2(9.114.47.104), netmask is 255.255.255.192, hostname is rhmn2. Running RHEL 6.
+Standby Management Node: rhmn2(9.114.47.104), netmask is 255.255.255.192, hostname is rhmn2. Running RHEL 7.
You need to substitute the hostnames and ip address with your own values when setting up your HAMN environment.
@@ -53,7 +53,8 @@ The configuration procedure will be quite different based on the shared data mec
/etc/xcat
/install
~/.xcat
- /
+ /
+ /tftpboot
``Note``:For MySQL, the database directory is ``/var/lib/mysql``; for PostGreSQL, the database directory is ``/var/lib/pgsql``; for DB2, the database directory is specified with the site attribute databaseloc; for sqlite, the database directory is /etc/xcat, already listed above.
@@ -64,6 +65,7 @@ Here is an example of how to make directories be shared data through NFS: ::
mount -o rw :/dir2 /install
mount -o rw :/dir3 ~/.xcat
mount -o rw :/dir4 /
+ mount -o rw :/dir5 /tftpboot
``Note``: if you need to setup high availability for some other applications, like the HPC software stack, between the two xCAT management nodes, the applications data should be on the shared data.
@@ -78,9 +80,9 @@ Setup xCAT on the Primary Management Node
The option ``firstalias`` will configure the Virtual IP ahead of the interface ip address, since ifconfig will not make the ip address configuration be persistent through reboots, so the Virtual IP address needs to be re-configured right after the management node is rebooted. This non-persistent Virtual IP address is designed to avoid ip address conflict when the crashed previous primary management is recovered with the Virtual IP address configured.
-#. Add the alias ip address into the ``/etc/resolv.conf`` as the nameserver. Change the hostname resolution order to be using ``/etc/hosts`` before using name server, change to "hosts: files dns" in ``/etc/nsswitch.conf``.
+#. Add the alias ip address ``9.114.47.97`` into the ``/etc/resolv.conf`` as the nameserver. Change the hostname resolution order to be using ``/etc/hosts`` before using name server, change to "hosts: files dns" in ``/etc/nsswitch.conf``.
-#. Change hostname to the hostname that resolves to the Virtual IP address. This is required for xCAT and database to be setup properly.
+#. Change hostname to the hostname that resolves to the Virtual IP address ``9.114.47.97``, add the alias ip address and its hostname ``9.114.47.97 rhmn`` into the ``/etc/hosts``. This is required for xCAT and database to be setup properly.
#. Install xCAT. The procedure described in :doc:`xCAT Install Guide <../../guides/install-guides/index>` could be used for the xCAT setup on the primary management node.
@@ -99,17 +101,29 @@ Setup xCAT on the Primary Management Node
tabdump policy
"1.2","rhmn1",,,,,,"trusted",,
"1.3","rhmn2",,,,,,"trusted",,
+ "1.4","rhmn",,,,,,"trusted",,
#. (Optional) DB2 only, change the databaseloc in site table: ::
chdef -t site databaseloc=/dbdirectory
-#. Install and configure database. Refer to the doc [**doto:** choosing_the_Database] to configure the database on the xCAT management node.
+#. Install and configure database. Refer to the doc [**doto:** choosing_the_Database] to configure the database on the xCAT management node. For PostgreSql, add primary and standby IP addresses access to database, use ``pgsqlsetup -i -a 9.114.47.103 -a 9.114.47.104`` to migrate an existing xCAT database from SQLite to PostgreSQL.
Verify xcat is running on correct database by running: ::
lsxcatd -a
+#. (Optional) PostgreSQL only, if want to change PostgreSql database location, new database directory should be shared data through NFS: ::
+
+ mkdir /
+ mount -o rw :/dir6 /
+
+ Then refer to :ref:`Modify PostgreSql database directory`.
+
+ Remove the old share data through NFS: ::
+
+ umount /
+
#. Backup the xCAT database tables for the current configuration on standby management node, using command : ::
dumpxCATdb -p .
@@ -125,15 +139,15 @@ Setup xCAT on the Primary Management Node
service dhcpd stop
chkconfig --level 2345 dhcpd off
-#. Stop Database and prevent the database from auto starting at boot time, use MySQL as an example: ::
+#. Stop Database and prevent the database from auto starting at boot time, use PostgreSQL as an example::
- service mysqld stop
- chkconfig mysqld off
+ service postgresql stop
+ chkconfig postgresql off
#. (Optional) If DFM is being used for hardware control capabilities, install DFM package, setup xCAT to communicate directly to the System P server's service processor.::
- xCAT-dfm RPM
- ISNM-hdwr_svr RPM
+ xCAT-dfm RPM
+ ISNM-hdwr_svr RPM
#. If there is any node that is already managed by the Management Node,change the noderes table tftpserver & xcatmaster & nfsserver attributes to the Virtual ip
@@ -144,11 +158,11 @@ Setup xCAT on the Primary Management Node
Setup xCAT on the Standby Management Node
=========================================
-#. Make sure the standby management node is NOT using the shared data.
+#. Make sure the standby management node is NOT using the shared data.
-#. Add the alias ip address into the ``/etc/resolv.conf`` as the nameserver. Change the hostname resolution order to be using ``/etc/hosts`` before using name server. Change "hosts: files dns" in /etc/nsswitch.conf.
+#. Add the alias ip address ``9.114.47.97`` into the ``/etc/resolv.conf`` as the nameserver. Change the hostname resolution order to be using ``/etc/hosts`` before using name server. Change "hosts: files dns" in /etc/nsswitch.conf.
-#. Temporarily change the hostname to the hostname that resolves to the Virtual IP address. This is required for xCAT and database to be setup properly. This only needs to be done one time.
+#. Temporarily change the hostname to the hostname that resolves to the Virtual IP address ``9.114.47.97``, add the alias ip address and its hostname ``9.114.47.97 rhmn`` into the ``/etc/hosts``. This is required for xCAT and database to be setup properly. This only needs to be done one time.
Also configure the Virtual IP address during this setup. ::
@@ -180,10 +194,10 @@ Setup xCAT on the Standby Management Node
service dhcpd stop
chkconfig --level 2345 dhcpd off
-#. Stop Database and prevent the database from auto starting at boot time. Use MySQL as an example: ::
+#. Stop Database and prevent the database from auto starting at boot time, use PostgreSQL as an example::
- service mysqld stop
- chkconfig mysqld off
+ service postgresql stop
+ chkconfig postgresql off
#. Backup the xCAT database tables for the current configuration on standby management node, using command: ::
@@ -275,10 +289,25 @@ In a planned failover, you can do necessary cleanup work on the previous primary
Take down the Current Primary Management Node
---------------------------------------------
-xCAT ships a sample script ``/opt/xcat/share/xcat/hamn/deactivate-mn`` to make the machine be a standby management node. Before using this script, you need to review the script carefully and make updates accordingly, here is an example of how to use this script: ::
+xCAT ships a sample script ``/opt/xcat/share/xcat/hamn/deactivate-mn`` to make the machine be a standby management node. Before using this script, you need to review the script carefully and make updates accordingly, correct the following variable values in this script: ::
+
+ SHAREDVG=sharedvg # For AIX, shared volumn group name
+ DBDIR=/var/lib/pgsql # database directory
+ SHAREDFS="/install /etc/xcat /root/.xcat /tftpboot" # Shared file systems
+ USEDB2=no # if DB2 is being used
+ USETEAL=no # if TEAL is being used
+ USEDFM=no # if DFM is being used
+ USEUNMOUNT=yes # umount share data directory
+ POWER775=no # Power 775 cluster
+ CHANGEHOSTNAME=no # change the hostname from virtual ip hostname to the original hostname
+ xcatdb=postgresql # support postgrel,DB2,mysql
+
+Here is an example of how to use this script: ::
/opt/xcat/share/xcat/hamn/deactivate-mn -i eth1:2 -v 9.114.47.97
+**Notes**: This script will be over-written after xCAT is upgraded. If this script is customized, make sure backup it before upgrading xCAT.
+
On the current primary management node:
If the management node is still available and running the cluster, perform the following steps to shutdown.
@@ -301,11 +330,9 @@ If the management node is still available and running the cluster, perform the f
exportfs -ua
-#. Stop database
+#. Stop database, use PostgreSQL as an example: ::
- Use MySQL as an example: ::
-
- service mysqld stop
+ service postgresql stop
#. Unmount shared data
@@ -314,7 +341,8 @@ If the management node is still available and running the cluster, perform the f
umount /etc/xcat
umount /install
umount ~/.xcat
- umount /db2database
+ umount /
+ umount /tftpboot
When trying to umount the file systems, if there are some processes that are accessing the files and directories on the file systems, you will get "Device busy" error. Then stop or kill all the processes that are accessing the shared data file systems and retry the unmount.
@@ -326,11 +354,26 @@ If the management node is still available and running the cluster, perform the f
Bring up the New Primary Management Node
----------------------------------------
+xCAT ships a sample script ``/opt/xcat/share/xcat/hamn/activate-mn`` to make the machine be a new primary management node. Before using this script, you need to review the script carefully and make updates accordingly, correct the following variable values in this script: ::
-Execute script ``/opt/xcat/share/xcat/hamn/activate-mn`` to make the machine be a primary management node: ::
+ SHAREDVG=sharedvg # For AIX, shared volumn group name
+ DBDIR=/var/lib/pgsql # database directory
+ SHAREDFS="/install /etc/xcat /root/.xcat" # Shared file systems
+ USEDFM=no # if DFM is being used
+ USENTP=no # if NTP is being used
+ POWER775=no # Power 775 cluster
+ USETEAL=no # if TEAL is being used
+ USEMOUNT=yes # mounted filesystems in the file /etc/fstab
+ CHANGEHOSTNAME=yes # set the hostname to the virtual ip address hostname
+ RESTARTDNS=yes # if yes, will execute "makedns -n"
+ xcatdb=postgresql # support postgrel,DB2,mysql
+
+Here is an example of how to use this script to make the machine be a primary management node: ::
/opt/xcat/share/xcat/hamn/activate-mn -i eth1:2 -v 9.114.47.97 -m 255.255.255.0
+**Notes**: This script will be over-written after xCAT is upgraded. If this script is customized, make sure backup it before upgrading xCAT.
+
On the new primary management node:
#. Configure Virtual IP: ::
@@ -344,18 +387,25 @@ On the new primary management node:
mount /etc/xcat
mount /install
mount /.xcat
- mount /db2database
+ mount /
+ mount /tftpboot
-#. Start database, use MySQL as an example: ::
+#. Start database:
- service mysql start
+ * **[MySQL]** ::
+
+ service mysql start
+
+ * **[PostgreSQL]** ::
+
+ service postgresql start
#. Start the daemons: ::
service dhcpd start
service xcatd start
- service hdwr_svr start
service conserver start
+ service hdwr_svr start # DFM only
#. (DFM only) Setup connection for CEC and Frame: ::
@@ -416,11 +466,12 @@ The operating system is installed on the internal disks.
Output will be similar to: ::
- /dev/sdd /dev/sdc /dev/sdb /dev/sda
+ /dev/sde /dev/sdd /dev/sdc /dev/sdb /dev/sda
/dev/sg0 [=/dev/sda scsi0 ch=0 id=1 lun=0]
/dev/sg1 [=/dev/sdb scsi0 ch=0 id=2 lun=0]
/dev/sg2 [=/dev/sdc scsi0 ch=0 id=3 lun=0]
/dev/sg3 [=/dev/sdd scsi0 ch=0 id=4 lun=0]
+ /dev/sg4 [=/dev/sde scsi0 ch=0 id=5 lun=0]
Use the ``sginfo -s `` to identify disks with the same serial number on both management nodes, for example:
@@ -454,6 +505,7 @@ The operating system is installed on the internal disks.
mkfs.ext3 -v /dev/sdc2
mkfs.ext3 -v /dev/sdc3
mkfs.ext3 -v /dev/sdc4
+ mkfs.ext3 -v /dev/sdc5
If you place entries for the disk in ``/etc/fstab``, which is not required, ensure that the entries do not have the system automatically mount the disk.
@@ -466,14 +518,16 @@ The operating system is installed on the internal disks.
mount /dev/sdc1 /etc/xcat
mount /dev/sdc2 /install
mount /dev/sdc3 ~/.xcat
- mount /dev/sdc4 /db2database
+ mount /dev/sdc4 /
+ mount /dev/sdc5 /tftpboot
After that, umount the file system on the primary management node: ::
umount /etc/xcat
umount /install
umount ~/.xcat
- umount /db2database
+ umount /
+ umount /tftpboot
#. Verify the file systems on the standby management node.
@@ -482,7 +536,8 @@ The operating system is installed on the internal disks.
mount /dev/sdc1 /etc/xcat
mount /dev/sdc2 /install
mount /dev/sdc3 ~/.xcat
- mount /dev/sdc4 /db2database
+ mount /dev/sdc4 /
+ mount /dev/sdc5/tftpboot
You may get errors "mount: you must specify the filesystem type" or "mount: special device /dev/sdb1 does not exist" when trying to mount the file systems on the standby management node, this is caused by the missing devices files on the standby management node, run ``fidsk /dev/sdx`` and simply select "w write table to disk and exit" in the fdisk menu, then retry the mount.
@@ -491,5 +546,6 @@ The operating system is installed on the internal disks.
umount /etc/xcat
umount /install
umount ~/.xcat
- umount /db2database
+ umount /
+ umount /tftpboot
diff --git a/docs/source/advanced/hierarchy/databases/postgres_configure.rst b/docs/source/advanced/hierarchy/databases/postgres_configure.rst
index 039b6c001..c9ce1e014 100644
--- a/docs/source/advanced/hierarchy/databases/postgres_configure.rst
+++ b/docs/source/advanced/hierarchy/databases/postgres_configure.rst
@@ -34,3 +34,64 @@ Restart PostgreSQL after editing the file: ::
For more information about changing the ``pg_hab.conf`` file and ``postgresql.conf`` files, see the following documentation:
`Setup the PostgreSQL Configuration Files `_
+
+.. _modify_postgresql_database_diretory:
+
+Modify PostgreSQL database directory
+------------------------------------
+
+#. Check the xcatdb have been switched to pgsql: ::
+
+ lsxcatd -a
+ Version 2.13.6 (git commit f8c0d11ff2c7c97d6e62389c0aafcdfa06cee1f6, built Mon Aug 7 07:15:47 EDT 2017)
+ This is a Management Node
+ cfgloc=Pg:dbname=xcatdb;host=10.3.5.100|xcatadm
+ dbengine=Pg
+ dbname=xcatdb
+ dbhost=10.3.5.100
+ dbadmin=xcatadm
+
+#. Check the current working directory: ::
+
+ sudo -u postgres psql
+ could not change directory to "/root"
+ psql (9.2.18)
+ Type "help" for help.
+
+ postgres=# SHOW data_directory;
+ data_directory
+ ---------------------
+ /var/lib/pgsql/data
+ (1 row)
+
+ postgres-# \q
+
+#. Stop postgresql service and modify the configuration files: ::
+
+ systemctl stop postgresql
+ mkdir /install/pgsql_db
+ rsync -av /var/lib/pgsql/ /install/pgsql_db/
+
+ cat /usr/lib/systemd/system/postgresql.service | grep -i PGDATA=
+ Environment=PGDATA=**/install/pgsql_db/data/**
+
+ cat /install/pgsql_db/data/postgresql.conf | grep data_directory
+ #data_directory = 'ConfigDir' # use data in another directory
+ **data_directory = '/install/pgsql_db/data/'**
+
+#. Reload, start postgresql service and check the working directory: ::
+
+ systemctl daemon-reload
+ systemctl start postgresql
+ sudo -u postgres psql
+ psql (9.2.18)
+ Type "help" for help.
+
+ postgres=# SHOW data_directory;
+ data_directory
+ ------------------------
+ /install/pgsql_db/data
+ (1 row)
+
+ postgres=#
+
diff --git a/docs/source/advanced/networks/onie_switches/os_cumulus/index.rst b/docs/source/advanced/networks/onie_switches/os_cumulus/index.rst
index d2b369957..82f0e4e38 100644
--- a/docs/source/advanced/networks/onie_switches/os_cumulus/index.rst
+++ b/docs/source/advanced/networks/onie_switches/os_cumulus/index.rst
@@ -10,3 +10,4 @@ This documentation will focus on installing the Cumulus Network Operating System
prepare.rst
install.rst
manage.rst
+ upgrade.rst
diff --git a/docs/source/advanced/networks/onie_switches/os_cumulus/install.rst b/docs/source/advanced/networks/onie_switches/os_cumulus/install.rst
index e0d132dfb..8915d02af 100644
--- a/docs/source/advanced/networks/onie_switches/os_cumulus/install.rst
+++ b/docs/source/advanced/networks/onie_switches/os_cumulus/install.rst
@@ -78,6 +78,8 @@ Validate the ssh keys are correctly configured by running a ``xdsh`` command: ::
xdsh frame01sw1 uptime
+.. _activate-the-license:
+
Activate the License
--------------------
diff --git a/docs/source/advanced/networks/onie_switches/os_cumulus/manage.rst b/docs/source/advanced/networks/onie_switches/os_cumulus/manage.rst
index 0f3ce1184..512c4b1f4 100644
--- a/docs/source/advanced/networks/onie_switches/os_cumulus/manage.rst
+++ b/docs/source/advanced/networks/onie_switches/os_cumulus/manage.rst
@@ -1,10 +1,10 @@
Switch Management
=================
-VLAN Configuration
-------------------
+Switch Port and VLAN Configuration
+----------------------------------
-xCAT ships a simple configuration script that will set all the ports on the switch to be part of VLAN 1. See the Cumulus Networks documentation for more information regarding advanced networking configuration. ::
+xCAT expects the configuration for the front-panel ports to be located at ``/etc/network/interfaces.d/xCAT.intf`` on the switch. The ``configinterface`` postscript can download an interface configuration file from the management node. Place the configuration file in the directory ``/install/custom/sw_os/cumulus/interface/`` on the management node. It will first look for a file named the same as the switch's hostname, followed by the name of each group, followed by the word 'default'. If the postscript cannot find a configuration file on the management node, it will set all the ports on the switch to be part of VLAN 1. See the Cumulus Networks documentation for more information regarding advanced networking configuration. ::
updatenode -P configinterface
diff --git a/docs/source/advanced/networks/onie_switches/os_cumulus/upgrade.rst b/docs/source/advanced/networks/onie_switches/os_cumulus/upgrade.rst
new file mode 100644
index 000000000..da079129c
--- /dev/null
+++ b/docs/source/advanced/networks/onie_switches/os_cumulus/upgrade.rst
@@ -0,0 +1,62 @@
+Cumulus OS upgrade
+==================
+
+The Cumulus OS on the ONIE switches can be upgraded in 2 ways:
+
+* Upgrade only the changed packages, using ``apt-get update`` and ``apt-get upgrade``. If the ONIE switches has internet access, this is the preferred method, otherwise, you need to build up a local cumulus mirror in the cluster.
+
+ Since in a typical cluster setup, the switches usually do not have internet access, you can create a local mirror on the server which has internet access and can be reached from the switches, the steps are ::
+
+ mkdir -p /install/mirror/cumulus
+ cd /install/mirror/cumulus
+ #the wget might take a long time, it will be better if you can set up
+ #a cron job to sync the local mirror with upstream
+ wget -m --no-parent http://repo3.cumulusnetworks.com/repo/
+
+ then compose a ``sources.list`` file on MN like this(take 172.21.253.37 as ip address of the local mirror server) ::
+
+ #cat /tmp/sources.list
+ deb http://172.21.253.37/install/mirror/cumulus/repo3.cumulusnetworks.com/repo CumulusLinux-3 cumulus upstream
+ deb-src http://172.21.253.37/install/mirror/cumulus/repo3.cumulusnetworks.com/repo CumulusLinux-3 cumulus upstream
+
+ deb http://172.21.253.37/install/mirror/cumulus/repo3.cumulusnetworks.com/repo CumulusLinux-3-security-updates cumulus upstream
+ deb-src http://172.21.253.37/install/mirror/cumulus/repo3.cumulusnetworks.com/repo CumulusLinux-3-security-updates cumulus upstream
+
+ deb http://172.21.253.37/install/mirror/cumulus/repo3.cumulusnetworks.com/repo CumulusLinux-3-updates cumulus upstream
+ deb-src http://172.21.253.37/install/mirror/cumulus/repo3.cumulusnetworks.com/repo CumulusLinux-3-updates cumulus upstream
+
+ distribute the ``sources.list`` file to the switches to upgrade with ``xdcp``, take "switch1" as an example here ::
+
+ xdcp switch1 /tmp/sources.list /etc/apt/sources.list
+
+ then invoke ``apt-get update`` and ``apt-get install`` on the switches to start package upgrade, a reboot might be needed after upgrading ::
+
+ xdsh switch1 'apt-get update && apt-get upgrade && reboot'
+
+ check the `/etc/os-release` file to make sure the Cumulus OS has been upgraded ::
+
+ cat /etc/os-release
+
+
+
+* Performe a binary (full image) install of the new version, using ONIE. If you expect to upgrade between major versions or if you have the binary image to upgrade to, this way is the recommended one. Make sure to backup your data and configuration files because binary install will erase all the configuration and data on the switch.
+
+ The steps to perform a binary (full image) install of the new version are:
+
+ 1) place the binary image "cumulus-linux-3.4.1.bin" under ``/install`` directory on MN("172.21.253.37") ::
+
+ mkdir -p /install/onie/
+ cp cumulus-linux-3.4.1.bin /install/onie/
+
+ 2) invoke the upgrade on switches with ``xdsh`` ::
+
+ xdsh switch1 "/usr/cumulus/bin/onie-install -a -f -i http://172.21.253.37/install/onie/cumulus-linux-3.4.1.bin && reboot"
+
+ The full upgrade process might cost 30 min, you can ping the switch with ``ping switch1`` to check whether it finishes upgrade.
+
+ 3) After upgrading, the license should be installed, see :ref:`Activate the License ` for detailed steps.
+
+ 4) Restore your data and configuration files on the switch.
+
+
+
diff --git a/docs/source/advanced/restapi/restapi_setup/restapi_setup.rst b/docs/source/advanced/restapi/restapi_setup/restapi_setup.rst
index 9855ef848..8f831211a 100644
--- a/docs/source/advanced/restapi/restapi_setup/restapi_setup.rst
+++ b/docs/source/advanced/restapi/restapi_setup/restapi_setup.rst
@@ -63,7 +63,7 @@ The steps to configure the certificate for https server: ::
export sslcfgfile=/etc/apache2/sites-enabled/ssl.conf # ubuntu
sed -i 's/^\(\s*\)SSLCertificateFile.*$/\1SSLCertificateFile \/etc\/xcat\/cert\/server-cred.pem/' $sslcfgfile
- sed -i 's/^\(\s*\)SSLCertificateKeyFile.*$/\1SSLCertificateKeyFile \/etc\/xcat\/cert\/server-cred.pem/' $sslcfgfile
+ sed -i 's/^\(\s*SSLCertificateKeyFile.*\)$/#\1/' $sslcfgfile
service httpd restart # rhel
service apache2 restart # sles/ubuntu
diff --git a/docs/source/guides/admin-guides/basic_concepts/xcat_db/regexp_db.rst b/docs/source/guides/admin-guides/basic_concepts/xcat_db/regexp_db.rst
index 1e3c8482b..a39bf7c9d 100644
--- a/docs/source/guides/admin-guides/basic_concepts/xcat_db/regexp_db.rst
+++ b/docs/source/guides/admin-guides/basic_concepts/xcat_db/regexp_db.rst
@@ -95,6 +95,63 @@ Using easy regular expression support you would put this in the hosts table. ::
In the easy regx example, the expression only has the 2nd part of the expression from the previous example. xCAT will evaluate the node name, matching the number part of the node name, and create the 1st part of the expression . The 2nd part supplied is what value to give the ip attribute. The resulting output is the same.
+Regular Expression Helper Functions
+-----------------------------------
+
+xCAT provides several functions that can simplify regular expressions.
+
+\ **a2idx** ASCII Character to Index\
+ Usage: ``a2idx(character)``
+
+ Turns a single character into a 1-indexed index. ‘a’ maps to 1 and ‘z’ maps to 26.
+
+\ **a2zidx** ASCII Character to 0-Index\
+ Usage: ``a2zidx(character)``
+
+ Turns a single character into a 0-indexed index. ‘a’ maps to 0 and ‘z’ maps to 25.
+
+\ **dim2idx** Dimensions to Index\
+ Usage: ``dim2idx(value, [count, value...])``
+
+ Converts dimensions (such as row, column, chassis, etc) into an index. An example system consists of 8 racks, two rows with four columns each.
+
+ +-----------+-----------+-----------+-----------+
+ | row1-col1 | row1-col2 | row1-col3 | row1-col4 |
+ +-----------+-----------+-----------+-----------+
+ | row2-col1 | row2-col2 | row2-col3 | row2-col4 |
+ +-----------+-----------+-----------+-----------+
+ To obtain the rack index, use ``|row(\d+)-col(\d+)|(dim2idx($1, 4, $2))|``. This maps the racks to:
+
+ +---+---+---+---+
+ | 1 | 2 | 3 | 4 |
+ +---+---+---+---+
+ | 5 | 6 | 7 | 8 |
+ +---+---+---+---+
+ Note that the size of the highest dimension (2 rows) is not needed, and all values are one-indexed.
+
+ If each rack contains 20 nodes, use ``|row(\d+)-col(\d+)-node(\d+)|(dim2idx($1, 4, $2, 20, $3)`` to determine a node index (useful for determining IP addresses).
+
+\ **skip** Skip indices\
+ Usage: ``skip(index, skiplist)``
+
+ Return an index with certain values skipped. The skip list uses the format ``start[:count][,start[:count]...]``. Using the example above, to skip racks 3 and 4, use:
+
+ ``|row(\d+)-col(\d+)|(skip(dim2idx($1, 4, $2),'3:2')|``
+
+ The result would be:
+
+ +---+---+---+---+
+ | 1 | 2 | | |
+ +---+---+---+---+
+ | 3 | 4 | 5 | 6 |
+ +---+---+---+---+
+
+\ **ipadd** Add to an IP address\
+ Usage: ``ipadd(octet1, octet2, octet3, octet4, toadd, skipstart, skipend)``
+
+ This function is useful when you need to cross octets. Optionally skip addresses at the start and end of octets (like .0 or .255 - technically those are valid IP addresses, but sometimes software makes poor assumptions about which broadcast and gateway addresses).
+
+
Verify your regular expression
------------------------------
diff --git a/docs/source/guides/admin-guides/manage_clusters/common/kvm/manage_vm.rst b/docs/source/guides/admin-guides/manage_clusters/common/kvm/manage_vm.rst
index 6aa25256c..849f080f3 100644
--- a/docs/source/guides/admin-guides/manage_clusters/common/kvm/manage_vm.rst
+++ b/docs/source/guides/admin-guides/manage_clusters/common/kvm/manage_vm.rst
@@ -25,24 +25,24 @@ Specify VM attributes
After the VM object is created, several key attributes need to be specified with ``chdef`` :
-1. the number of virtual cpus in the VM: ::
+1. the hardware management module, "kvm" for PowerKVM: ::
+
+ chdef vm1 mgt=kvm
+
+2. the number of virtual cpus in the VM: ::
chdef vm1 vmcpus=2
-2. the kvm hypervisor of the VM: ::
+3. the kvm hypervisor of the VM: ::
chdef vm1 vmhost=kvmhost1
-3. the virtual memory size, with the unit "Megabit". Specify 1GB memory to "vm1" here: ::
+4. the virtual memory size, with the unit "Megabit". Specify 1GB memory to "vm1" here: ::
chdef vm1 vmmemory=1024
**Note**: For diskless node, the **vmmemory** should be at least 2048 MB, otherwise the node cannot boot up.
-4. the hardware management module, "kvm" for PowerKVM: ::
-
- chdef vm1 mgt=kvm
-
5. Define the virtual network card, it should be set to the bridge "br0" which has been created in the hypervisor. If no bridge is specified, no network device will be created for the VM node "vm1": ::
chdef vm1 vmnics=br0
diff --git a/docs/source/guides/admin-guides/references/man1/pgsqlsetup.1.rst b/docs/source/guides/admin-guides/references/man1/pgsqlsetup.1.rst
index e0b7b8298..8e16004c7 100644
--- a/docs/source/guides/admin-guides/references/man1/pgsqlsetup.1.rst
+++ b/docs/source/guides/admin-guides/references/man1/pgsqlsetup.1.rst
@@ -85,7 +85,7 @@ OPTIONS
\ **-a|-**\ **-access**\ \ *address*\
- This option is used to specify additional IP addresses from which the service nodes will connect to the PostgreSQL database. Without it, only the management node will be configured for database access. This option can be specified multiple times.
+ This option is used to specify additional IP addresses from which the additional nodes will connect to the PostgreSQL database, for example, service nodes IP addresses or MN HA primary/standby nodes physical IP addresses. Without it, only the management node will be configured for database access. This option can be specified multiple times.
diff --git a/docs/source/guides/admin-guides/references/man1/rspconfig.1.rst b/docs/source/guides/admin-guides/references/man1/rspconfig.1.rst
index 038709fe0..dab879fa5 100644
--- a/docs/source/guides/admin-guides/references/man1/rspconfig.1.rst
+++ b/docs/source/guides/admin-guides/references/man1/rspconfig.1.rst
@@ -47,7 +47,7 @@ OpenBMC specific:
=================
-\ **rspconfig**\ \ *noderange*\ {\ **ip | netmask | gateway | hostname | vlan | sshcfg**\ }
+\ **rspconfig**\ \ *noderange*\ {\ **ipsrc | ip | netmask | gateway | hostname | vlan | sshcfg**\ }
MPA specific:
@@ -406,9 +406,15 @@ OPTIONS
+\ **ipsrc**\
+
+ Get the IP source for OpenBMC.
+
+
+
\ **ip**\
- The ip address.
+ The IP address.
diff --git a/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst b/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst
index e84f3e74d..e219a5ea8 100644
--- a/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst
+++ b/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst
@@ -15,7 +15,7 @@ SYNOPSIS
\ **switchdiscover [-v| -**\ **-version]**\
-\ **switchdiscover**\ [\ *noderange*\ | \ **-**\ **-range**\ \ *ip_ranges*\ ] \ **[-V] [-w][-r|-x|-z][-s**\ \ *scan_methods*\ \ **-**\ **-setup**\ ]
+\ **switchdiscover**\ [\ *noderange*\ | \ **-**\ **-range**\ \ *ip_ranges*\ ] \ **[-V] [-w][-r|-x|-z][-s**\ \ *scan_methods*\ ] [\ **-**\ **-setup**\ ] [\ **-c**\ \ *community*\ ]
***********
@@ -31,7 +31,7 @@ To view all the switches defined in the xCAT database use \ **lsdef -w "nodetype
For lldp method, make sure that lldpd package is installed and lldpd is running on the xCAT management node. lldpd comes from xcat-dep package or you can get it from http://vincentbernat.github.io/lldpd/installation.html.
-For snmp method, make sure that snmpwalk command is installed and snmp is enabled for switches. To install snmpwalk, "yum install net-snmp-utils" for redhat and sles, "apt-get install snmp" for Ubuntu.
+For snmp method, make sure that snmpwalk command is installed and snmp is enabled for switches. To install snmpwalk, "yum install net-snmp-utils" for redhat and sles, "apt-get install snmp" for Ubuntu. The switchdiscover command only check the switches with default community string, if user already configured switch with other commmunity string, need to pass in with \ **-c**\ option for switchdiscover command to be able to discover.
*******
@@ -118,6 +118,12 @@ OPTIONS
+\ **-c**\
+
+ User defined community string for snmp scan.
+
+
+
************
RETURN VALUE
diff --git a/docs/source/guides/admin-guides/references/man5/xcatdb.5.rst b/docs/source/guides/admin-guides/references/man5/xcatdb.5.rst
index b4a9ba93e..6fd7f9b94 100644
--- a/docs/source/guides/admin-guides/references/man5/xcatdb.5.rst
+++ b/docs/source/guides/admin-guides/references/man5/xcatdb.5.rst
@@ -157,27 +157,6 @@ Before you panic, let me explain each column:
See http://www.perl.com/doc/manual/html/pod/perlre.html for information on perl regular expressions.
-Regular Expression Helper Functions
-============================
-
-xCAT provides several functions that can simplify regular expressions.
-
-\ **a2idx(character) **\
- Turns a single character into a 1-indexed index. ‘a’ maps to 1 and ‘z’ maps to 26.
-
-\ **a2zidx(character) **\
- Turns a single character into a 0-indexed index. ‘a’ maps to 0 and ‘z’ maps to 25.
-
-\ **dim2idx(value, [count, value...]) **\
- Converts dimensions (such as row, column, chassis, etc) into an index. If each rack has 18 nodes, use dim2idx(racknum, 18, nodenum). Additional dimensions should be added at the beginning. All values are 1-indexed.
-
-\ **skip(index, skiplist) **\
- Return an index with certain values skipped. The skip list uses the format start[:count][,start[:count]...]
-
-\ **ipadd(octet1, octet2, octet3, octet4, toadd, skipstart, skipend) **\
- Add to an IP address. Generally only necessary when you cross octets. Optionally skip addresses at the start and end of octets (like .0 or .255). Technically those are valid IP addresses, but sometimes software makes poor assumptions about which broadcast and gateway addresses.
-
-
Easy Regular Expressions
========================
@@ -187,6 +166,46 @@ As of xCAT 2.8.1, you can use a modified version of the regular expression suppo
http://xcat-docs.readthedocs.org/en/latest/guides/admin-guides/basic_concepts/xcat_db/regexp_db.html#easy-regular-expressions
+Regular Expression Helper Functions
+===================================
+
+
+xCAT provides several functions that can simplify regular expressions.
+
+
+\ **a2idx**\
+
+ ASCII Character to Index
+
+
+
+\ **a2zidx**\
+
+ ASCII Character to 0-Index
+
+
+
+\ **dim2idx**\
+
+ Dimensions to Index
+
+
+
+\ **skip**\
+
+ Skip indices
+
+
+
+\ **ipadd**\
+
+ Add to an IP address
+
+
+
+http://xcat-docs.readthedocs.org/en/latest/guides/admin-guides/basic_concepts/xcat_db/regexp_db.html#regular-expression-helper-functions
+
+
******************
OBJECT DEFINITIONS
diff --git a/docs/source/guides/install-guides/apt/index.rst b/docs/source/guides/install-guides/apt/index.rst
index 2b8cc45d3..97c34885d 100644
--- a/docs/source/guides/install-guides/apt/index.rst
+++ b/docs/source/guides/install-guides/apt/index.rst
@@ -1,3 +1,5 @@
+.. _ubuntu_install_guide:
+
Installation Guide for Ubuntu Server LTS
========================================
diff --git a/docs/source/guides/install-guides/yum/index.rst b/docs/source/guides/install-guides/yum/index.rst
index 37ae5033f..2ae2d97d3 100644
--- a/docs/source/guides/install-guides/yum/index.rst
+++ b/docs/source/guides/install-guides/yum/index.rst
@@ -1,3 +1,5 @@
+.. _rhel_install_guide:
+
Installation Guide for Red Hat Enterprise Linux
===============================================
diff --git a/docs/source/guides/install-guides/zypper/index.rst b/docs/source/guides/install-guides/zypper/index.rst
index 2a44ca0e3..253711f78 100644
--- a/docs/source/guides/install-guides/zypper/index.rst
+++ b/docs/source/guides/install-guides/zypper/index.rst
@@ -1,3 +1,5 @@
+.. _sles_install_guide:
+
Installation Guide for SUSE Linux Enterprise Server
===================================================
diff --git a/docs/source/index.rst b/docs/source/index.rst
index d507a22b7..0afdb7281 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -32,6 +32,7 @@ Table of Contents
guides/install-guides/index.rst
guides/admin-guides/index.rst
advanced/index.rst
+ references/index.rst
troubleshooting/index.rst
developers/index.rst
help.rst
diff --git a/docs/source/references/coral/discovery/compute/index.rst b/docs/source/references/coral/discovery/compute/index.rst
new file mode 100644
index 000000000..f685c63b8
--- /dev/null
+++ b/docs/source/references/coral/discovery/compute/index.rst
@@ -0,0 +1,9 @@
+Compute Nodes
+=============
+
+.. toctree::
+ :maxdepth: 2
+
+ discover.rst
+ validation.rst
+
diff --git a/docs/source/references/coral/discovery/core_sw/discover.rst b/docs/source/references/coral/discovery/core_sw/discover.rst
new file mode 100644
index 000000000..20517215f
--- /dev/null
+++ b/docs/source/references/coral/discovery/core_sw/discover.rst
@@ -0,0 +1,3 @@
+Discover Switches
+=================
+
diff --git a/docs/source/references/coral/discovery/core_sw/index.rst b/docs/source/references/coral/discovery/core_sw/index.rst
new file mode 100644
index 000000000..150400044
--- /dev/null
+++ b/docs/source/references/coral/discovery/core_sw/index.rst
@@ -0,0 +1,11 @@
+Core Switches
+=============
+
+.. toctree::
+ :maxdepth: 2
+
+ pre.rst
+ discover.rst
+ vlan.rst
+ known_issues.rst
+
diff --git a/docs/source/references/coral/discovery/core_sw/known_issues.rst b/docs/source/references/coral/discovery/core_sw/known_issues.rst
new file mode 100644
index 000000000..635383512
--- /dev/null
+++ b/docs/source/references/coral/discovery/core_sw/known_issues.rst
@@ -0,0 +1,2 @@
+Known Issues
+============
diff --git a/docs/source/references/coral/discovery/core_sw/pre.rst b/docs/source/references/coral/discovery/core_sw/pre.rst
new file mode 100644
index 000000000..0495d946d
--- /dev/null
+++ b/docs/source/references/coral/discovery/core_sw/pre.rst
@@ -0,0 +1,4 @@
+Prerequisites
+=============
+
+
diff --git a/docs/source/references/coral/discovery/core_sw/vlan.rst b/docs/source/references/coral/discovery/core_sw/vlan.rst
new file mode 100644
index 000000000..0867106da
--- /dev/null
+++ b/docs/source/references/coral/discovery/core_sw/vlan.rst
@@ -0,0 +1,2 @@
+VLAN Configuration
+==================
diff --git a/docs/source/references/coral/discovery/edge_sw/discover.rst b/docs/source/references/coral/discovery/edge_sw/discover.rst
new file mode 100644
index 000000000..20517215f
--- /dev/null
+++ b/docs/source/references/coral/discovery/edge_sw/discover.rst
@@ -0,0 +1,3 @@
+Discover Switches
+=================
+
diff --git a/docs/source/references/coral/discovery/edge_sw/index.rst b/docs/source/references/coral/discovery/edge_sw/index.rst
new file mode 100644
index 000000000..2586ec2e9
--- /dev/null
+++ b/docs/source/references/coral/discovery/edge_sw/index.rst
@@ -0,0 +1,10 @@
+Edge Switches
+=============
+
+.. toctree::
+ :maxdepth: 2
+
+ pre.rst
+ discover.rst
+ vlan.rst
+ known_issues.rst
diff --git a/docs/source/references/coral/discovery/edge_sw/known_issues.rst b/docs/source/references/coral/discovery/edge_sw/known_issues.rst
new file mode 100644
index 000000000..635383512
--- /dev/null
+++ b/docs/source/references/coral/discovery/edge_sw/known_issues.rst
@@ -0,0 +1,2 @@
+Known Issues
+============
diff --git a/docs/source/references/coral/discovery/edge_sw/pre.rst b/docs/source/references/coral/discovery/edge_sw/pre.rst
new file mode 100644
index 000000000..0495d946d
--- /dev/null
+++ b/docs/source/references/coral/discovery/edge_sw/pre.rst
@@ -0,0 +1,4 @@
+Prerequisites
+=============
+
+
diff --git a/docs/source/references/coral/discovery/edge_sw/vlan.rst b/docs/source/references/coral/discovery/edge_sw/vlan.rst
new file mode 100644
index 000000000..0867106da
--- /dev/null
+++ b/docs/source/references/coral/discovery/edge_sw/vlan.rst
@@ -0,0 +1,2 @@
+VLAN Configuration
+==================
diff --git a/docs/source/references/coral/discovery/index.rst b/docs/source/references/coral/discovery/index.rst
new file mode 100644
index 000000000..3d7984876
--- /dev/null
+++ b/docs/source/references/coral/discovery/index.rst
@@ -0,0 +1,13 @@
+Discovery
+=========
+
+.. toctree::
+ :maxdepth: 2
+
+ core_sw/index.rst
+ mgmt_sw/index.rst
+ mid_sw/index.rst
+ servicenode/index.rst
+ edge_sw/index.rst
+ compute/index.rst
+
diff --git a/docs/source/references/coral/discovery/mgmt_sw/discover.rst b/docs/source/references/coral/discovery/mgmt_sw/discover.rst
new file mode 100644
index 000000000..20517215f
--- /dev/null
+++ b/docs/source/references/coral/discovery/mgmt_sw/discover.rst
@@ -0,0 +1,3 @@
+Discover Switches
+=================
+
diff --git a/docs/source/references/coral/discovery/mgmt_sw/index.rst b/docs/source/references/coral/discovery/mgmt_sw/index.rst
new file mode 100644
index 000000000..c319c6883
--- /dev/null
+++ b/docs/source/references/coral/discovery/mgmt_sw/index.rst
@@ -0,0 +1,11 @@
+Management Switches
+===================
+
+.. toctree::
+ :maxdepth: 2
+
+ pre.rst
+ discover.rst
+ vlan.rst
+ known_issues.rst
+
diff --git a/docs/source/references/coral/discovery/mgmt_sw/known_issues.rst b/docs/source/references/coral/discovery/mgmt_sw/known_issues.rst
new file mode 100644
index 000000000..635383512
--- /dev/null
+++ b/docs/source/references/coral/discovery/mgmt_sw/known_issues.rst
@@ -0,0 +1,2 @@
+Known Issues
+============
diff --git a/docs/source/references/coral/discovery/mgmt_sw/pre.rst b/docs/source/references/coral/discovery/mgmt_sw/pre.rst
new file mode 100644
index 000000000..0495d946d
--- /dev/null
+++ b/docs/source/references/coral/discovery/mgmt_sw/pre.rst
@@ -0,0 +1,4 @@
+Prerequisites
+=============
+
+
diff --git a/docs/source/references/coral/discovery/mgmt_sw/vlan.rst b/docs/source/references/coral/discovery/mgmt_sw/vlan.rst
new file mode 100644
index 000000000..0867106da
--- /dev/null
+++ b/docs/source/references/coral/discovery/mgmt_sw/vlan.rst
@@ -0,0 +1,2 @@
+VLAN Configuration
+==================
diff --git a/docs/source/references/coral/discovery/mid_sw/discover.rst b/docs/source/references/coral/discovery/mid_sw/discover.rst
new file mode 100644
index 000000000..20517215f
--- /dev/null
+++ b/docs/source/references/coral/discovery/mid_sw/discover.rst
@@ -0,0 +1,3 @@
+Discover Switches
+=================
+
diff --git a/docs/source/references/coral/discovery/mid_sw/index.rst b/docs/source/references/coral/discovery/mid_sw/index.rst
new file mode 100644
index 000000000..985a1d35b
--- /dev/null
+++ b/docs/source/references/coral/discovery/mid_sw/index.rst
@@ -0,0 +1,11 @@
+Mid Switches
+============
+
+.. toctree::
+ :maxdepth: 2
+
+ pre.rst
+ discover.rst
+ vlan.rst
+ known_issues.rst
+
diff --git a/docs/source/references/coral/discovery/mid_sw/known_issues.rst b/docs/source/references/coral/discovery/mid_sw/known_issues.rst
new file mode 100644
index 000000000..635383512
--- /dev/null
+++ b/docs/source/references/coral/discovery/mid_sw/known_issues.rst
@@ -0,0 +1,2 @@
+Known Issues
+============
diff --git a/docs/source/references/coral/discovery/mid_sw/pre.rst b/docs/source/references/coral/discovery/mid_sw/pre.rst
new file mode 100644
index 000000000..0495d946d
--- /dev/null
+++ b/docs/source/references/coral/discovery/mid_sw/pre.rst
@@ -0,0 +1,4 @@
+Prerequisites
+=============
+
+
diff --git a/docs/source/references/coral/discovery/mid_sw/vlan.rst b/docs/source/references/coral/discovery/mid_sw/vlan.rst
new file mode 100644
index 000000000..0867106da
--- /dev/null
+++ b/docs/source/references/coral/discovery/mid_sw/vlan.rst
@@ -0,0 +1,2 @@
+VLAN Configuration
+==================
diff --git a/docs/source/references/coral/discovery/servicenode/index.rst b/docs/source/references/coral/discovery/servicenode/index.rst
new file mode 100644
index 000000000..23ff6169e
--- /dev/null
+++ b/docs/source/references/coral/discovery/servicenode/index.rst
@@ -0,0 +1,9 @@
+Service Nodes
+=============
+
+.. toctree::
+ :maxdepth: 2
+
+ discover.rst
+ validation.rst
+
diff --git a/docs/source/references/coral/index.rst b/docs/source/references/coral/index.rst
new file mode 100644
index 000000000..4639e3360
--- /dev/null
+++ b/docs/source/references/coral/index.rst
@@ -0,0 +1,12 @@
+CORAL
+=====
+
+CORAL stands for Collaboration of Oak Ridge, Argonne, and Livermore and is solution that IBM is building for the Department of Energy to superseed its current cluster of Supercomputers.
+
+
+.. toctree::
+ :maxdepth: 2
+
+ known_issues/index.rst
+.. mn/index.rst
+.. discovery/index.rst
diff --git a/docs/source/references/coral/known_issues/genesis_base.rst b/docs/source/references/coral/known_issues/genesis_base.rst
new file mode 100644
index 000000000..adb57d762
--- /dev/null
+++ b/docs/source/references/coral/known_issues/genesis_base.rst
@@ -0,0 +1,22 @@
+xCAT Genesis Base
+=================
+
+xCAT ships a ``xCAT-genesis-base`` package as part of xcat-deps. This is a light-weight diskless linux image based on Fedora (Fedora26, currently) that is used by xCAT to do hardware discovery.
+
+To support the Power9 hardware, changes are made to the kernel in the Red Hat Enterprise distribution that are not yet available in the Fedora kernels. Without that support, running the scripts in xCAT discovery caused segmentation faults described in this issue: https://github.com/xcat2/xcat-core/issues/3870
+
+Work-around
+-----------
+
+xCAT cannot ship a kernel based on RHEL distribution, so the customer needs to build a version of the ``xCAT-genesis-base`` on-site using a server running Red Hat Enterprise Linux.
+
+1. Download the latest timestamp version of the ``xCAT-genesis-builder`` RPM provided here: http://xcat.org/files/xcat/xcat-dep/2.x_Linux/beta/
+
+2. Install the ``xCAT-genesis-builder`` RPM on a node that is installed with the RHEL version being deployed.
+
+3. Build the ``xCAT-genesis-base`` RPM: ::
+
+ /opt/xcat/share/xcat/netboot/genesis/builder/buildrpm
+
+4. Install this package on top of the xCAT install and execute: ``mknb ppc64``
+
diff --git a/docs/source/references/coral/known_issues/index.rst b/docs/source/references/coral/known_issues/index.rst
new file mode 100644
index 000000000..359cd90de
--- /dev/null
+++ b/docs/source/references/coral/known_issues/index.rst
@@ -0,0 +1,7 @@
+Known Issues
+============
+
+.. toctree::
+ :maxdepth: 2
+
+ genesis_base.rst
diff --git a/docs/source/references/coral/mn/configure/index.rst b/docs/source/references/coral/mn/configure/index.rst
new file mode 100644
index 000000000..801000b83
--- /dev/null
+++ b/docs/source/references/coral/mn/configure/index.rst
@@ -0,0 +1,5 @@
+Configure
+=========
+
+.. toctree::
+ :maxdepth: 2
diff --git a/docs/source/references/coral/mn/index.rst b/docs/source/references/coral/mn/index.rst
new file mode 100644
index 000000000..55f5cb559
--- /dev/null
+++ b/docs/source/references/coral/mn/index.rst
@@ -0,0 +1,12 @@
+Management Node
+===============
+
+The Management Node should be installed with a RHEL Operating System. The following guides describe the process of installation, configuration and validation of xCAT on the Management Node.
+
+.. toctree::
+ :maxdepth: 2
+
+ install.rst
+ configure/index.rst
+ validate/index.rst
+
diff --git a/docs/source/references/coral/mn/install.rst b/docs/source/references/coral/mn/install.rst
new file mode 100644
index 000000000..92baff000
--- /dev/null
+++ b/docs/source/references/coral/mn/install.rst
@@ -0,0 +1,16 @@
+Install
+=======
+
+
+Prerequisite
+------------
+
+Install the following RPMs Management Node. They are used by various tools xCAT provides to assist with debugging/validation: ::
+
+ yum -y install tcpdump pciutils bzip2 bind-utils
+
+
+Install xCAT
+------------
+
+See :ref:`rhel_install_guide` for detailed xCAT installation instructions.
diff --git a/docs/source/references/coral/mn/validate/index.rst b/docs/source/references/coral/mn/validate/index.rst
new file mode 100644
index 000000000..8337700a0
--- /dev/null
+++ b/docs/source/references/coral/mn/validate/index.rst
@@ -0,0 +1,6 @@
+Validate
+========
+
+.. toctree::
+ :maxdepth: 2
+
diff --git a/docs/source/references/index.rst b/docs/source/references/index.rst
new file mode 100644
index 000000000..7a3d6402a
--- /dev/null
+++ b/docs/source/references/index.rst
@@ -0,0 +1,11 @@
+Reference Implementation
+========================
+
+Reference documentation created for management of large clusters using xCAT.
+
+.. toctree::
+ :maxdepth: 2
+
+ coral/index.rst
+ percs/index.rst
+
diff --git a/docs/source/references/percs/index.rst b/docs/source/references/percs/index.rst
new file mode 100644
index 000000000..e60f08f29
--- /dev/null
+++ b/docs/source/references/percs/index.rst
@@ -0,0 +1,5 @@
+PERCS
+=====
+
+See documentation here: https://sourceforge.net/p/xcat/wiki/XCAT_Power_775_Hardware_Management/
+
diff --git a/docs/source/security/2017/20170828_openssl.rst b/docs/source/security/2017/20170828_openssl.rst
new file mode 100644
index 000000000..9592f1f6d
--- /dev/null
+++ b/docs/source/security/2017/20170828_openssl.rst
@@ -0,0 +1,31 @@
+2017-08-28 - OpenSSL Vulnerabilities
+====================================
+
+*Aug 28, 2017*, OpenSSL announced the following security advisories: https://www.openssl.org/news/secadv/20170828.txt
+
+
+Advisory CVEs
+-------------
+
+* CVE-2017-3735 - **Malformed X.509 IPAddressFamily could cause OOB read** (Severity: Low)
+
+If an X.509 certificate has a malformed IPAddressFamily extension,
+OpenSSL could do a one-byte buffer overread. The most likely result
+would be an erroneous display of the certificate in text format.
+
+As this is a low severity fix, no release is being made. The fix can be
+found in the source repository (1.0.2, 1.1.0, and master branches); see
+https://github.com/openssl/openssl/pull/4276. This bug has been present
+since 2006.
+
+
+Please see the security bulletin above for patch, upgrade, or suggested work around information.
+
+Action
+------
+
+xCAT uses OpenSSL for client-server communication but **does not** ship it.
+
+It is highly recommended to keep your OpenSSL levels up-to-date with the indicated versions in the security bulletins to prevent any potential security threats. Obtain the updated software packages from your Operating system distribution channels.
+
+
diff --git a/docs/source/security/2017/index.rst b/docs/source/security/2017/index.rst
index 588d8c30e..78e927e17 100644
--- a/docs/source/security/2017/index.rst
+++ b/docs/source/security/2017/index.rst
@@ -4,5 +4,6 @@
.. toctree::
:maxdepth: 1
+ 20170828_openssl.rst
20170216_openssl.rst
20170126_openssl.rst
diff --git a/docs/source/troubleshooting/os_installation/debug_port.rst b/docs/source/troubleshooting/os_installation/debug_port.rst
index f5d043892..ac2e8741a 100644
--- a/docs/source/troubleshooting/os_installation/debug_port.rst
+++ b/docs/source/troubleshooting/os_installation/debug_port.rst
@@ -3,7 +3,7 @@ Enabling Debug Port: Running commands in the installer from MN
**This mode is supported with debug level set to 1 or 2**
-xCAT creates a server in the **installer**, listening on port ``3001``. It executes commands sent to it from the xCAT MN and returns the response output.
+xCAT creates a service inside the **installer**, listening on port ``3054``. It executes commands sent to it from the xCAT MN and returns the response output.
The command ``runcmdinstaller`` can be used to send request to installer:
diff --git a/perl-xCAT/db2man b/perl-xCAT/db2man
index da35965e9..ee73edc5e 100755
--- a/perl-xCAT/db2man
+++ b/perl-xCAT/db2man
@@ -271,6 +271,36 @@ As of xCAT 2.8.1, you can use a modified version of the regular expression suppo
http://xcat-docs.readthedocs.org/en/latest/guides/admin-guides/basic_concepts/xcat_db/regexp_db.html#easy-regular-expressions
+=head2 Regular Expression Helper Functions
+
+xCAT provides several functions that can simplify regular expressions.
+
+=over 4
+
+=item B
+
+ASCII Character to Index
+
+=item B
+
+ASCII Character to 0-Index
+
+=item B
+
+Dimensions to Index
+
+=item B
+
+Skip indices
+
+=item B
+
+Add to an IP address
+
+=back
+
+http://xcat-docs.readthedocs.org/en/latest/guides/admin-guides/basic_concepts/xcat_db/regexp_db.html#regular-expression-helper-functions
+
=head1 OBJECT DEFINITIONS
Because it can get confusing what attributes need to go in what tables, the xCAT database can also
diff --git a/perl-xCAT/perl-xCAT.spec b/perl-xCAT/perl-xCAT.spec
index 86c15f41a..43ae21992 100644
--- a/perl-xCAT/perl-xCAT.spec
+++ b/perl-xCAT/perl-xCAT.spec
@@ -26,6 +26,7 @@ Includes xCAT::Table, xCAT::NodeRange, among others.
%define zvm %(if [ "$zvm" = "1" ];then echo 1; else echo 0; fi)
%define fsm %(if [ "$fsm" = "1" ];then echo 1; else echo 0; fi)
+%define builddate %(date)
%prep
%setup -q -n perl-xCAT
%build
diff --git a/perl-xCAT/xCAT/DBobjUtils.pm b/perl-xCAT/xCAT/DBobjUtils.pm
index 880160f42..0d6697955 100755
--- a/perl-xCAT/xCAT/DBobjUtils.pm
+++ b/perl-xCAT/xCAT/DBobjUtils.pm
@@ -902,6 +902,19 @@ sub setobjdefs
}
my @attrprovided = ();
+ #get group objects data
+ my %DBgroupsattr;
+ my %tmpghash;
+ my @tmplgrplist;
+ my %grpvalidattr;
+ if (defined($objhash{$objname}{'groups'})){
+
+ @tmplgrplist = split(",", $objhash{$objname}{'groups'});
+ foreach my $tmpgrp (@tmplgrplist) {
+ $tmpghash{$tmpgrp} = "group";
+ }
+ %DBgroupsattr=xCAT::DBobjUtils->getobjdefs(\%tmpghash);
+ }
# check FINALATTRS to see if all the attrs are valid
foreach my $attr (keys %{ $objhash{$objname} }) {
@@ -992,7 +1005,6 @@ sub setobjdefs
}
}
}
- xCAT::MsgUtils->message("I", $rsp, $::callback);
$checkedattrs{$attr_name} = 1;
if ($invalidattr->{$attr_name}->{valid} != 1) {
$invalidattr->{$attr_name}->{valid} = 0;
@@ -1147,10 +1159,26 @@ sub setobjdefs
my $rsp;
foreach my $att (keys %$invalidattr) {
+ my $pickvalidattr=0;
if ($invalidattr->{$att}->{valid} != 1) {
my $tt = $invalidattr->{$att}->{valid};
- push @{ $rsp->{data} }, "Cannot set the attr=\'$att\' attribute unless $invalidattr->{$att}->{condition}.";
- xCAT::MsgUtils->message("E", $rsp, $::callback);
+ #if attribute is set invalid, check if its pre-check attribute exists in group objects, pick the attribute into valid.
+ # ex. if I want to set hdwctrlpoint I will have
+ # to match the right value for mgtmethod, but mgtmethod does exist in node object in chdef command
+ # if mgtmethod exists in group objects, set hdwctrlpoint valid
+ my $conditionkv=$invalidattr->{$att}->{condition};
+ $conditionkv=~s/(^'|'$)//g;
+ my ($attk, $attv)=split("=", $conditionkv);
+ foreach my $tmpgrp (@tmplgrplist) {
+ if ($DBgroupsattr{$tmpgrp}{$attk} eq $attv) {
+ $pickvalidattr=1;
+ last;
+ }
+ }
+ if ($pickvalidattr != 1) {
+ push @{ $rsp->{data} }, "Cannot set the attr=\'$att\' attribute unless $invalidattr->{$att}->{condition}.";
+ xCAT::MsgUtils->message("E", $rsp, $::callback);
+ }
}
}
diff --git a/perl-xCAT/xCAT/DSHCLI.pm b/perl-xCAT/xCAT/DSHCLI.pm
index 787bb64c7..7e22de2d3 100644
--- a/perl-xCAT/xCAT/DSHCLI.pm
+++ b/perl-xCAT/xCAT/DSHCLI.pm
@@ -3855,10 +3855,10 @@ sub usage_dsh
my $usagemsg1 = " xdsh -h \n xdsh -q \n xdsh -V \n";
my $usagemsg1a = "xdsh [-K] [-l logonuserid]\n";
my $usagemsg2 = " [-B | --bypass ] [-c] [-e] [-E environment_file]
- [--devicetype type_of_device] [-f fanout]\n";
+ [--devicetype type_of_device] [-f fanout] [--ip ip_addr]\n";
my $usagemsg3 = " [-l user_ID] [-L] ";
my $usagemsg4 = "[-m] [-o options][-q] [-Q] [-r remote_shell]
- [-i image] [-s] [-S ksh | csh] [-t timeout]\n";
+ [-i image] [-s] [-S ksh | csh] [--show key|script] [-t timeout]\n";
my $usagemsg5 = " [-T] [-X environment variables] [-v] [-z] [--sudo]\n";
my $usagemsg6 = " ";
my $usagemsg .= $usagemsg1 .= $usagemsg1a .= $usagemsg2 .= $usagemsg3 .=
@@ -3962,8 +3962,10 @@ sub parse_and_run_dsh
'c|cleanup' => \$options{'cleanup'},
'E|environment=s' => \$options{'environment'},
'I|ignore-sig|ignoresig=s' => \$options{'ignore-signal'},
+ 'ip=s' => \$options{'ip'},
'K|keysetup' => \$options{'ssh-setup'},
'L|no-locale' => \$options{'no-locale'},
+ 'show=s' => \$options{'show'},
'Q|silent' => \$options{'silent'},
'S|syntax=s' => \$options{'syntax'},
'T|trace' => \$options{'trace'},
@@ -4131,7 +4133,7 @@ sub parse_and_run_dsh
# with error, if the Management Node is in the Database and in the
# noderange
my @mname = xCAT::Utils->noderangecontainsMn(@nodelist);
- if (@mname) { # MN in the nodelist
+ if ( @mname and !$options{'ip'} ) { # MN in the nodelist and --ip not specified
my $nodes = join(',', @mname);
my $rsp = {};
$rsp->{error}->[0] =
@@ -4165,7 +4167,7 @@ sub parse_and_run_dsh
# password for the key update. This was setup in xdsh client
# frontend.
- if (!($ENV{'DSH_REMOTE_PASSWORD'}))
+ if (!($ENV{'DSH_REMOTE_PASSWORD'}) && !(defined $options{'show'}))
{
my $rsp = {};
$rsp->{error}->[0] =
@@ -4239,7 +4241,22 @@ sub parse_and_run_dsh
#
# setup ssh keys on the nodes or ib switch
#
- my $rc = xCAT::TableUtils->setupSSH($options{'nodes'}, $options{'timeout'});
+ my $rc;
+
+ # If 'show' was specified then pass the value in an environment variable.
+ if ( $options{'show'} ) {
+ $ENV{'DSH_SHOW'} = $options{'show'};
+ }
+
+ # Go perform the setup of the SSH keys.
+ if ( $options{'ip'} ) {
+ # If IPs were passed then use them as the target of the unlock.
+ $rc = xCAT::TableUtils->setupSSH($options{'ip'} );
+ } else {
+ # Unlock the nodes
+ $rc = xCAT::TableUtils->setupSSH($options{'nodes'}, $options{'timeout'});
+ }
+
my @results = "return code = $rc";
return (@results);
}
diff --git a/perl-xCAT/xCAT/MacMap.pm b/perl-xCAT/xCAT/MacMap.pm
index 103ef87d4..e5cd444c6 100644
--- a/perl-xCAT/xCAT/MacMap.pm
+++ b/perl-xCAT/xCAT/MacMap.pm
@@ -543,11 +543,19 @@ sub refresh_table {
pipe my $child, my $parent;
$child->autoflush(1);
$parent->autoflush(1);
+
$children++;
my $cpid = xCAT::Utils->xfork;
- unless (defined $cpid) { die "Cannot fork" }
+ unless (defined $cpid) {
+ $children--;
+ close($child);
+ close($parent);
+ xCAT::MsgUtils->message("S", "refresh_table: failed to fork refresh_switch process for $entry->{switch},skip...");
+ next;
+ }
if ($cpid == 0) {
+ $SIG{CHLD} = 'DEFAULT';
close($child);
my $runstart = time;
$self->refresh_switch($parent, $community, $entry->{switch});
@@ -709,50 +717,55 @@ sub refresh_switch {
my $output = shift;
my $community = shift;
my $switch = shift;
+ my %index_to_vlan = ();
+ my %index_to_mac = ();
- unless($self->{collect_mac_info})
- {
- if($self->{switchparmhash}->{$switch}->{switchtype} eq 'onie'){
- #for cumulus switch, the MAC table can be retrieved with ssh
- #which is much faster than snmp
- my $mymac;
- my $myport;
+ if($self->{switchparmhash}->{$switch}->{switchtype} eq 'onie'){
+ #for cumulus switch, the MAC table can be retrieved with ssh
+ #which is much faster than snmp
+ my $mymac;
+ my $myport;
- 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);
- unless (@res) {
- 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");
- }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]+) .*/){
- $mymac=$1;
- $myport=$2;
- $myport=sprintf("%d",$myport);
-
- #try all the possible port number formats
- #e.g, "5","swp5","05","swp05"
- unless(exists $self->{switches}->{$switch}->{$myport}){
- if(exists $self->{switches}->{$switch}->{"swp".$myport}){
- $myport="swp".$myport;
- }else{
- $myport=sprintf("%02d",$myport);
- unless(exists $self->{switches}->{$switch}->{$myport}){
- if(exists $self->{switches}->{$switch}->{"swp".$myport}){
- $myport="swp".$myport;
- }else{
- $myport="";
- }
+ 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");
+ }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]+) .*/){
+ $mymac=$1;
+ $myport=$2;
+ $myport=sprintf("%d",$myport);
+ my $macport=$2;
+ my $macvlan=$3;
+
+ #try all the possible port number formats
+ #e.g, "5","swp5","05","swp05"
+ unless(exists $self->{switches}->{$switch}->{$myport}){
+ if(exists $self->{switches}->{$switch}->{"swp".$myport}){
+ $myport="swp".$myport;
+ }else{
+ $myport=sprintf("%02d",$myport);
+ unless(exists $self->{switches}->{$switch}->{$myport}){
+ if(exists $self->{switches}->{$switch}->{"swp".$myport}){
+ $myport="swp".$myport;
+ }else{
+ $myport="";
}
}
}
-
- if($myport){
- if($output){
- printf $output "$mymac|%s\n", $self->{switches}->{$switch}->{$myport};
- }
- }
}
+ if($myport){
+ if($output){
+ printf $output "$mymac|%s\n", $self->{switches}->{$switch}->{$myport};
+ }
+ }
+ push @{ $index_to_vlan{$macport} }, $macvlan;
+ push @{ $index_to_mac{$macport} }, $mymac;
}
+
+ }
+ unless($self->{collect_mac_info}) {
return;
}
}
@@ -797,12 +810,56 @@ sub refresh_switch {
return;
}
+ #check if it is Mellanox IB switch
+ foreach (keys %{$namemap}) {
+ my $ifname = $namemap->{$_};
+ if ($self->{collect_mac_info}) {
+ if ( ($ifname =~ /IB/) || ($ifname =~ /ib/) ) {
+ $self->{macinfo}->{$switch}->{ErrorStr} = "This command does not support Mellanox IB Switch";
+ return;
+ }
+ }
+ last;
+ }
+
# get mtu
my $iftomtumap = walkoid($session, '.1.3.6.1.2.1.2.2.1.4', silentfail => 1, verbose => $self->{show_verbose_info}, switch => $switch, callback => $self->{callback});
unless (defined($iftomtumap)) {
xCAT::MsgUtils->message("I", "MTU information is not availabe for this switch $switch");
}
+ my $iscisco = 0;
+ if ($self->{switchparmhash}->{$switch}->{switchtype} eq 'onie'){
+ my $bridgetoifmap = walkoid($session, '.1.3.6.1.2.1.17.1.4.1.2', ciscowarn => $iscisco, verbose => $self->{show_verbose_info}, switch => $switch, callback => $self->{callback}); # Good for all switches
+ if (not ref $bridgetoifmap or !keys %{$bridgetoifmap}) {
+ xCAT::MsgUtils->message("S", "Error communicating with " . $session->{DestHost} . ": failed to get a valid response to BRIDGE-MIB request");
+ $self->{macinfo}->{$switch}->{ErrorStr} = "Failed to get a valid response to BRIDGE-MIB request";
+ return;
+ }
+ foreach my $boid (keys %$bridgetoifmap) {
+ my $port_index = $boid;
+ my $port_name = $namemap->{ $bridgetoifmap->{$port_index} };
+ my $mtu = $iftomtumap->{ $bridgetoifmap->{$port_index} };
+ if (defined($index_to_mac{$port_index})) {
+ push @{ $self->{macinfo}->{$switch}->{$port_name} }, @{ $index_to_mac{$port_index} };
+ }
+ else {
+ $self->{macinfo}->{$switch}->{$port_name}->[0] = '';
+ }
+
+ if (defined($index_to_vlan{$port_index})) {
+ push @{ $self->{vlaninfo}->{$switch}->{$port_name} }, @{ $index_to_vlan{$port_index} };
+ }
+ else {
+ $self->{vlaninfo}->{$switch}->{$port_name}->[0] = '';
+ }
+ push @{ $self->{mtuinfo}->{$switch}->{$port_name} } , $mtu;
+
+ }
+ return;
+
+ }
+
# get port state
my $mactostate = walkoid($session, '.1.3.6.1.2.1.17.7.1.2.2.1.3', silentfail => 1, verbose => $self->{show_verbose_info}, switch => $switch, callback => $self->{callback});
@@ -844,7 +901,6 @@ sub refresh_switch {
}
my $vlan;
- my $iscisco = 0;
foreach $vlan (sort keys %vlans_to_check) { #Sort, because if numbers, we want 1 first, because that vlan should not get communiy string indexed query
unless (not $vlan or $vlan eq 'NA' or $vlan eq '1') { #don't subject users to the context pain unless needed
$iscisco = 1;
@@ -878,9 +934,22 @@ sub refresh_switch {
}
return;
}
+ my $bridgeifvalid = 0;
+ foreach (keys %$mactoindexmap) {
+ my $index = $mactoindexmap->{$_};
+ if (defined($bridgetoifmap->{$index})) {
+ $bridgeifvalid = 1;
+ last;
+ }
+ }
+ unless ($bridgeifvalid) {
+ # create a dummy bridgetoifmap to cover switches that thing it should go straight to ifindex
+ $bridgetoifmap = {};
+ foreach (keys %$namemap) {
+ $bridgetoifmap->{$_} = $_;
+ }
+ }
if (defined($self->{collect_mac_info})) {
- my %index_to_mac = ();
- my %index_to_vlan = ();
foreach (keys %$mactoindexmap) {
my $index = $mactoindexmap->{$_};
my @tmp = split /\./, $_;
diff --git a/perl-xCAT/xCAT/MsgUtils.pm b/perl-xCAT/xCAT/MsgUtils.pm
index 577d97ec4..079b5e3a7 100644
--- a/perl-xCAT/xCAT/MsgUtils.pm
+++ b/perl-xCAT/xCAT/MsgUtils.pm
@@ -884,5 +884,28 @@ sub perf_log_process
}
}
+#------------------------------------------------------------------
+
+=head3 report_node_error
+ Using the passing callback to report node level error
+ Arguments:
+ $cb (callback reference)
+ $node (node name)
+ $msg (error message)
+=cut
+
+#-----------------------------------------------------------------
+sub report_node_error
+{
+ shift;
+ my ($cb, $node, $msg) = @_;
+
+ my $rsp;
+ $rsp->{node}->[0]->{name}->[0] = $node;
+ $rsp->{node}->[0]->{error}->[0] = $msg;
+ $rsp->{node}->[0]->{errorcode}->[0] = 1;
+ $cb->($rsp);
+}
+
1;
diff --git a/perl-xCAT/xCAT/RemoteShellExp.pm b/perl-xCAT/xCAT/RemoteShellExp.pm
index 19ee11541..959405f35 100755
--- a/perl-xCAT/xCAT/RemoteShellExp.pm
+++ b/perl-xCAT/xCAT/RemoteShellExp.pm
@@ -466,7 +466,7 @@ sub testkeys
return 0;
} else {
my $rsp = {};
- $rsp->{error}->[0] = $msg;
+ $rsp->{error}->[0] = "Testing the ssh connection to $nodes failed:".$msg;
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
return 1;
}
@@ -598,7 +598,7 @@ sub sendnodeskeys
$rc = 0;
} else {
my $rsp = {};
- $rsp->{error}->[0] = "mkdir:$node has error,$msg";
+ $rsp->{error}->[0] = "Failed to run \"/bin/mkdir -p /tmp/$to_userid/.ssh\" on $node: $msg";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
$rc = 1;
}
@@ -686,7 +686,7 @@ sub sendnodeskeys
$rc = 0;
} else {
my $rsp = {};
- $rsp->{error}->[0] = "copykeys:$node has error,$msg";
+ $rsp->{error}->[0] = "Failed to copy ssh credentials and helper script to $node: $msg";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
$rc = 1;
}
@@ -715,7 +715,7 @@ sub sendnodeskeys
# command to run copy.sh
my $spawnruncopy =
- "$remoteshell $node -l $to_userid /tmp/$to_userid/.ssh/copy.sh";
+ "$remoteshell $node -l $to_userid /tmp/$to_userid/.ssh/copy.sh $to_userid";
# send mkdir command
unless ($sendkeys->spawn($spawnruncopy))
@@ -771,7 +771,7 @@ sub sendnodeskeys
$rc = 0;
} else {
my $rsp = {};
- $rsp->{error}->[0] = "copy.sh:$node has error,$msg";
+ $rsp->{error}->[0] = "Failed to apply the ssh keys on $node:$msg";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
$rc = 1;
}
diff --git a/perl-xCAT/xCAT/Schema.pm b/perl-xCAT/xCAT/Schema.pm
index c38db16d2..f01edfd98 100755
--- a/perl-xCAT/xCAT/Schema.pm
+++ b/perl-xCAT/xCAT/Schema.pm
@@ -276,7 +276,7 @@ qq{ link,ro - The file is readonly, and will be placed in tmpfs on the booted no
table_descr => 'Node storage resources',
descriptions => {
node => 'The node name',
- controller => 'The management address to attach/detach new volumes.
+ controller => 'The management address to attach/detach new volumes.
In the scenario involving multiple controllers, this data must be
passed as argument rather than by table value',
osvolume => "Specification of what storage to place the node OS image onto. Examples include:
@@ -664,13 +664,13 @@ passed as argument rather than by table value',
servicenode => 'A comma separated list of node names (as known by the management node) that provides most services for this node. The first service node on the list that is accessible will be used. The 2nd node on the list is generally considered to be the backup service node for this node when running commands like snmove.',
netboot => 'The type of network booting to use for this node. Valid values:
- Arch OS valid netboot options
- x86, x86_64 ALL pxe, xnba
+ Arch OS valid netboot options
+ x86, x86_64 ALL pxe, xnba
ppc64 <=rhel6, <=sles11.3 yaboot
ppc64 >=rhels7, >=sles11.4 grub2,grub2-http,grub2-tftp
ppc64le NonVirtualize ALL petitboot
ppc64le PowerKVM Guest ALL grub2,grub2-http,grub2-tftp
-
+
',
tftpserver => 'The TFTP server for this node (as known by this node). If not set, it defaults to networks.tftpserver.',
tftpdir => 'The directory that roots this nodes contents from a tftp and related perspective. Used for NAS offload by using different mountpoints.',
@@ -807,16 +807,16 @@ passed as argument rather than by table value',
exlist => 'The fully qualified name of the file that stores the file names and directory names that will be excluded from the image during packimage command. It is used for diskless image only.',
postinstall => 'Supported in diskless image only. The fully qualified name of the scripts running in non-chroot mode after the package installation but before initrd generation during genimage. If multiple scripts are specified, they should be seperated with comma ",". A set of osimage attributes are exported as the environment variables to be used in the postinstall scripts:
- IMG_ARCH(The architecture of the osimage, such as "ppc64le","x86_64"),
- IMG_NAME(The name of the osimage, such as "rhels7.3-ppc64le-netboot-compute"),
- IMG_OSVER(The os release of the osimage, such as "rhels7.3","sles11.4"),
+ IMG_ARCH(The architecture of the osimage, such as "ppc64le","x86_64"),
+ IMG_NAME(The name of the osimage, such as "rhels7.3-ppc64le-netboot-compute"),
+ IMG_OSVER(The os release of the osimage, such as "rhels7.3","sles11.4"),
IMG_KERNELVERSION(the "kernelver" attribute of the osimage),
- IMG_PROFILE(the profile of the osimage, such as "service","compute"),
- IMG_PKGLIST(the "pkglist" attribute of the osimage),
- IMG_PKGDIR(the "pkgdir" attribute of the osimage),
- IMG_OTHERPKGLIST(the "otherpkglist" attribute of the osimage),
- IMG_OTHERPKGDIR(the "otherpkgdir" attribute of the osimage),
- IMG_ROOTIMGDIR(the "rootimgdir" attribute of the osimage)',
+ IMG_PROFILE(the profile of the osimage, such as "service","compute"),
+ IMG_PKGLIST(the "pkglist" attribute of the osimage),
+ IMG_PKGDIR(the "pkgdir" attribute of the osimage),
+ IMG_OTHERPKGLIST(the "otherpkglist" attribute of the osimage),
+ IMG_OTHERPKGDIR(the "otherpkgdir" attribute of the osimage),
+ IMG_ROOTIMGDIR(the "rootimgdir" attribute of the osimage)',
rootimgdir => 'The directory name where the image is stored. It is generally used for diskless image. it also can be used in sysclone environment to specify where the image captured from golden client is stored. in sysclone environment, rootimgdir is generally assigned to some default value by xcat, but you can specify your own store directory. just one thing need to be noticed, wherever you save the image, the name of last level directory must be the name of image. for example, if your image name is testimage and you want to save this image under home directoy, rootimgdir should be assigned to value /home/testimage/',
kerneldir => 'The directory name where the 3rd-party kernel is stored. It is used for diskless image only.',
nodebootif => 'The network interface the stateless/statelite node will boot over (e.g. eth0)',
@@ -1069,7 +1069,7 @@ passed as argument rather than by table value',
" nodes, use a simple comma-separated list of NICs. To specify different \n" .
" NICs for different nodes, use the format: \"xcatmn|eth1,eth2;service|bond0\", \n" .
" where xcatmn is the name of the management node, and DNS should listen on\n" .
-" the eth1 and eth2 interfaces. All the nods in group 'service' should \n" .
+" the eth1 and eth2 interfaces. All the nods in group 'service' should \n" .
" listen on the 'bond0' interface.\n\n" .
" NOTE: If using this attribute to block certain interfaces, make sure\n" .
" the IP maps to your hostname of xCAT MN is not blocked since xCAT needs\n" .
@@ -1504,8 +1504,30 @@ passed as argument rather than by table value',
},
},
+zvmivp => {
+ cols => [qw(id ip schedule last_run type_of_run access_user orch_parms prep_parms main_ivp_parms comments disable)],
+ keys => [qw(id)],
+ table_desc => 'List of z/VM Installation Verification Procedures (IVPs) to be periodically run.',
+ descriptions => {
+ id => 'Unique identifier associated with the IVP run, e.g. 1.',
+ ip => 'IP address of the target system, either the IP of the OpenStack compute node or the xCAT management node.',
+ schedule => 'The hours (0-24) that the IVP should be run. Multiple hours are separated by a blank.',
+ last_run => 'The last time the IVP was run specified as a set of 3 blank delimeted words: year, Julian date, and hour (in 24 hour format).',
+ type_of_run => 'The type of run requested, \'fullivp\' or \'basicivp\'.',
+ access_user => 'User on the OpenStack node that is used to: push the IVP preparation script to the OpenStack system, '.
+ 'drive the preparation script to validate the OpenStack configuration files, and return the created '.
+ 'driver script to the xCAT MN system for the next part of the IVP. This user should be '.
+ 'able to access the OpenStack configuration files that are scanned by the IVP.',
+ orch_parms => 'Parameters to pass to the IVP orchestrator script, verifynode.',
+ prep_parms => 'Parameters to pass to the phase 1 IVP preparation script.',
+ main_ivp_parms => 'Parameters to pass to the main IVP script.',
+ comments => 'Any user provided notes or description of the run.',
+ disable => "Set to 'yes' or '1' to disable this IVP run.",
+ },
+ },
+
zvm => {
- cols => [qw(node hcp userid nodetype parent comments disable)],
+ cols => [qw(node hcp userid nodetype parent comments disable discovered status)],
keys => [qw(node)],
table_desc => 'List of z/VM virtual servers.',
descriptions => {
@@ -1516,6 +1538,8 @@ passed as argument rather than by table value',
parent => 'The parent node. For LPAR, this specifies the CEC. For z/VM, this specifies the LPAR. For VM, this specifies the z/VM host operating system.',
comments => 'Any user provided notes.',
disable => "Set to 'yes' or '1' to comment out this row.",
+ discovered => "Set to '1' to indicate this node was discovered.",
+ status => "The processing status. Key value pairs (key=value) indicating status of the node. Multiple pairs are separated by semi-colons. Keys include: CLONING, CLONE_ONLY.",
},
},
@@ -1551,6 +1575,7 @@ passed as argument rather than by table value',
If multiple ip addresses are associated with each NIC:
!|,!|,..., for example, eth0!-eth0|-eth0-ipv6,ib0!-ib0|-ib0-ipv6.
The xCAT object definition commands support to use nichostnamesuffixes. as the sub attributes.
+
Note: According to DNS rules a hostname must be a text string up to 24 characters drawn from the alphabet (A-Z), digits (0-9) and minus sign (-). When you are specifying "nichostnamesuffixes" or "nicaliases" make sure the resulting hostnames will conform to this naming convention',
nichostnameprefixes => 'Comma-separated list of hostname prefixes per NIC.
If only one ip address is associated with each NIC:
@@ -1869,6 +1894,7 @@ foreach my $tabname (keys(%xCAT::ExtTab::ext_tabspec)) {
osdistro => { attrs => [], attrhash => {}, objkey => 'osdistroname' },
osdistroupdate => { attrs => [], attrhash => {}, objkey => 'osupdatename' },
zone => { attrs => [], attrhash => {}, objkey => 'zonename' },
+ zvmivp => { attrs => [], attrhash => {}, objkey => 'id' },
firmware => { attrs => [], attrhash => {}, objkey => 'cfgfile' },
taskstate => { attrs => [], attrhash => {}, objkey => 'node' },
pdu => { attrs => [], attrhash => {}, objkey => 'node' },
diff --git a/perl-xCAT/xCAT/Usage.pm b/perl-xCAT/xCAT/Usage.pm
index efa72327e..67d1bee90 100755
--- a/perl-xCAT/xCAT/Usage.pm
+++ b/perl-xCAT/xCAT/Usage.pm
@@ -145,7 +145,7 @@ my %usage = (
rspconfig [garp=]
rspconfig [userid= username= password=]
OpenBMC specific:
- rspconfig [ip|netmask|gateway|hostname|vlan]
+ rspconfig [ipsrc|ip|netmask|gateway|hostname|vlan]
iDataplex specific:
rspconfig [thermprofile]
rspconfig [thermprofile=]
@@ -250,13 +250,16 @@ my %usage = (
lsvm [-a|--all]
PPC (using Direct FSP Management) specific:
lsvm [-l|--long] --p775
- lsvm
+ lsvm
zVM specific:
lsvm noderange
lsvm noderange --getnetworknames
lsvm noderange --getnetwork network_name
lsvm noderange --diskpoolnames
- lsvm noderange --diskpool pool_name",
+ lsvm noderange --diskpool pool_name
+ lsvm noderange --queryalldisks
+ lsvm noderange --querypagevolumes
+ lsvm noderange --queryspoolvolumes",
"chvm" =>
"Usage:
Common:
@@ -270,7 +273,7 @@ my %usage = (
chvm [lparname=<*|name>]
chvm [vmcpus=min/req/max] [vmmemory=min/req/max]
[vmothersetting=hugepage:N,bsr:N]
- [add_physlots=drc_index1,drc_index2...]
+ [add_physlots=drc_index1,drc_index2...]
[add_vmnics=vlan1,vlan2] [add_vmstorage=] [--vios]
chvm [del_physlots=drc_index1,drc_index2...]
chvm [del_vadapter=slotid]
@@ -328,7 +331,7 @@ my %usage = (
pdudiscover [|--range ipranges] [-r|-x|-z] [-w] [-V|--verbose] [--setup]",
"switchdiscover" =>
"Usage: switchdiscover [-h|--help|-v|--version]
- switchdiscover [|--range ipranges] [-s scan_methods] [-r|-x|-z] [-w] [-V|--verbose] [--setup]",
+ switchdiscover [|--range ipranges] [-s scan_methods] [-c community] [-r|-x|-z] [-w] [-V|--verbose] [--setup]",
"switchprobe" =>
"Usage: switchprobe [] [-V|--verbose | -c|--check]",
"makentp" =>
@@ -448,7 +451,7 @@ Options:
[-f|--snsync] Performs File Syncing to the service nodes that service
the nodes in the noderange.
- [-g|--genmypost] Will generate a new mypostscript file for the
+ [-g|--genmypost] Will generate a new mypostscript file for the
the nodes in the noderange, if site precreatemypostscripts is 1 or YES.
[-l|--user] User name to run the updatenode command. It overrides the
diff --git a/perl-xCAT/xCAT/Utils.pm b/perl-xCAT/xCAT/Utils.pm
index e44a184ee..35b9abea2 100644
--- a/perl-xCAT/xCAT/Utils.pm
+++ b/perl-xCAT/xCAT/Utils.pm
@@ -2294,11 +2294,19 @@ sub osver
$os = $id_like;
}
+ if (!$os ) {
+ $os = "unknown";
+ }
+
$verrel = $version;
if (!$verrel and $version_id) {
$verrel = $version_id;
}
+ if (!$verrel ) {
+ $verrel = "unknown";
+ }
+
if (!$name and $prettyname) {
$name = $prettyname;
diff --git a/perl-xCAT/xCAT/zvmCPUtils.pm b/perl-xCAT/xCAT/zvmCPUtils.pm
index 7c12ab418..22f5e67b7 100644
--- a/perl-xCAT/xCAT/zvmCPUtils.pm
+++ b/perl-xCAT/xCAT/zvmCPUtils.pm
@@ -2,7 +2,7 @@
#-------------------------------------------------------
=head1
-
+
This is a CP utility plugin for z/VM.
=cut
@@ -23,14 +23,14 @@ use warnings;
Node
Returns : UserID
Example : my $userID = xCAT::zvmCPUtils->getUserId($node);
-
+
=cut
#-------------------------------------------------------
sub getUserId {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -38,10 +38,15 @@ sub getUserId {
}
# Get user ID using VMCP
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q userid"`;
- my @results = split(' ', $out);
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q userid"`;
+ my $cmd = "$sudo /sbin/vmcp q userid";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
+ my @results = split( ' ', $out );
- return ($results[0]);
+ return ( $results[0] );
}
#-------------------------------------------------------
@@ -53,14 +58,14 @@ sub getUserId {
Node
Returns : z/VM host
Example : my $host = xCAT::zvmCPUtils->getHost($node);
-
+
=cut
#-------------------------------------------------------
sub getHost {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -68,8 +73,13 @@ sub getHost {
}
# Get host using VMCP
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q userid"`;
- my @results = split(' ', $out);
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q userid"`;
+ my $cmd = "$sudo /sbin/vmcp q userid";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
+ my @results = split( ' ', $out );
my $host = $results[2];
return ($host);
@@ -84,14 +94,14 @@ sub getHost {
Node
Returns : Privilege class
Example : my $class = xCAT::zvmCPUtils->getPrivileges($node);
-
+
=cut
#-------------------------------------------------------
sub getPrivileges {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -99,10 +109,15 @@ sub getPrivileges {
}
# Get privilege class
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q priv"`;
- my @out = split('\n', $out);
- $out[1] = xCAT::zvmUtils->trimStr($out[1]);
- $out[2] = xCAT::zvmUtils->trimStr($out[2]);
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q priv"`;
+ my $cmd = "$sudo /sbin/vmcp q priv";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
+ my @out = split( '\n', $out );
+ $out[1] = xCAT::zvmUtils->trimStr( $out[1] );
+ $out[2] = xCAT::zvmUtils->trimStr( $out[2] );
my $str = " $out[1]\n $out[2]\n";
return ($str);
@@ -116,15 +131,15 @@ sub getPrivileges {
Arguments : User (root or non-root)
Node
Returns : Memory
- Example : my $memory = xCAT::zvmCPUtils->getMemory($node);
-
+ Example : my $memory = xCAT::zvmCPUtils->getMemory($user, $node);
+
=cut
#-------------------------------------------------------
sub getMemory {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -132,10 +147,15 @@ sub getMemory {
}
# Get memory
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q virtual storage"`;
- my @out = split(' ', $out);
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q virtual storage"`;
+ my $cmd = "$sudo /sbin/vmcp q virtual storage";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
+ my @out = split( ' ', $out );
- return (xCAT::zvmUtils->trimStr($out[2]));
+ return ( xCAT::zvmUtils->trimStr( $out[2] ) );
}
@@ -148,15 +168,15 @@ sub getMemory {
Arguments : User (root or non-root)
Node
Returns : Processor(s)
- Example : my $proc = xCAT::zvmCPUtils->getCpu($node);
-
+ Example : my $proc = xCAT::zvmCPUtils->getCpu( $user, $node );
+
=cut
#-------------------------------------------------------
sub getCpu {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -164,7 +184,12 @@ sub getCpu {
}
# Get processors
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q virtual cpus"`;
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q virtual cpus"`;
+ my $cmd = "$sudo /sbin/vmcp q virtual cpus";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
my $str = xCAT::zvmUtils->tabStr($out);
return ($str);
@@ -179,14 +204,14 @@ sub getCpu {
Node
Returns : NIC(s)
Example : my $nic = xCAT::zvmCPUtils->getNic($node);
-
+
=cut
#-------------------------------------------------------
sub getNic {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -194,7 +219,12 @@ sub getNic {
}
# Get NIC
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q virtual nic"`;
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q virtual nic"`;
+ my $cmd = "$sudo /sbin/vmcp q virtual nic";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
my $str = xCAT::zvmUtils->tabStr($out);
return ($str);
@@ -209,14 +239,38 @@ sub getNic {
Node
Returns : Network names
Example : my $lans = xCAT::zvmCPUtils->getNetworkNames($user, $node);
-
+
=cut
#-------------------------------------------------------
sub getNetworkNames {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
+
+ # Directory where executables are
+ my $dir = '/opt/zhcp/bin';
+ my $hcp;
+ my $hcpUserId;
+ # Get node properties from 'zvm' table
+ my @propNames = ( 'hcp', 'userid' );
+ my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
+
+ # Get zHCP. If not propVals then the node is probably a zhcp
+ if (!$propVals) {
+ $hcpUserId = xCAT::zvmCPUtils->getUserId($::SUDOER, $node);
+ $hcpUserId =~ tr/a-z/A-Z/;
+ $hcp = $node;
+ } else {
+ $hcp = $propVals->{'hcp'};
+ $hcpUserId = xCAT::zvmCPUtils->getUserId($::SUDOER, $hcp);
+ $hcpUserId =~ tr/a-z/A-Z/;
+ }
+
+ if ( !$hcpUserId ) {
+ xCAT::zvmUtils->printSyslog("$node: (Error) Missing node HCP. Userid: $hcpUserId");
+ return ("$node: (Error) Missing node HCP. Userid: $hcpUserId");
+ }
my $sudo = "sudo";
if ($user eq "root") {
@@ -224,28 +278,128 @@ sub getNetworkNames {
}
# Get network names
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q lan | egrep 'LAN|VSWITCH'"`;
- my @lines = split('\n', $out);
- my @parms;
+ my $out;
+ my $outmsg;
my $names;
- foreach (@lines) {
+ my $count;
+ my @parms;
+ my @lines;
+ my $switchNamesFound = "";
+ my $start = 0;
+ my $switchName;
+ my $lanType;
+ my $lanName;
+ my $lanOwner;
+ my $rc;
- # Trim output
- $_ = xCAT::zvmUtils->trimStr($_);
- @parms = split(' ', $_);
+ #If this is zhcp then use SMAPI calls to get network names; otherwise use q lan
+ if (!$propVals) {
+ my $retStr;
+ # First get the VSWITCH information, saving the switch name
+ xCAT::zvmUtils->printSyslog("ssh $user\@$hcp $sudo $dir/smcli Virtual_Network_Vswitch_Query_Extended -T $hcpUserId -k 'switch_name=*'");
+ $out = `ssh $user\@$hcp "$sudo $dir/smcli Virtual_Network_Vswitch_Query_Extended -T $hcpUserId -k 'switch_name=*'"`;
+ $rc = $? >> 8;
+ if ($rc == 255) {
+ $retStr = "(Error) Failed to communicate with the zhcp system: $hcpUserId";
+ xCAT::zvmUtils->printSyslog($retStr);
+ return $retStr;
+ } elsif ($rc) {
+ $retStr = "(Error) Error trying to execute smcli Virtual_Network_Vswitch_Query_Extended. rc:$rc Output:$out";
+ xCAT::zvmUtils->printSyslog($retStr);
+ return $retStr;
+ }
+ if ( $out =~ m/Failed/i ) {
+ xCAT::zvmUtils->printSyslog($out);
+ return ($out);
+ }
+ @lines = split( '\n', $out );
+ # Just get the lines with "switch_name"
+ @lines = grep /switch_name/, @lines;
+ $count = @lines;
- # Get the network name
- if ($parms[0] eq "LAN") {
+ # Grep output is 1 line for each item
+ for (my $i=0; $i < $count; $i++) {
+ @parms = split( ' ', $lines[$i]);
+ $switchName = $parms[1];
+ $switchNamesFound .= "+" . $switchName . "+";
+ $names .= "VSWITCH" . " " . "SYSTEM" . " " . $switchName . "\n";
+ }
- # Determine if this network is a hipersocket
- # Only hipersocket guest LANs are supported
- if ($_ =~ m/Type: HIPERS/i) {
- $names .= $parms[0] . ":HIPERS " . $parms[1] . " " . $parms[2] . "\n";
+ # Next get the LAN information, skipping switches we have
+ xCAT::zvmUtils->printSyslog("ssh $user\@$hcp $sudo $dir/smcli Virtual_Network_LAN_Query -T $hcpUserId -n '*' -o '*'");
+ $out = `ssh $user\@$hcp "$sudo $dir/smcli Virtual_Network_LAN_Query -T $hcpUserId -n '*' -o '*'"`;
+ $rc = $? >> 8;
+ if ($rc == 255) {
+ $retStr = "(Error) Failed to communicate with the zhcp system: $hcpUserId";
+ xCAT::zvmUtils->printSyslog($retStr);
+ return $retStr;
+ } elsif ($rc) {
+ $retStr = "(Error) Error trying to execute smcli Virtual_Network_LAN_Query. rc:$rc Output:$out";
+ xCAT::zvmUtils->printSyslog($retStr);
+ return $retStr;
+ }
+ if ( $out =~ m/Failed/i ) {
+ xCAT::zvmUtils->printSyslog($out);
+ return ($out);
+ }
+ @lines = split( '\n', $out );
+ # Just get the lines with "Name:|Owner:|LAN type:"
+ @lines = grep /Name:|Owner:|LAN type:/, @lines;
+ $count = @lines;
+
+ # Grep output is 3 lines for each item
+ for (my $i=0; $i < ($count/3); $i++) {
+ @parms = split( ' ', $lines[$start]);
+ $lanName = $parms[1];
+ $start++;
+ @parms = split(' ', $lines[$start]);
+ $lanOwner = $parms[1];
+ $start++;
+ if ( $lines[$start] =~ m/QDIO/i ) {
+ $lanType = ":QDIO ";
} else {
- $names .= $parms[0] . ":QDIO " . $parms[1] . " " . $parms[2] . "\n";
+ $lanType = ":HIPERS ";
+ }
+ $start++;
+ # Skip any lanNames that were found by VSWITCH query
+ my $search = "+$lanName+";
+ if (index($switchNamesFound, $search) == -1) {
+ $names .= "LAN" . $lanType . $lanOwner . " " . $lanName . "\n";
+ }
+ }
+ # use vmcp q lan if this is not the zhcp node
+ } else {
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q lan | egrep 'LAN|VSWITCH'"`;
+ my $cmd = $sudo . ' /sbin/vmcp q lan';
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i 'LAN|VSWITCH'`;
+ @lines = split( '\n', $out );
+
+ foreach (@lines) {
+
+ # Trim output
+ $_ = xCAT::zvmUtils->trimStr($_);
+ @parms = split( ' ', $_ );
+
+ # sample output from q lan
+ # LAN SYSTEM GLAN1 Type: QDIO Connected: 1 Maxconn: INFINITE
+ # VSWITCH SYSTEM XCATVSW1 Type: QDIO Connected: 2 Maxconn: INFINITE
+ # Get the network name
+ if ( $parms[0] eq "LAN" ) {
+
+ # Determine if this network is a hipersocket
+ # Only hipersocket guest LANs are supported
+ if ( $_ =~ m/Type: HIPERS/i ) {
+ $names .= $parms[0] . ":HIPERS " . $parms[1] . " " . $parms[2] . "\n";
+ } else {
+ $names .= $parms[0] . ":QDIO " . $parms[1] . " " . $parms[2] . "\n";
+ }
+ } elsif ( $parms[0] eq "VSWITCH" ) {
+ $names .= $parms[0] . " " . $parms[1] . " " . $parms[2] . "\n";
}
- } elsif ($parms[0] eq "VSWITCH") {
- $names .= $parms[0] . " " . $parms[1] . " " . $parms[2] . "\n";
}
}
@@ -261,14 +415,14 @@ sub getNetworkNames {
Node
Returns : Array of networks names
Example : my @networks = xCAT::zvmCPUtils->getNetworkNamesArray($user, $node);
-
+
=cut
#-------------------------------------------------------
sub getNetworkNamesArray {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my @networks;
my %netHash;
@@ -278,25 +432,29 @@ sub getNetworkNamesArray {
}
# Get the networks used by the node
- my $out = `ssh $user\@$node "$sudo /sbin/vmcp q v nic" | egrep -i "VSWITCH|LAN"`;
- my @lines = split('\n', $out);
+ #my $out = `ssh $user\@$node "$sudo /sbin/vmcp q v nic" | egrep -i "VSWITCH|LAN"`;
+ my $cmd = $sudo . ' /sbin/vmcp q v nic';
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i 'VSWITCH|LAN'`;
+ my @lines = split( '\n', $out );
# Loop through each line
my $line;
my @words;
my $name;
- foreach (@lines) {
-
+ foreach(@lines) {
# Get network name
# Line should contain: MAC: 02-00-01-00-00-12 VSWITCH: SYSTEM VSW1
- $line = xCAT::zvmUtils->trimStr($_);
- @words = split(' ', $line);
+ $line = xCAT::zvmUtils->trimStr( $_ );
+ @words = split( ' ', $line );
if (@words) {
- $name = xCAT::zvmUtils->trimStr($words[4]);
+ $name = xCAT::zvmUtils->trimStr( $words[4] );
# If network is not 'None'
if ($name ne 'None') {
-
# Save network
$netHash{$name} = 1;
}
@@ -304,7 +462,7 @@ sub getNetworkNamesArray {
}
# Push networks into array
- foreach $name (keys %netHash) {
+ foreach $name ( keys %netHash ) {
push(@networks, $name);
}
@@ -321,26 +479,110 @@ sub getNetworkNamesArray {
Network name
Returns : Network configuration
Example : my $config = xCAT::zvmCPUtils->getNetwork($node, $netName);
-
+
=cut
#-------------------------------------------------------
sub getNetwork {
# Get inputs
- my ($class, $user, $node, $netName) = @_;
+ my ( $class, $user, $node, $netName, $netType ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
- # Get network info
+ # Directory where executables are
+ my $dir = '/opt/zhcp/bin';
+ my $hcp;
+ my $hcpUserId;
my $out;
+ my $retStr;
+ my $rc;
+
+ my $netNameQuery = $netName;
if ($netName eq "all") {
- $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q lan"`;
+ $netNameQuery = "*";
+ }
+
+ xCAT::zvmUtils->printSyslog("getNetwork for NetType:$netType NetName:$netName NetNameQuery:$netNameQuery");
+
+ # Get node properties from 'zvm' table
+ my @propNames = ( 'hcp', 'userid' );
+ my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
+
+ # Get zHCP. If not propVals then the node is probably a zhcp
+ if (!$propVals) {
+ $hcpUserId = xCAT::zvmCPUtils->getUserId($::SUDOER, $node);
+ $hcpUserId =~ tr/a-z/A-Z/;
+ $hcp = $node;
} else {
- $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q lan $netName"`;
+ $hcp = $propVals->{'hcp'};
+ $hcpUserId = xCAT::zvmCPUtils->getUserId($::SUDOER, $hcp);
+ $hcpUserId =~ tr/a-z/A-Z/;
+ }
+
+ if ( !$hcpUserId ) {
+ xCAT::zvmUtils->printSyslog("$node: (Error) Missing node HCP. Userid: $hcpUserId");
+ return ("$node: (Error) Missing node HCP. Userid: $hcpUserId");
+ }
+
+ #If this is zhcp then use SMAPI calls to get network names; otherwise use q lan
+ if (!$propVals) {
+ # If this is a vswitch, use: Virtual_Network_Vswitch_Query_Extended
+ if (index($netType, "VSWITCH") >= 0) {
+ xCAT::zvmUtils->printSyslog("ssh $user\@$hcp $sudo $dir/smcli Virtual_Network_Vswitch_Query_Extended -T $hcpUserId -k 'switch_name='$netNameQuery -k 'VEPA_STATUS=YES'");
+ $out = `ssh $user\@$hcp "$sudo $dir/smcli Virtual_Network_Vswitch_Query_Extended -T $hcpUserId -k 'switch_name='$netNameQuery -k 'VEPA_STATUS=YES'"`;
+ $rc = $? >> 8;
+ if ($rc == 255) {
+ $retStr = "(Error) Failed to communicate with the zhcp system: $hcpUserId";
+ xCAT::zvmUtils->printSyslog($retStr);
+ return $retStr;
+ } elsif ($rc) {
+ $retStr = "(Error) Error trying to execute smcli Virtual_Network_Vswitch_Query_Extended. rc:$rc Output:$out";
+ xCAT::zvmUtils->printSyslog($retStr);
+ return $retStr;
+ }
+ if ( $out =~ m/Failed/i ) {
+ xCAT::zvmUtils->printSyslog($out);
+ }
+ } else {
+ # Get the LAN information
+ xCAT::zvmUtils->printSyslog("ssh $user\@$hcp $sudo $dir/smcli Virtual_Network_LAN_Query -T $hcpUserId -n $netNameQuery -o '*'");
+ $out = `ssh $user\@$hcp "$sudo $dir/smcli Virtual_Network_LAN_Query -T $hcpUserId -n $netNameQuery -o '*' "`;
+ $rc = $? >> 8;
+ if ($rc == 255) {
+ $retStr = "(Error) unable to communicate with the zhcp system: $hcpUserId";
+ xCAT::zvmUtils->printSyslog($retStr);
+ return $retStr;
+ } elsif ($rc) {
+ $retStr = "(Error) Error trying to execute smcli Virtual_Network_LAN_Query. rc:$rc Output:$out";
+ xCAT::zvmUtils->printSyslog($retStr);
+ return $retStr;
+ }
+ if ( $out =~ m/Failed/i ) {
+ xCAT::zvmUtils->printSyslog($out);
+ }
+ }
+ # if not zhcp use q lan output
+ } else {
+ # Get network info.
+ if ( $netName eq "all" ) {
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q lan"`;
+ my $cmd = "$sudo /sbin/vmcp q lan";
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
+ } else {
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q lan $netName"`;
+ my $cmd = "$sudo /sbin/vmcp q lan $netName";
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
+ }
}
return ($out);
@@ -355,14 +597,14 @@ sub getNetwork {
Node
Returns : Disk(s)
Example : my $storage = xCAT::zvmCPUtils->getDisks($node);
-
+
=cut
#-------------------------------------------------------
sub getDisks {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -370,7 +612,12 @@ sub getDisks {
}
# Get disks
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q virtual dasd"`;
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q virtual dasd"`;
+ my $cmd = "$sudo /sbin/vmcp q virtual dasd";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
my $str = xCAT::zvmUtils->tabStr($out);
return ($str);
@@ -383,16 +630,17 @@ sub getDisks {
Description : Load Linux VMCP module on a given node
Arguments : User (root or non-root)
Node
- Returns : Nothing
+ Returns : Nothing, or error string
+
Example : xCAT::zvmCPUtils->loadVmcp($node);
-
+
=cut
#-------------------------------------------------------
sub loadVmcp {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -400,8 +648,8 @@ sub loadVmcp {
}
# Load Linux VMCP module
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/modprobe vmcp"`;
- return;
+ my $cmd = "$sudo /sbin/modprobe vmcp";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
}
#-------------------------------------------------------
@@ -413,14 +661,14 @@ sub loadVmcp {
Node
Returns : VSwitch ID(s)
Example : my @vswitch = xCAT::zvmCPUtils->getVswitchId($node);
-
+
=cut
#-------------------------------------------------------
sub getVswitchId {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -428,13 +676,19 @@ sub getVswitchId {
}
# Get VSwitch
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q v nic" | grep "VSWITCH"`;
- my @lines = split('\n', $out);
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q v nic" | grep "VSWITCH"`;
+ my $cmd = $sudo . ' /sbin/vmcp q v nic';
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i 'VSWITCH'`;
+ my @lines = split( '\n', $out );
my @parms;
my @vswitch;
foreach (@lines) {
- @parms = split(' ', $_);
- push(@vswitch, $parms[4]);
+ @parms = split( ' ', $_ );
+ push( @vswitch, $parms[4] );
}
return @vswitch;
@@ -444,21 +698,23 @@ sub getVswitchId {
=head3 grantVSwitch
- Description : Grant VSwitch access for a given userID
+ Description : Grant VSwitch access for a given userID
Arguments : User (root or non-root)
zHCP
User ID
VSWITCH ID
+ lan port type ( or '')
+ vlan id (or '')
Returns : Operation results (Done/Failed)
- Example : my $out = xCAT::zvmCPUtils->grantVswitch($callback, $hcp, $userId, $vswitchId);
-
+ Example : my $out = xCAT::zvmCPUtils->grantVswitch($callback, $hcp, $userId, $vswitchId, [$vlanporttype, $vlanid]);
+
=cut
#-------------------------------------------------------
sub grantVSwitch {
# Get inputs
- my ($class, $callback, $user, $hcp, $userId, $vswitchId) = @_;
+ my ( $class, $callback, $user, $hcp, $userId, $vswitchId, $vlanporttype, $vlanid ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
@@ -468,23 +724,81 @@ sub grantVSwitch {
$sudo = "";
}
- # Use SMAPI EXEC
- my $out = `ssh $user\@$hcp "$sudo $dir/smcli Virtual_Network_Vswitch_Set -T SYSTEM -n $vswitchId -I $userId"`;
- xCAT::zvmUtils->printSyslog("grantVSwitch- ssh $user\@$hcp $sudo $dir/smcli Virtual_Network_Vswitch_Set -T SYSTEM -n $vswitchId -I $userId");
+ my $lanidparm = '';
+ if ($vlanporttype ne "") {
+ $lanidparm = " -k \'port_type=" + $vlanporttype + "\'";
+ }
+ if ($vlanid ne "") {
+ $lanidparm += " -k \'user_vlan_id=" + $vlanid + "\'";
+ }
+
+ # Use SMAPI EXEC, use new extended SMAPI vs old one
+ # my $out = `ssh $user\@$hcp "$sudo $dir/smcli Virtual_Network_Vswitch_Set -T SYSTEM -n $vswitchId -I $userId -u 2"`;
+ # xCAT::zvmUtils->printSyslog("grantVSwitch- ssh $user\@$hcp $sudo $dir/smcli Virtual_Network_Vswitch_Set -T SYSTEM -n $vswitchId -I $userId -u 2");
+ xCAT::zvmUtils->printSyslog( "grantVSwitch- ssh $user\@$hcp $sudo $dir/smcli Virtual_Network_Vswitch_Set_Extended -T SYSTEM -k 'switch_name='$vswitchId -k 'grant_userid='$userId -k 'persist=YES '$lanidparm" );
+ my $out = `ssh $user\@$hcp "$sudo $dir/smcli Virtual_Network_Vswitch_Set_Extended -T SYSTEM -k 'switch_name='$vswitchId -k 'grant_userid='$userId -k 'persist=YES' $lanidparm"`;
+
$out = xCAT::zvmUtils->trimStr($out);
# If return string contains 'Done' - Operation was successful
my $retStr;
- if ($out =~ m/Done/i) {
+ if ( $out =~ m/Done/i ) {
$retStr = "Done\n";
} else {
- $retStr = "Failed\n";
+ $retStr = "Failed " . "Error output: $out\n";
+ xCAT::zvmUtils->printSyslog("Error output: $out");
return $retStr;
}
return $retStr;
}
+=head3 revokeVSwitch
+
+ Description : Revoke VSwitch access for a given userID
+ Arguments : User (root or non-root)
+ zHCP
+ User ID
+ VSWITCH ID
+ Returns : Operation results (Done/Failed)
+ Example : my $out = xCAT::zvmCPUtils->revokeVswitch($callback, $hcp, $userId, $vswitchId);
+
+=cut
+
+#-------------------------------------------------------
+sub revokeVSwitch {
+
+ # Get inputs
+ my ( $class, $callback, $user, $hcp, $userId, $vswitchId ) = @_;
+
+ # Directory where executables are
+ my $dir = '/opt/zhcp/bin';
+
+ my $sudo = "sudo";
+ if ($user eq "root") {
+ $sudo = "";
+ }
+
+ # Use SMAPI EXEC, use new extended SMAPI
+ my $out = `ssh $user\@$hcp "$sudo $dir/smcli Virtual_Network_Vswitch_Set_Extended -T SYSTEM -k 'switch_name='$vswitchId -k 'revoke_userid='$userId -k 'persist=YES'"`;
+ xCAT::zvmUtils->printSyslog("revokeVSwitch- ssh $user\@$hcp $sudo $dir/smcli Virtual_Network_Vswitch_Set_Extended -T SYSTEM -k 'switch_name='$vswitchId -k 'revoke_userid='$userId -k 'persist=YES'");
+ $out = xCAT::zvmUtils->trimStr($out);
+
+ xCAT::zvmUtils->printSyslog($out);
+
+
+ # If return string contains 'Done' - Operation was successful
+ my $retStr;
+ if ( $out =~ m/Done/i ) {
+ $retStr = "Done\n";
+ } else {
+ $retStr = "Failed " . "Error output: $out\n";
+ xCAT::zvmUtils->printSyslog("Error output: $out");
+ return $retStr;
+ }
+
+ return $retStr;
+}
#-------------------------------------------------------
=head3 flashCopy
@@ -498,14 +812,14 @@ sub grantVSwitch {
Target address
Returns : Operation results (Done/Failed)
Example : my $results = xCAT::zvmCPUtils->flashCopy($user, $hcp, $srcAddr, $targetAddr);
-
+
=cut
#-------------------------------------------------------
sub flashCopy {
# Get inputs
- my ($class, $user, $hcp, $srcAddr, $tgtAddr) = @_;
+ my ( $class, $user, $hcp, $srcAddr, $tgtAddr ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
@@ -516,17 +830,20 @@ sub flashCopy {
}
# Flash copy using CP
+
+ xCAT::zvmUtils->printSyslog("CP FlashCopy- ssh $user\@$hcp $sudo /sbin/vmcp flashcopy $srcAddr 0 end to $tgtAddr 0 end synchronous");
my $out = `ssh $user\@$hcp "$sudo /sbin/vmcp flashcopy $srcAddr 0 end to $tgtAddr 0 end synchronous"`;
$out = xCAT::zvmUtils->trimStr($out);
# If return string contains 'Command complete' - Operation was successful
my $retStr = "";
- if ($out =~ m/Command complete/i) {
+ if ( $out =~ m/Command complete/i ) {
$retStr = "Copying data via CP FLASHCOPY... Done\n";
} else {
$out = xCAT::zvmUtils->tabStr($out);
$retStr = "Copying data via CP FLASHCOPY... Failed\n$out";
+ xCAT::zvmUtils->printSyslog("$out");
}
return $retStr;
@@ -545,18 +862,20 @@ sub flashCopy {
Target address
Returns : Operation results (Done/Failed)
Example : my $results = xCAT::zvmCPUtils->smapiFlashCopy($user, $node, $srcId, $srcAddr, $tgtId, $targetAddr);
-
+
=cut
#-------------------------------------------------------
sub smapiFlashCopy {
# Get inputs
- my ($class, $user, $hcp, $srcId, $srcAddr, $tgtId, $tgtAddr) = @_;
+ my ( $class, $user, $hcp, $srcId, $srcAddr, $tgtId, $tgtAddr ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
+ my $retStr = "";
+
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
@@ -565,19 +884,23 @@ sub smapiFlashCopy {
my $hcpUserId = xCAT::zvmCPUtils->getUserId($user, $hcp);
# Use SMAPI EXEC to flash copy
- my $cmd = '\"' . "CMD=FLASHCOPY $srcId $srcAddr 0 END $tgtId $tgtAddr 0 END" . '\"';
- my $out = `ssh $user\@$hcp "$sudo $dir/smcli xCAT_Commands_IUO -T $hcpUserId -c $cmd"`;
+ my $cmd = '\"' . "CMD=FLASHCOPY $srcId $srcAddr 0 END $tgtId $tgtAddr 0 END SYNC" . '\"';
xCAT::zvmUtils->printSyslog("smapiFlashCopy- ssh $user\@$hcp $sudo $dir/smcli xCAT_Commands_IUO -T $hcpUserId -c $cmd");
+ my $out = `ssh $user\@$hcp "$sudo $dir/smcli xCAT_Commands_IUO -T $hcpUserId -c $cmd"`;
+ my $rc = $? >> 8;
+ if ($rc == 255) {
+ $retStr = "(Error) Failed to communicate with the zhcp system: $hcp output:$out";
+ return $retStr;
+ }
$out = xCAT::zvmUtils->trimStr($out);
# If return string contains 'Done' - Operation was successful
- my $retStr = "";
- if ($out =~ m/Done/i) {
+ if (( $out =~ m/Done/i ) or (($out =~ m/Return Code: 592/i) and ($out =~m/Reason Code: 8888/i))) {
$retStr = "Copying data via SMAPI FLASHCOPY... Done\n";
} else {
$out = xCAT::zvmUtils->tabStr($out);
- $retStr = "Copying data via SMAPI FLASHCOPY... $out";
+ $retStr = "An Error occurred copying data via SMAPI FLASHCOPY... $out";
}
return $retStr;
@@ -593,44 +916,145 @@ sub smapiFlashCopy {
UserID to receive file
Source file
Target file to be created by punch (e.g. sles.parm)
- Options, e.g. -t (Convert EBCDIC to ASCII)
- Returns : Operation results (Done/Failed)
- Example : my $rc = xCAT::zvmCPUtils->punch2Reader($hcp, $userId, $srcFile, $tgtFile, $options);
-
+ Options, e.g. -t (Convert EBCDIC to ASCII) or "" for no options
+ SPOOL file class to be assigned to the punched file
+ "" means that the current class is to be used
+ anything else is the class to set on the punched file
+ Returns : Operation results ("Done" or "Failed" with additional info)
+ Example : my $response = xCAT::zvmCPUtils->punch2Reader( $user, $hcp, $userId, $srcFile,
+ $tgtFile, $options, $spoolClass );
+
=cut
#-------------------------------------------------------
sub punch2Reader {
- my ($class, $user, $hcp, $userId, $srcFile, $tgtFile, $options) = @_;
+ my ( $class, $user, $hcp, $userId, $srcFile, $tgtFile, $options, $spoolClass ) = @_;
+
+ my $out = "";
+ my $punched = 0;
+ my $rc = 0;
+ my $subResp = "";
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
+ my $punchTarget = "";
+ if ( $spoolClass eq "" ) {
+ $punchTarget = "-u $userId";
+ }
+
# Get source node OS
my $os = xCAT::zvmUtils->getOsVersion($user, $hcp);
- # Punch to reader
# VMUR located in different directories on RHEL and SLES
- my $out;
- if ($os =~ m/sles10/i) {
- $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmur punch $options -u $userId -r $srcFile -N $tgtFile"`;
- } elsif ($os =~ m/rhel/i) {
- $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /usr/sbin/vmur punch $options -u $userId -r $srcFile -N $tgtFile"`;
+ my $vmur;
+ if ( $os =~ m/sles10/i ) {
+ $vmur = "/sbin/vmur";
} else {
- $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /usr/sbin/vmur punch $options -u $userId -r $srcFile -N $tgtFile"`;
+ $vmur = "/usr/sbin/vmur";
}
- # If punch is successful -- Look for this string
- my $searchStr = "created and transferred";
- if (!($out =~ m/$searchStr/i)) {
- $out = "Failed\n";
- } else {
- $out = "Done\n";
+ # Punch the file. A loop is done in case the punch is currently in use.
+ my $done = 0;
+ my $maxTries = 12; # 12 attempts with 15 second waits for punch to become available
+ my $maxTime = $maxTries / 4; # Total time: 3 minutes
+ for ( my $i=0; ( $i < $maxTries and !$done ); $i++ ) {
+ $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo $vmur punch $options $punchTarget -r $srcFile -N $tgtFile" 2>&1`;
+ $rc = $? >> 8;
+ if ( $rc == 255 ) {
+ xCAT::zvmUtils->printSyslog( "(Error) In punch2Reader(), SSH communication with $hcp failed for command: $vmur punch" );
+ $subResp = "Failed to communicate with the zHCP system: $hcp";
+ $done = 1;
+ } elsif ( $out =~ m/A concurrent instance of vmur is already active/i ) {
+ # Recoverable error: retry the command after a delay
+ xCAT::zvmUtils->printSyslog( "punch2Reader() Punch in use on $hcp, retrying in 15 seconds" );
+ $subResp = "Failed, Punch in use on $hcp for over $maxTime minutes."; # Assume it will never become available
+ sleep( 15 );
+ } elsif ( $rc == 0 ) {
+ # Punch appears successful
+ $subResp = '';
+ $punched = 1;
+ $done = 1;
+ } else {
+ # Punch failed for other than currently in use.
+ chomp( $out );
+ $subResp = "Failed, punch info: '$out'";
+ xCAT::zvmUtils->printSyslog( "punch2Reader() Failed punching $srcFile to $userId from $hcp, rc: $rc, out: '$out'" );
+ $done = 1;
+ }
}
- return $out;
+ # If we successfully punched the file, we may have some final steps.
+ if ( $punched == 1 ) {
+ # If a spool class was specified then we punched to the zHCP's reader instead of
+ # punching directly to the target virtual machine and now we need to transfer it
+ # to the target virtual machine. Otherwise, we are done.
+ if ( $spoolClass ne "" ) {
+ # Split the punch response line so we can access the spoolid of the created punch file.
+ # e.g. Reader file with spoolid 0002 created.
+ my @words = split( / /, $out );
+ my $spoolId = $words[4];
+
+ # Change the class of the spool file that we created so that it is the requested class.
+ # We could not spool the punch to the desired class because of the possibility of
+ # multiple threads using the punch that require different classes. Thus, we need to
+ # change the individual punch files.
+ $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo vmcp change rdr $spoolId class $spoolClass" 2>&1`;
+ $rc = $? >> 8;
+ if ( $rc == 255 ) {
+ # SSH failure to communicate with zHCP. Nothing to do, file remains in zHCP's reader.
+ xCAT::zvmUtils->printSyslog( "(Error) In punch2Reader(), SSH communication with $hcp failed for command: vmcp change rdr $spoolId class $spoolClass" );
+ $subResp = "Failed to communicate with the zHCP system to change the reader file $spoolId to class $spoolClass: $hcp";
+ } elsif ( $rc != 0 ) {
+ # Generic failure of transfer command.
+ chomp( $out );
+ xCAT::zvmUtils->printSyslog( "punch2Reader() Change of spool file $spoolId on $hcp to class $spoolClass failed, rc: $rc, out: $out" );
+ $subResp = "Failed, change rdr info rc: $rc, out: '$out'";
+ }
+
+ # If we did not have any errors, then transfer the spoolfile to the targer user's reader.
+ if ( $subResp eq "" ) {
+ $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo vmcp transfer rdr $spoolId to $userId" 2>&1`;
+ $rc = $? >> 8;
+ if ( $rc == 0 ) {
+ # Successful transfer
+ $subResp = "Done";
+ } elsif ( $rc == 255 ) {
+ # SSH failure to communicate with zHCP. Nothing to do, file remains in zHCP's reader.
+ xCAT::zvmUtils->printSyslog( "(Error) In punch2Reader(), SSH communication with $hcp failed for command: vmcp transfer rdr $spoolId to $userId" );
+ $subResp = "Failed to communicate with the zHCP system to transfer reader file $spoolId: $hcp";
+ } else {
+ # Generic failure of transfer command.
+ chomp( $out );
+ xCAT::zvmUtils->printSyslog( "punch2Reader() Transfer of spool file $spoolId from $hcp to $userId failed, rc: $rc, out: $out" );
+ $subResp = "Failed, transfer info rc: $rc, out: '$out'";
+ }
+ }
+
+ # If we had any error then attempt to purge the file from the zHCP machine.
+ if ( $subResp ne "Done" ) {
+ $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo vmcp purge reader $spoolId"`;
+ $rc = $? >> 8;
+ if ( $rc == 255 ) {
+ # SSH failure to communicate with zHCP. Nothing to do, file remains in zHCP's reader.
+ xCAT::zvmUtils->printSyslog( "(Error) In punch2Reader(), SSH communication with $hcp failed for command: vmcp purge reader $spoolId" );
+ $subResp = $subResp. "\nFailed to communicate with the zHCP system to purge reader file $spoolId: $hcp";
+ } elsif ( $rc != 0 ) {
+ # Any failure is bad and unrecoverable.
+ chomp( $out );
+ xCAT::zvmUtils->printSyslog( "punch2Reader() Unable to purge spool file $spoolId on $hcp, rc: $rc, out: $out" );
+ $subResp = $subResp . "\nUnable to purge reader rc: $rc, out: '$out'";
+ }
+ }
+ } else {
+ # Successful punch directly to the target virtual machine.
+ $subResp = "Done";
+ }
+ }
+
+ return $subResp;
}
#-------------------------------------------------------
@@ -643,12 +1067,12 @@ sub punch2Reader {
UserID to purge reader
Returns : Nothing
Example : my $rc = xCAT::zvmCPUtils->purgeReader($hcp, $userId);
-
+
=cut
#-------------------------------------------------------
sub purgeReader {
- my ($class, $user, $hcp, $userId) = @_;
+ my ( $class, $user, $hcp, $userId ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
@@ -662,13 +1086,11 @@ sub purgeReader {
my $out;
if (xCAT::zvmUtils->smapi4xcat($user, $hcp)) {
-
# Use SMAPI EXEC to purge reader
my $cmd = '\"' . "CMD=PURGE $userId RDR ALL" . '\"';
$out = `ssh $user\@$hcp "$sudo $dir/smcli xCAT_Commands_IUO -T $userId -c $cmd"`;
xCAT::zvmUtils->printSyslog("smcli xCAT_Commands_IUO -T $userId -c $cmd");
} else {
-
# Purge reader using CP
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmcp purge $userId rdr all"`;
xCAT::zvmUtils->printSyslog("/sbin/vmcp purge $userId rdr all");
@@ -688,12 +1110,12 @@ sub purgeReader {
UserID to send CP command
Returns : Nothing
Example : xCAT::zvmCPUtils->sendCPCmd($hcp, $userId, $cmd);
-
+
=cut
#-------------------------------------------------------
sub sendCPCmd {
- my ($class, $user, $hcp, $userId, $cmd) = @_;
+ my ( $class, $user, $hcp, $userId, $cmd ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
@@ -707,13 +1129,11 @@ sub sendCPCmd {
my $out;
if (xCAT::zvmUtils->smapi4xcat($user, $hcp)) {
-
# Use SMAPI EXEC to send command
$cmd = '\"' . "CMD=SEND CP $userId " . uc($cmd) . '\"';
$out = `ssh $user\@$hcp "$sudo $dir/smcli xCAT_Commands_IUO -T $userId -c $cmd"`;
xCAT::zvmUtils->printSyslog("smcli xCAT_Commands_IUO -T $userId -c $cmd");
} else {
-
# Send CP command to given user
$out = `ssh $user\@$hcp "$sudo /sbin/vmcp send cp $userId $cmd"`;
xCAT::zvmUtils->printSyslog("/sbin/vmcp send cp $userId $cmd");
@@ -734,13 +1154,14 @@ sub sendCPCmd {
Returns : 2 - Layer 2
3 - Layer 3
-1 - Failed to get network layer
+ error string if SSH fails
Example : my $layer = xCAT::zvmCPUtils->getNetworkLayer($node);
-
+
=cut
#-------------------------------------------------------
sub getNetworkLayer {
- my ($class, $user, $node, $netName) = @_;
+ my ( $class, $user, $node, $netName ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -748,23 +1169,28 @@ sub getNetworkLayer {
}
# Exit if the network name is not given
- if (!$netName) {
+ if ( !$netName ) {
return -1;
}
# Get network type (Layer 2 or 3)
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q lan $netName"`;
- if (!$out) {
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q lan $netName"`;
+ my $cmd = "$sudo /sbin/vmcp q lan $netName";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput($out) == -1) {
+ return $out;
+ }
+ if ( !$out ) {
return -1;
}
# Go through each line
- my $layer = 3; # Default to layer 3
- my @lines = split('\n', $out);
+ my $layer = 3; # Default to layer 3
+ my @lines = split( '\n', $out );
foreach (@lines) {
# If the line contains ETHERNET, then it is a layer 2 network
- if ($_ =~ m/ETHERNET/i) {
+ if ( $_ =~ m/ETHERNET/i ) {
$layer = 2;
}
}
@@ -780,14 +1206,14 @@ sub getNetworkLayer {
Arguments : User (root or non-root)
zHCP
Name of network
- Returns : Network type (VSWITCH/HIPERS/QDIO)
+ Returns : Network type (VSWITCH/HIPERS/QDIO) or string containing (Error)...
Example : my $netType = xCAT::zvmCPUtils->getNetworkType($hcp, $netName);
-
+
=cut
#-------------------------------------------------------
sub getNetworkType {
- my ($class, $user, $hcp, $netName) = @_;
+ my ( $class, $user, $hcp, $netName ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -795,25 +1221,33 @@ sub getNetworkType {
}
# Get network details
- my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmcp q lan $netName" | grep "Type"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmcp q lan $netName"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo /sbin/vmcp q lan $netName\"", $hcp, "getNetworkType", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+
+ $out = `echo "$out" | egrep -a 'Type'`;
# Go through each line and determine network type
- my @lines = split('\n', $out);
+ my @lines = split( '\n', $out );
my $netType = "";
foreach (@lines) {
# Virtual switch
- if ($_ =~ m/VSWITCH/i) {
+ if ( $_ =~ m/VSWITCH/i ) {
$netType = "VSWITCH";
}
# HiperSocket guest LAN
- elsif ($_ =~ m/HIPERS/i) {
+ elsif ( $_ =~ m/HIPERS/i ) {
$netType = "HIPERS";
}
# QDIO guest LAN
- elsif ($_ =~ m/QDIO/i) {
+ elsif ( $_ =~ m/QDIO/i ) {
$netType = "QDIO";
}
}
@@ -828,16 +1262,16 @@ sub getNetworkType {
Description : Add processor(s) to given node
Arguments : User (root or non-root)
Node
- Returns : Nothing
+ Returns : Nothing or error string if failure
Example : my $out = xCAT::zvmCPUtils->defineCpu($node, $addr, $type);
-
+
=cut
#-------------------------------------------------------
sub defineCpu {
# Get inputs
- my ($class, $user, $node, $addr, $type) = @_;
+ my ( $class, $user, $node, $addr, $type ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -845,7 +1279,34 @@ sub defineCpu {
}
# Define processor(s)
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp define cpu $addr type $type"`;
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp define cpu $addr type $type"`;
+ my $cmd = "$sudo /sbin/vmcp define cpu $addr type $type";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
return ($out);
}
+
+#-------------------------------------------------------
+
+=head3 getIplTime
+
+ Description : Get the IPL time
+ Arguments : User (root or non-root)
+ zHCP
+ Returns : IPL time
+ Example : my $out = xCAT::zvmCPUtils->getIplTime($user, $hcp);
+
+=cut
+
+#-------------------------------------------------------
+sub getIplTime {
+ my ($class, $user, $hcp) = @_;
+
+ my $sudo = "sudo";
+ if ($user eq "root") {
+ $sudo = "";
+ }
+
+ my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmcp q cplevel"`;
+ return ((split("\n", $out))[2]);
+}
diff --git a/perl-xCAT/xCAT/zvmMsgs.pm b/perl-xCAT/xCAT/zvmMsgs.pm
new file mode 100644
index 000000000..6544f941a
--- /dev/null
+++ b/perl-xCAT/xCAT/zvmMsgs.pm
@@ -0,0 +1,1410 @@
+# IBM(c) 2016 EPL license http://www.eclipse.org/legal/epl-v10.html
+#-------------------------------------------------------
+
+=head1
+
+ This is a message utility plugin for z/VM.
+
+=cut
+
+#-------------------------------------------------------
+package xCAT::zvmMsgs;
+use Text::Wrap;
+use strict;
+use warnings;
+1;
+
+
+# Messages
+# Severity strings
+my @sevInfo = ( '', # No header
+ 'Bypassing test', # Bypassing message
+ 'Info', # Information message
+ 'unknown', # Unknown severity
+ 'Warning', # Warning message
+ 'Error' # Error message
+ );
+
+# Hash of message ids. Message ids should be in uppercase. 'ALL' should not
+# be used as a message id as this indicates that all messages are wanted.
+# For each message id there is another hash with additional info:
+# severity - Severity of message and indicate whether it gets a header to the
+# message text (e.g. "Error (IVP:MAINT01) " )
+# 0 - no message header, unrated output
+# 1 - bypass message used by automated tests
+# 2 - information message with "Info" header
+# 3 - unknown message severity
+# 4 - warning message with "Warning" header
+# 5 - error message with "Error" header
+# recAction - Recommended action:
+# 0 - non-fatal message, continue processing
+# 1 - fatal message, end further processing
+# explain - Further explanation of the message.
+# subTab - (optional) Indicates the tabbing characters to use. This is
+# used to control whether subsequent lines of a message are
+# indented. The default is '\t', to indent the lines.
+# sysAct - System action to be performed. Normally, this is not specified
+# because the severity generates a default system action.
+# userResp - Suggested user response.
+
+#******************************************************************************
+# verifynode messages
+#******************************************************************************
+my %verifyMsgs = (
+ 'FATAL_DEFAULTS' =>
+ {
+ 'sysAct' => 'No further verification will be performed.'
+ },
+ 'NONFATAL_DEFAULTS' =>
+ {
+ 'sysAct' => 'Verification continues.'
+ },
+ 'GENERIC_RESPONSE' =>
+ { 'severity' => 0,
+ 'recAction' => 0,
+ 'text' => '%s',
+ },
+ 'GENERIC_RESPONSE_NOINDENT' =>
+ { 'severity' => 0,
+ 'recAction' => 0,
+ 'text' => '%s',
+ 'subTab' => '',
+ },
+ 'CLNUP01' =>
+ { 'severity' => 5,
+ 'recAction' => 0,
+ 'text' => 'Unable to remove the temporary directory, %s, from the'.
+ 'from the compute node system at %s. '.
+ 'The following command failed: %s with rc: %s, out: %s',
+ 'explain' => 'The IVP created a temporary directory on the target system. '.
+ 'It was unable to remove the directory when it was finished with it. '.
+ 'The message indicate the command, return code and output of the command.',
+ 'userResp' => 'Determine the cause of the error and correct it, if possible. You may want '.
+ 'to access the system and remove the directory.',
+ },
+ 'DFLT01' =>
+ { 'severity' => 2,
+ 'recAction' => 0,
+ 'text' => '%s so the function will use \'%s\' as the default value. %s',
+ 'explain' => 'A value was not specified so the function will use the indicated default.',
+ 'userResp' => 'You can specify the missing value in order to avoid this message in the future. ' .
+ 'If the value is acceptable then you can ingnore this message.',
+ },
+ 'DRIV01' =>
+ { 'severity' => 5,
+ 'recAction' => 1,
+ 'text' => 'The driver script, %s, failed, rc: %s, out: %s',
+ 'explain' => 'The driver script failed with the indicated return code and output. '.
+ 'The IVP is unable to run the full installation verification test.',
+ 'sysAct' => 'IVP processing stops.',
+ 'userResp' => 'Determine the cause of the error and correct the error. Run the IVP after '.
+ 'you have corrected the error. Otherwise, consult the support team.',
+ },
+ 'DRIV02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The driver script, %s, did not specify the z/VM host node information in the %s property',
+ 'explain' => 'The driver script did not specify the z/VM host node property. '.
+ 'The IVP will default to notifying the user on the system where the '.
+ 'xCAT management node runs.',
+ 'userResp' => 'Determine why the property was not defined in OpenStack and correct the error. Run the IVP after '.
+ 'you have corrected the error. Otherwise, consult the support team.',
+ },
+ 'DRIV03' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The ZHCP agent related to the host, \'%s\', could not be determined from the xCAT node information.',
+ 'explain' => 'The driver script specified a z/VM host. However, the IVP was not able to determine the ZHCP '.
+ 'agent associated with the host.',
+ 'sysAct' => 'IVP processing continues. The IVP will attempt to determine the ZHCP agent using some other information.',
+ 'userResp' => 'Verify that the host node in xCAT has an hcp property and that hosttype is \'zvm\'. '.
+ 'Run the IVP after you have corected the error.',
+ },
+ 'GNRL01' =>
+ { 'severity' => 5,
+ 'recAction' => 0,
+ 'text' => 'An unexpected command failure occurred, cmd: \'%s\', rc: %s, out: %s',
+ 'explain' => 'An unexpected failure was encountered during processing. The command that '.
+ 'failed is shown along with the return code and output of the command.',
+ 'sysAct' => 'This failure will cause some processing to be bypassed but the IVP run will continue.',
+ 'userResp' => 'Determine the cause of the error and correct the error. Run the IVP after '.
+ 'you have corrected the error. Otherwise, consult the support team.',
+ },
+ 'GNRL02' =>
+ { 'severity' => 5,
+ 'recAction' => 0,
+ 'text' => 'An error occurred attempting to punch \'%s\' from %s to user %s on %s. '.
+ 'The file remains on the source system as \'%s\'. Output from the punch invocation: %s',
+ 'explain' => 'An unexpected failure occurred while attempting to punch a file.',
+ 'sysAct' => 'An attempt will be made to remove the file but this may fail. '.
+ 'The IVP will try to send the file to an alternate user and will indicate if this was successful. '.
+ 'This failure may prevent the IVP from sending the log file to the notify user on the target system.',
+ 'userResp' => 'The original log file exists on the xCAT management node in the /var/log/xcat/ivp directory. '.
+ 'You may access it on that system if you did not receive the file on an alternate userid and system.',
+ },
+ 'GNRL04' =>
+ { 'severity' => 5,
+ 'recAction' => 1,
+ 'text' => 'An unexpected command failure occurred, cmd: \'%s\', rc: %s, out: %s',
+ 'explain' => 'An unexpected failure was encountered during processing. The command that '.
+ 'failed is shown along with the return code and output of the command.',
+ 'sysAct' => 'Processing terminates.',
+ 'userResp' => 'Determine the cause of the error and correct the error. Run the command again after '.
+ 'you have corrected the error. Otherwise, consult the support team.',
+ },
+ 'GOSL01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The command \'%s\' was sent to %s to determine the OpenStack level but '.
+ 'did not return an expected response. Instead it returned rc: %s and out: %s.',
+ 'explain' => 'The value returned by the command was not an expected value. '.
+ 'This is expected to be a single word, e.g. \'14.0.2\', with the '.
+ 'components of the version separated by a period. There should be '.
+ 'at least two components.',
+ 'userResp' => 'Determine the reason that the OpenStack level is not a recognized value. '.
+ 'Run the command again after you have corrected the error. '.
+ 'Otherwise, consult the support team.',
+ },
+ 'GOSL02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The command \'%s\' was sent to %s to determine the OpenStack level but '.
+ 'did not return one of the recognized versions. '.
+ 'Instead, it returned rc: %s and out: %s.',
+ 'explain' => 'The value returned by the command was not an expected value. '.
+ 'The expected values are listed in /opt/xcat/openstack.versions.',
+ 'userResp' => 'Determine the reason that the OpenStack level is not a recognized value. '.
+ 'Run the command again after you have corrected the error. '.
+ 'Otherwise, consult the support team.',
+ },
+ 'ID01' =>
+ { 'severity' => 5,
+ 'recAction' => 1,
+ 'text' => 'The system attempted to generate a unique IVP id but failed to do so after 10000 attempts.',
+ 'explain' => 'An IVP id was not specified so the system attempted to generate a unique IVP id. '.
+ 'This begins with an id of 10 and increments by 1 upto 10010. Unfortunately, '.
+ 'a unique unused Id was not found in the zvmivp table. You may have a corrupted '.
+ 'zvmivp table or have somehow filled the table with 10000 IVPs which is highly abnormal.',
+ 'sysAct' => 'Processing terminates.',
+ 'userResp' => 'Determine the cause of the error and correct the error. Run the command again after '.
+ 'you have corrected the error. Otherwise, consult the support team.',
+ },
+ 'ID02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The IVP id, %s, does not exist. A new IVP will be scheduled using that id.',
+ 'explain' => 'The specified IVP id was not found in the zvmivp table.',
+ 'sysAct' => 'Processing continues and a new IVP will be added to the table of scheduled IVPs using the '.
+ 'specified id.',
+ 'userResp' => 'If you incorrectly specified the IVP id and did not want to add a new ID, then you should '.
+ 'remove the IVP that you do not want. '.
+ 'From the xCAT GUI, go to Help->Verify xCAT to remove the IVP.',
+ },
+ 'ID03' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The IVP id does not exist in the zvmivp table: %s',
+ 'explain' => 'The specified IVP id was not found in the zvmivp table.',
+ 'sysAct' => 'Processing terminates.',
+ 'userResp' => 'Specify the correct id and retry.',
+ },
+ 'MN01' =>
+ { 'severity' => 2,
+ 'recAction' => 0,
+ 'text' => 'Could not find an xCAT management node which had an IP address of %s, cmd: \'%s\', rc: %s, out: %s',
+ 'explain' => 'An xCAT node that represents the xCAT management node could not be found. '.
+ 'The xCAT management node is not required by the IVP but some processing '.
+ 'such as default notification of the z/VM host on which the xCAT management '.
+ 'node runs will not occur.',
+ 'userResp' => 'If you expected the xCAT management node to exist, please review the '.
+ 'command that was issued and the return code and output to determine '.
+ 'why the xCAT management node was not found and correct the issue. '.
+ 'Run the IVP or other command that you issuedd after you have corrected the issue.',
+ },
+ 'MN02' =>
+ { 'severity' => 2,
+ 'recAction' => 0,
+ 'text' => 'The xCAT management node is not defined as a node in xCAT and the function will not '.
+ 'be performed.',
+ 'explain' => 'The issued command requires the existence of the xCAT MN as an xCAT node. '.
+ 'The requrested processing cannot be performed.',
+ 'sysAct' => 'Processing terminates.',
+ 'userResp' => 'Determine the cause of the error and correct the error.',
+ },
+ 'MN03' =>
+ { 'severity' => 2,
+ 'recAction' => 0,
+ 'text' => 'The xCAT management node is not defined as a node so only a basic IVP will be run.',
+ 'explain' => 'The xCAT MN should exist as an xCAT node. The failure to find the node indicates '.
+ 'a larger failure. An automated IVP will be performed to verify the general '.
+ 'functioning of the environment but it will not be added to the zvmivp table. '.
+ 'We expect the installation to define the xCAT node upon seeing this message '.
+ 'and that will allow the automated IVP to create default IVPs in the zvmivp table.',
+ 'sysAct' => 'Processing continues.',
+ 'userResp' => 'Define the xCAT management node in xCAT.',
+ },
+ 'MSG01' =>
+ { 'severity' => 2,
+ 'recAction' => 0,
+ 'text' => '%s on %s is unable to receive messages at this time, status: \'%s\'. '.
+ 'They will not be sent the IVP results message.',
+ 'explain' => 'The IVP attempted to send a message to the user on the target system '.
+ 'to notify them of the status of the IVP run. The user was '.
+ 'unavailable to receive the message. '.
+ 'Status of \'SSI\' indicates they are logged on another system in the SSI '.
+ 'cluster while \'DSC\' indicates the machine is running disconnected. '.
+ 'The userid is defined by the XCAT_notify property in the '.
+ 'DMSSICNF COPY file or the zvmnotify property in the xCAT site table.',
+ 'sysAct' => 'Processing continues. The log file from the run was '.
+ 'sent to the userid as a spool file.',
+ 'userResp' => 'If the userid is not the userid that you expected to receive the '.
+ 'IVP status message then correct the XCAT_notify property in '.
+ 'the DMSSICNF COPY file and recycle SMAPI to pick up the new value or '.
+ 'as a temporary measure until the next recycle of SMAPI, update the '.
+ 'zvmnotify property in the xCAT site table.',
+ },
+ 'OPER01' =>
+ { 'severity' => 5,
+ 'recAction' => 1,
+ 'text' => 'Required operand %s is missing.',
+ 'explain' => 'The indicated operand is required but missing.',
+ 'sysAct' => 'Processing terminates.',
+ 'userResp' => 'Specify the command with the required operand.',
+ },
+ 'OPER02' =>
+ { 'severity' => 5,
+ 'recAction' => 1,
+ 'text' => 'Operand %s has a value of \'%s\' which is not one of the recognized values: %s.',
+ 'explain' => 'The value for the operand is not recognized.',
+ 'sysAct' => 'Processing terminates.',
+ 'userResp' => 'Specify the command with the correct operand value.',
+ },
+ 'OPER03' =>
+ { 'severity' => 5,
+ 'recAction' => 1,
+ 'text' => 'Conflicting operands were specified: %s.',
+ 'sysAct' => 'Processing terminates.',
+ 'userResp' => 'Specify the command with the correct operand value.',
+ },
+ 'PERL01' =>
+ { 'severity' => 4,
+ 'recAction' => 1,
+ 'text' => 'A perl script error was detected in %s.\n'.
+ ' Calling parms: %s\n'.
+ ' Reason: %s',
+ 'explain' => 'The indicated perl script encountered a perl scripting error '.
+ 'that prevents it from operating correctly. The script is '.
+ 'ending the current run. This error message is a restatement of '.
+ 'a previous message so that you are ensured to see the error.',
+ 'userResp' => 'Review the previous messages to determine whether the error '.
+ 'is caused by bad invocation parameters or an error within '.
+ 'the script. Please report this problem if it is not caused '.
+ 'by a user error.',
+ },
+ 'PREP01' =>
+ { 'severity' => 5,
+ 'recAction' => 1,
+ 'text' => 'Unable to create the %s directory in the system running the xCAT management node. rc: %s, out: %s',
+ 'explain' => 'The specified directory is used to contain the driver script created '.
+ 'by the IVP preparation script. This directory exists in the virtual '.
+ 'server that runs the xCAT management node. The directory '.
+ 'could not be created.'.
+ 'The current OpenStack properties cannot be validated. '.
+ 'A saved version of the driver script from a previous run will be used, if it exists.',
+ 'userResp' => 'Determine the cause of the error. It could be caused by running the '.
+ 'verifynode script under a user that does not have root authority. '.
+ 'If you cannot correct the problem then you can download the IVP preparation script '.
+ 'to the target system and run it as discussed in the Enabling z/VM for OpenStack manual. '.
+ 'The driver script may then be uploaded to the xCAT management node system and '.
+ 'moved to the indicated location so that it can be used in a subsequent IVP.',
+ },
+ 'PREP02' =>
+ { 'severity' => 5,
+ 'recAction' => 0,
+ 'text' => 'Unable to send the IVP preparation script, %s, to the OpenStack system at %s. '.
+ 'The script was intended to be used to create a driver script for the IVP '.
+ 'on the system running the xCAT management node at %s. '.
+ 'A previous version of the driver script will be used. '.
+ 'The following command failed: %s with rc: %s, out: %s',
+ 'explain' => 'The xCAT Management Node was unable to send the IVP preparation script to the '.
+ 'specified system in order to analyze the OpenStack properties and '.
+ 'construct the driver script for the next phase of the IVP. The command failed '.
+ 'with the indicated return code and output. '.
+ 'The current OpenStack properties cannot be validated. '.
+ 'A saved version of the driver script from a previous run will be used, if it exists.',
+ 'userResp' => 'Determine the cause of the error and correct it, if possible.'.
+ 'If you cannot correct the problem then you can download the IVP preparation script '.
+ 'to the target system and run it as discussed in the Enabling z/VM for OpenStack manual. '.
+ 'The driver script may then be uploaded to the xCAT management node system and '.
+ 'moved to the indicated location so that it can be used in a subsequent IVP.',
+ },
+ 'PREP04' =>
+ { 'severity' => 5,
+ 'recAction' => 0,
+ 'text' => 'Unable to retrieve the driver script created by the IVP preparation script, %s, '.
+ 'from the OpenStack system at %s. '.
+ 'The driver script was intended to be used to drive the IVP '.
+ 'on the system running the xCAT management node at %s. '.
+ 'The following command failed: %s with rc: %s, out: %s',
+ 'explain' => 'The xCAT Management Node was unable to retrieve the driver script from the '.
+ 'specified system for the next phase of the IVP. '.
+ 'A saved version of the driver script from a previous run will be used, it it exists.',
+ 'userResp' => 'Determine the cause of the error and correct it, if possible. '.
+ 'If you cannot correct the problem then you can download the IVP preparation script '.
+ 'to the target system and run it as discussed in the Enabling z/VM for OpenStack manual. '.
+ 'The driver script may then be uploaded to the xCAT management node system and '.
+ 'moved to the indicated location so that it can be used in a subsequent IVP.',
+ },
+ 'PREP06' =>
+ { 'severity' => 5,
+ 'recAction' => 1,
+ 'text' => 'Unable to determine the OpenStack level of the OpenStack system at %s. '.
+ 'The full IVP cannot be run.',
+ 'explain' => 'The xCAT Management Node was unable to level of OpenStack running the in the indicated system. '.
+ 'This is necessary so that the correct level of analysis code can be run '.
+ 'to validate the system. '.
+ 'A saved version of the driver script from a previous run will be used, if it exists.',
+ 'userResp' => 'Determine the cause of the error and correct it, if possible. If OpenStack '.
+ 'Nova services are not actively running on the system then please start them '.
+ 'and reattempt the IVP.'.
+ 'If you cannot correct the problem then you can download the IVP preparation script '.
+ 'to the target system and run it as discussed in the Enabling z/VM for OpenStack manual. '.
+ 'The driver script may then be uploaded to the xCAT management node system and '.
+ 'moved to the indicated location so that it can be used in a subsequent IVP.',
+ },
+ 'PREP07' =>
+ { 'severity' => 5,
+ 'recAction' => 0,
+ 'text' => 'Unable to reduce the file permissions on %s with command: %s,\nrc: %s, out: %s',
+ 'explain' => 'The xCAT Management Node was unable to lower the file permission on the indicated file.',
+ 'userResp' => 'Determine the cause of the error and correct it, if possible. You may want to change the '.
+ 'permissions on the file.',
+ },
+ 'SITE01' =>
+ { 'severity' => 5,
+ 'recAction' => 0,
+ 'text' => 'The \'%s\' property from the site table has a value that is not valid. Value: \'%s\', '.
+ 'bad portion of the value: \'%s\'',
+ 'explain' => 'The site table contains a property that is used in the IVP processing. The value '.
+ 'of the property has the following format:'.
+ "\n".
+ 'zvmnotify: \'hostnode(userid_on_the_host)\' If additional host/userid combinations are specified '.
+ 'then they are connected by a semicolon and no blanks are allowed between the '.
+ 'components that make up the value. '.
+ 'For example, \'host1(usera);host2(userb)\'',
+ 'userResp' => 'Correct the error and rerun the IVP. Otherwise, consult the support team.',
+ },
+ 'SITE02' =>
+ { 'severity' => 5,
+ 'recAction' => 0,
+ 'text' => 'The \'%s\' property from the site table is missing or has an empty string value.',
+ 'explain' => 'The site table contains a property that is used in the IVP processing. The property '.
+ 'is missing from the table or has a value that is an empty string. The \'master\' '.
+ 'property should specify the IP address of the xCAT management node that matches the value '.
+ 'specified for the \'ip\' property of the node that represents the xCAT management node.',
+ 'userResp' => 'Correctly specify the master property in the site table and rerun the IVP. '.
+ 'Otherwise, consult the support team.',
+ },
+ 'VSTN01' =>
+ { 'severity' => 4,
+ 'recAction' => 1,
+ 'text' => 'Unable to SSH to %s.',
+ 'explain' => 'The xCAT management node uses SSH to obtain information '.
+ 'from the target system or to make changes within Linux on the '.
+ 'target system. This does not appear to be working. '.
+ 'This may be due to the system not being unlocked to the xCAT management node for '.
+ 'communication or a TCP/IP error.',
+ 'sysAct' => 'The system action depends upon the severity of the problem. '.
+ 'It will attempt to continue, if possible.',
+ 'userResp' => 'First, attempt to unlock the target system from the xCAT GUI by selecting the ' .
+ 'node on the Nodes->Nodes panel and choosing \'unlock\' in ' .
+ 'the \'Configuration\' pulldown. If that does not work then investigate '.
+ 'TCP/IP errors or network configuration errors within the target system.',
+ },
+ 'TP01' =>
+ { 'severity' => 5,
+ 'recAction' => 0,
+ 'text' => 'The \'%s\' property from the %s table is %s: \'%s\'. A default of \'%s\' will be used instead of that property.',
+ 'explain' => 'A property in the indicated table has a value that is not valid. '.
+ 'The default will be used instead. ',
+ 'userResp' => 'Correctly specify the property in the table.',
+ },
+ 'VA01' =>
+ { 'severity' => 4,
+ 'recAction' => 1,
+ 'text' => 'xCAT MN is unable to issue a simple \'pwd\' command on the target system.',
+ 'explain' => 'The xCAT management node uses SSH to obtain information '.
+ 'from the target system or to make changes within Linux on the '.
+ 'target system. The xCAT MN can access the system but is unable to issue '.
+ 'a simple command.',
+ 'userResp' => 'Unlock the target node from the xCAT GUI by selecting the ' .
+ 'node on the Nodes->Nodes panel and choosing \'unlock\' in ' .
+ 'the \'Configuration\' pulldown. If this does not work then log onto the '.
+ 'virtual machine to see why simple commands are failing.',
+ },
+ 'VD01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => '%s is not a version supported by xCAT.',
+ 'explain' => 'The Linux distribution name and version was compared to the list of '.
+ 'versions that xCAT supports and was not found in the list.',
+ 'sysAct' => 'Some xCAT functions may be unavailable such as image capture and deploy '.
+ 'or work incorrectly.',
+ 'userResp' => 'Either update the OS running in the target node or monitor the xCAT ' .
+ 'responses to commands directed to the node to ensure that it is doing '.
+ 'what you desire.',
+ },
+ 'VPF01' =>
+ { 'severity' => 4,
+ 'recAction' => 1,
+ 'text' => 'Unable to determine the power status of %s, rpower rc: %s, msg: %s',
+ 'explain' => 'An xCAT rpower command with the stat option was issued to determine '.
+ 'the power status of the specified node and returned a non-zero return code.',
+ 'userResp' => 'The return code and the message returned by rpower (shown in the message '.
+ 'after msg:) should be used to determine the cause of the error. '.
+ 'Please correct the error and retry the test.',
+ },
+ 'VP02' =>
+ { 'severity' => 4,
+ 'recAction' => 1,
+ 'text' => '%s is not logged on.',
+ 'explain' => 'The virtual machine related to the node is not currently logged on.',
+ 'userResp' => 'Log the virtual machine on to the z/VM host and retry the verification.',
+ },
+ 'VS05' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Linux is not configured for the service: %s.',
+ 'explain' => 'The specified service should be configured on the target system. '.
+ 'This ensures that images '.
+ 'captured from this system will have the service started when the '.
+ 'new system boots to allow xCAT and/or OpenStack to complete the configuration of the '.
+ 'system the first time it boots.',
+ 'userResp' => 'Configure Linux to start service on boot of the server.'
+ },
+ 'VS06' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The %s service is not configured for the following run levels: %s',
+ 'explain' => 'The specified service should be configured on the target '.
+ 'system for the specified run levels. This ensures that images '.
+ 'captured from this system will have the service started when the '.
+ 'new system boots to allow xCAT and/or OpenStack to complete the configuration of the '.
+ 'system the first time it boots.',
+ 'userResp' => 'Configure the service to be \'on\' for indicated run levels.'
+ },
+ 'VX01' =>
+ { 'severity' => 4,
+ 'recAction' => 1,
+ 'text' => 'Unable to determine the version number of the xcatconf4z that is shipped in the xCAT MN.',
+ 'explain' => 'The verification code runs xcatconf4z with the \'version\' operand ' .
+ 'on the target node. The script did not return a version string. ' .
+ 'This normally indicates that xcatconf4z is a very early version.',
+ 'userResp' => 'xcatconf4z should be updated to the latest level.',
+ },
+ 'VX02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'xcatconf4z on the system is back level. Unable to determine the version installed.',
+ 'explain' => 'xcatconf4z exists on the system but is very old and does not respond to the version query.',
+ 'userResp' => 'xcatconf4z should be updated to the latest level.',
+ },
+ 'VX03' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'xcatconf4z on the system is back level at %s. It should be at %s.',
+ 'explain' => 'The xcatconf4z on that target node is compared to the one shipped with ' .
+ 'the xCAT MN. The xcatconf4z should be at the same level as the one ' .
+ 'on xCAT MN or at a later level.',
+ 'userResp' => 'xcatconf4z should be updated to the latest level.'
+ },
+ 'VX04' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'xcatconf4z is not set up to receive configuration directive files from its reader.',
+ 'explain' => 'The xcatconf4z script reads configuration directives sent as reader files to it ' .
+ 'from authorized userids. The script contains a variable, authorized_senders, that ' .
+ 'lists the names of authorized virtual machines.',
+ 'userResp' => 'Configure the authorized_senders variable in the script to contain the userids '.
+ 'of ZHCP virtual machines that will send configuration directives to this node or '.
+ 'to images create from this node.'
+ },
+ 'VX05' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Linux is not setup to start xcatconf4z on boot.',
+ 'explain' => 'The xcatconf4z script should be configured on the target '.
+ 'system to start when the system boots. This ensures that images '.
+ 'captured from this system will have the service started when the '.
+ 'new system boots to allow xCAT to complete the configuration of the '.
+ 'system the first time it boots.',
+ 'userResp' => 'Configure Linux to start xcatconf4z on boot of the server.'
+ },
+ 'VX06' =>
+ { 'severity' => 4,
+ 'recAction'=> 1,
+ 'text' => 'xcatconf4z was not found in the /opt directory on the target node.',
+ 'explain' => 'The xcatconf4z script should exist in the /opt directory on the target node.',
+ 'userResp' => 'Obtain xcatconf4z and put it in the /opt directory on the target node.'
+ },
+ 'VX07' =>
+ { 'severity' => 4,
+ 'recAction'=> 0,
+ 'text' => '/opt/bin/mkisofs was not found on the target system.',
+ 'explain' => 'The xcatconf4z script invokes the /opt/bin/mkisofs to create ' .
+ 'an ISO9660 disk in which it stores configuration '.
+ 'data used by the activation engine. The mkisofs file is missing '.
+ 'and will prevent proper operation of the xcatconf4z script during '.
+ 'deploy of an image.',
+ 'userResp' => 'This function should be obtained from the Linux distribution and '.
+ 'installed.'
+ },
+ 'WAIT01' =>
+ { 'severity' => 2,
+ 'recAction' => 0,
+ 'text' => 'Sleeping %s seconds to allow xcatd to start. Wait %s of %s.',
+ 'explain' => 'The xCAT daemon (xcatd) is not running.',
+ 'sysAct' => 'The process will wait the indicated time and then recheck the status. '.
+ 'If the xCAT daemon does not start after a number of attempts then the '.
+ 'process will stop waiting. A subsequent attempt to use xCAT daemon '.
+ 'functions is expected to fail and will log the problem.',
+ 'userResp' => 'It may take a short while for the xCAT daemon to start up or resume '.
+ 'after a restart. A delay should not be considered a problem unless '.
+ 'the xCAT daemon does not start up.'
+ },
+ );
+
+#******************************************************************************
+# zxcatIVP messages
+#******************************************************************************
+my %zxcativpMsgs = (
+ 'FATAL_DEFAULTS' =>
+ {
+ 'sysAct' => 'No further verification will be performed.'
+ },
+ 'NONFATAL_DEFAULTS' =>
+ {
+ 'sysAct' => 'Verification continues.'
+ },
+ 'GENERIC_RESPONSE' =>
+ { 'severity' => 0,
+ 'recAction' => 0,
+ 'text' => '%s',
+ },
+ 'GENERIC_RESPONSE_NOINDENT' =>
+ { 'severity' => 0,
+ 'recAction' => 0,
+ 'text' => '%s',
+ 'subTab' => '',
+ },
+ 'BPVMN01' =>
+ { 'severity' => 1,
+ 'recAction' => 0,
+ 'text' => 'The node id for the xCAT MN was not specified, so the IVP will not verify that it exists.',
+ 'explain' => 'The node name of the xCAT MN is a configuration property, zvm_xcat_master '.
+ 'in /etc/nova/nova.conf file, that is used by z/VM OpenStack plugin code. '.
+ 'The driver script created by the IVP preparation script normally passes this value '.
+ 'in the zxcatIVP_mnNode environment variable. '.
+ 'The IVP perform tests related to the value. This bypass message is '.
+ 'expected when the IVP is driven directly without a driver script; for '.
+ 'example, in basic test mode but is not expected when a full IVP is run.',
+ 'sysAct' => 'Some tests which use the node name of the xCAT MN will not be run.',
+ 'userResp' => 'If you did not run the preparation script to create a driver script, then '.
+ 'consider doing so and rerunning the test with the driver script. '.
+ 'If you intended to run the basic IVP which is run without a driver script '.
+ 'then you can ignore this message.'
+ },
+ 'BPVDP01' =>
+ { 'severity' => 1,
+ 'recAction' => 0,
+ 'text' => 'Disk pool names were not specified, so IVP will verify the pools associated with each host.',
+ 'explain' => 'Directory manager disk pools are used for obtaining OpenStack ephemeral '.
+ 'disks. The zvm_diskpool property in /etc/nova/nova.conf file specifies the disk pools. '.
+ 'The driver script created by the IVP preparation script normally passes this value '.
+ 'in the zxcatIVP_diskpools environment variable. '.
+ 'The IVP perform tests related to the value. This bypass message is '.
+ 'expected when the IVP is driven directly without a driver script; for '.
+ 'example, in basic test mode but is not expected when a full IVP is run.',
+ 'userResp' => 'If you did not run the preparation script to create a driver script, then '.
+ 'consider doing so and rerunning the test with the driver script. '.
+ 'If you intended to run the basic IVP which is run without a driver script '.
+ 'then you can ignore this message.'
+ },
+ 'BPVDS01' =>
+ { 'severity' => 1,
+ 'recAction' => 0,
+ 'text' => 'Directory space tests related to ZHCP agent will not be run.',
+ 'explain' => 'The IVP detected that the ZHCP agent is on the same system as the xCAT management node. ' .
+ 'The space related tests would have already be run for the xCAT MN so similar tests ' .
+ 'will not be run for the ZHCP agent.',
+ 'userResp' => 'If you want to verify additional directories for the ZHCP running on the xCAT MN\'s system '.
+ 'then specify the directory information as part of the xcatDiskSpace command line operand or ' .
+ 'zxcatIVP_xcatDiskSpace environment variable. Please remember to include directories '.
+ 'that are defaults for the xCAT MN\'s directory space tests. You can see the defaults in the ' .
+ 'help output for zxcatIVP.'
+ },
+ 'BPVN01' =>
+ { 'severity' => 1,
+ 'recAction' => 0,
+ 'text' => 'Networks were not specified, so IVP will not verify them.',
+ 'explain' => 'Virtual switches are used for internet access by the deployed '.
+ 'virtual servers. The flat_networks property in section ml2_type_flat '.
+ 'and the network_vlan_ranges property in section ml2_type_vlan '.
+ 'in the /etc/neutron/plugins/ml2/ml2_conf.ini file specify the vswitches. '.
+ 'The driver script created by the IVP preparation script normally passes this value '.
+ 'in the zxcatIVP_networks environment variable. '.
+ 'The IVP perform tests related to the value. This bypass message is '.
+ 'expected when the IVP is driven directly without a driver script; for '.
+ 'example, in basic test mode but is not expected when a full IVP is run.',
+ 'userResp' => 'If you did not run the preparation script to create a driver script, then '.
+ 'consider doing so and rerunning the test with the driver script. '.
+ 'If you intended to run the basic IVP which is run without a driver script '.
+ 'then you can ignore this message.'
+ },
+ 'BPVCNC01' =>
+ { 'severity' => 1,
+ 'recAction' => 0,
+ 'text' => 'Compute Node address or export user was not specified, so the IVP will '.
+ 'not verify that the xCAT MN can communicate with the compute node.',
+ 'explain' => 'The address of the virtual server where the nova compute services '.
+ 'are running is configured in the '.
+ 'my_ip property in the /etc/nova/nova.conf file. The driver script '.
+ 'created by the IVP preparation script normally passes this value '.
+ 'in the zxcatIVP_cNAddress environment variable. '.
+ "\n\n".
+ 'The export user is normally set to \'nova\' by the IVP preparation script '.
+ 'and is passed in the zxcatIVP_expUser environment variable.'.
+ 'The IVP will perform tests related to these values. This bypass message is '.
+ 'expected when the IVP is driven directly without a driver script; for '.
+ 'example, in basic test mode but is not expected when a full IVP is run.',
+ 'userResp' => 'If you did not run the preparation script to create a driver script, then '.
+ 'consider doing so and rerunning the test with the driver script. '.
+ 'If you intended to run the basic IVP which is run without a driver script '.
+ 'then you can ignore this message.',
+ },
+ 'MAIN01' =>
+ { 'severity' => 4,
+ 'recAction' => 1,
+ 'text' => 'Significant error detected, no further verification will be performed.',
+ 'explain' => 'A significant warning was detected, which prevents further tests '.
+ 'from accurately validating the system.',
+ 'sysAct' => 'No further verification will be performed for this run.',
+ 'userResp' => 'You should correct the situation indicated by previous warning '.
+ 'messages and then rerun the IVP.',
+ },
+ 'STN01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Unable to SSH to %s.',
+ 'explain' => 'The xCAT management node uses SSH to obtain information '.
+ 'from the target node or to make changes within Linux on the '.
+ 'target node. This does not appear to be working.',
+ 'userResp' => 'You should investigate TCP/IP errors or network configuration errors within the target node.',
+ },
+ 'VCMAP01' =>
+ { 'severity' => 4,
+ 'recAction' => 1,
+ 'text' => 'Unable to determine the role of the Cloud Manager Appliance from the %s file.',
+ 'explain' => 'The Cloud Manager Appliance has a /var/lib/sspmod/appliance_system_role '.
+ 'file that cannot be read or does not contain the expected role property '.
+ 'in its expected form of "role=value" where the value is either: '.
+ 'CONTROLLER, COMPUTE, COMPUTE_MN, or MN.'.
+ 'This indicates corruption of the file and possibly other files, or a failed '.
+ 'install.',
+ 'userResp' => 'You should correct the corruption of the /var/lib/sspmod/appliance_system_role '.
+ 'file and then rerun the IVP.',
+ },
+ 'VCMAP02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Unable to determine the version of Cloud Manager Appliance from the %s file.',
+ 'explain' => 'The Cloud Manager Appliance contains a /opt/ibm/cmo/version file '.
+ 'that cannot be read or does not contain a line indicating the '.
+ 'version of the appliance. This indicates a possible corruption of '.
+ 'the file system or a failed install.',
+ 'userResp' => 'You should verify that the file exists on the appliance and has the proper '.
+ 'permissions set to allow user root to read the file.',
+ },
+ 'VCNC01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'xCAT MN is unable to SSH to %s with user %s.',
+ 'explain' => 'The xCAT MN could not SSH into the compute node. This can occur for the '.
+ 'following reasons:'.
+ "\n".
+ '* the wrong user name was specified,'.
+ "\n".
+ '* the wrong IP address was specified,'.
+ "\n".
+ '* or the SSH keys were not set up on the compute '.
+ 'node to allow the xCAT MN to push data to that node.'.
+ "\n\n".
+ 'The error message indicates the IP address and user name that the IVP thinks '.
+ 'xCAT MN will use.',
+ 'userResp' => 'Verify the my_ip property, if it was specified in '.
+ '/etc/nova/nova.conf, or verify the local IP address of the OpenStack system. '.
+ 'The local IP address is used by the IVP preparation script as a default '.
+ 'when the my_ip property is not set. The IVP uses this '.
+ 'address to verify that the xCAT MN can access the compute node. xCAT MN '.
+ 'communicates with the compute node using this IP address. An address '.
+ 'which is not accessible by the xCAT MN will cause various xCAT functions '.
+ 'to fail. If the my_ip is not set, an incorrect default for your compute '.
+ 'node might have been chosen. You may wish to specify the my_ip property '.
+ 'with a valid value for your environment. Also, verify the value of the '.
+ 'zxcatIVP_expUser specified in the driver script by the IVP preparation script '.
+ 'script. This value defaults to "nova", which is the user name under '.
+ 'which the compute node will allow xCAT MN to access the system.',
+ },
+ 'VDP01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Disk pool %s was not found as a disk pool.',
+ 'explain' => 'The specified disk pool was not found. The disk pool is specified in '.
+ '/etc/nova/nova.conf and is passed to the IVP in the driver script '.
+ 'by the zxcatIVP_diskpools environment variable.',
+ 'userResp' => 'Verify the zvm_diskpool property in /etc/nova/nova.conf is correct.'
+ },
+ 'VDP02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Disk pool %s has no free space',
+ 'explain' => 'The indicated disk pool has no space for minidisk creation. '.
+ 'You may need to add disks to the directory manager disk pool '.
+ 'or specify a different disk pool for the zvm_diskpool property in '.
+ '/etc/nova/nova.conf.'.
+ "\n\n".
+ 'If you are running a basic IVP and see this message for disk pool '.
+ 'XCAT1, you can ignore the warning. Disk pool XCAT1 is a special '.
+ 'disk pool that normally has no available space. This disk pool '.
+ 'is not intended to be used as a disk pool by the compute node.',
+ 'userResp' => 'Add space to the disk pool in the directory manager.'
+ },
+ 'VDP03' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Unable to obtain a list of disk pools for host %s.',
+ 'explain' => 'The list of disk pools defined in the directory manager could not be obtained for '.
+ 'the specified host.',
+ 'userResp' => 'This can be caused by a few different problems. They include: '.
+ "\n".
+ '* No disk pools/regions defined in the directory manager - Use directory manager '.
+ 'commands to verify that disk pools have been defined, or to define them. '.
+ "\n".
+ '* The ZHCP server is unresponsive - Ensure that the ZHCP server is running. Other '.
+ 'error messages will occur if it is not running. '.
+ "\n".
+ '* SMAPI is unable to communicate with the directory manager - Use the SMAPI '.
+ 'SMSTATUS command to collect SMAPI debug information and verify the configuration '.
+ 'between SMAPI and the directory manager. '.
+ "\n".
+ '* If the name of the host node is incorrect in the message, then the xCAT server '.
+ 'may have been previously started prior to modifying the properties in '.
+ 'DMSSICNF COPY. This can cause an invalid xCAT node to be created for the host. Subsequent '.
+ 'restarts with a correctly configured DMSSICNF COPY file will not remove the '.
+ 'incorrect node but only add the new one. When the IVP attempts to verify the '.
+ 'host, it fails. See "zxcatIVP Issues" in the Enabling Manual for information on how to '.
+ 'remove the invalid node.',
+ },
+ 'VDS01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The file system related to the %s directory on the %s system has %s percent space '.
+ 'in use which is more than the expected maximum of %s percent.',
+ 'explain' => 'The file system is over the recommended percentage of space in use. This can cause processing errors.',
+ 'userResp' => 'You can eliminate this warning by freeing up space in the directories related to the file system or '.
+ 'adding space to the CMA\'s root disk. '.
+ 'See Appendix G, "Increasing the Size of the CMA\'s Root Disk using LVM Commands" section '.
+ 'in the Enabling z/VM for OpenStack Manual for instructions on increasing the size of the root disk.'
+ },
+ 'VDS02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The file system related to the %s directory on the %s system has %s available space '.
+ 'which is less than the expected minimum of %s.',
+ 'explain' => 'The file system has less than the minimum available space. This can cause processing errors.',
+ 'userResp' => 'You can eliminate this warning by freeing up space in the directories related to the file system or '.
+ 'adding space to the CMA\'s root disk. '.
+ 'See Appendix G, "Increasing the Size of the CMA\'s Root Disk using LVM Commands" section '.
+ 'in the Enabling z/VM for OpenStack Manual for instructions on increasing the size of the root disk.'
+ },
+ 'VDS03' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Unable to determine the percentage of disk space used by the %s system\'s file system '.
+ 'related to the %s directory.',
+ 'explain' => 'The IVP attempts to determine the size of the file system disk space related to the specified directory '.
+ 'using the df -h command and is unable to do so. This error is normally '.
+ 'related to disk corruption issue or problems with a logical volume associated with the directory.',
+ 'userResp' => 'Please review the messages log file on the affected system for errors related to the disks.'
+ },
+ 'VDS04' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The following files are larger than the expected maximum of \'%s\': %s',
+ 'explain' => 'Very large files in the indicated directory and it subdirectories can consume space needed '.
+ 'for normal operations. The IVP program warns of very large files.',
+ 'userResp' => 'You should consider removing the identified files. Please note that '.
+ 'the IVP program compiles a simple '.
+ 'list of large files in the directories. It only removes some files from the list such as '.
+ 'files ending in .so or with .so. in the name or .jar at the end of the filename. For this reason, '.
+ 'you should only remove files which you have identified as log files or which you know '.
+ 'are files which can be safely removed. See "Space Issues on persistent '.
+ 'Directory Can Lead to xCAT MN Issues" in the Enabling Manual for '.
+ 'instructions on addressing space issues.'
+ },
+ 'VDS05' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The size of the logical volume on which the xCAT MN image repository resides (%s) '.
+ 'is less than image pruning goal (%s).',
+ 'explain' => 'The xCAT MN image repository is a subdirectory of the /install '.
+ 'directory. The IVP compares the size of the logical volume '.
+ 'providing storage for the directory to the value specified in the '.
+ 'xcat_free_space_threshold property in the /etc/install/nova.conf '.
+ 'file in the OpenStack systen (passed using the '.
+ 'xcatIVP_expectedReposSpace property in the driver script). When '.
+ 'the OpenStack performs automated pruning of older OpenStack '.
+ 'images from the xCAT image repository (images that still exist in '.
+ 'Glance), it will attempt to free up enough space to match the '.
+ 'xcat_free_space_threshold. An xcat_free_space_threshold value '.
+ 'that is greater than the size of the logical volume can result in '.
+ 'more images being removed than necessary when automatic pruning '.
+ 'occurs. This will result in images being transferred between '.
+ 'OpenStack and xCAT unnecessarily.',
+ 'userResp' => 'You should consider adding additional volumes the logical volume '.
+ 'by updating the XCAT_iso property in the DMSSICNF COPY file for '.
+ 'an xCAT MN system, or to the cmo_data_disk property in the '.
+ 'DMSSICMO COPY file for a CMA in controller role.'
+ },
+ 'VHN01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The host node (%s) was not defined.',
+ 'explain' => 'The specified host node was not defined to xCAT. ',
+ 'userResp' => 'Verify that the zvm_host property is specified '.
+ 'correctly in /etc/nova/nova.conf. This property is passed by the driver '.
+ 'script in the zxcatIVP_hostNode environment variable.'
+ },
+ 'VHN02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Host node does not have an ZHCP associated with it.',
+ 'explain' => 'The specified host node, specified with the zvm_host property in '.
+ '/etc/nova/nova.conf, does not have a ZHCP agent associated with it. '.
+ 'This property is passed by the driver script in the zxcatIVP_hostNode '.
+ 'environment variable.',
+ 'userResp' => 'You should correct the host node in xCAT by associating a ZHCP agent '.
+ 'using the hcp property so that it can be managed by xCAT and the services '.
+ 'services that use xCAT.'
+ },
+ 'VMN01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'MN node(%s) was not defined.',
+ 'explain' => 'The xCAT management node specified on the zvm_xcat_master '.
+ 'property in the /etc/nova/nova.conf file was not in the list of '.
+ 'defined xCAT nodes. The probable cause of this message is an '.
+ 'incorrectly specified property value for the xCAT node that '.
+ 'represents the xCAT MN.',
+ 'userResp' => 'You can view the list of nodes using the xCAT GUI in the '.
+ 'Nodes->Nodes tab. The xCAT MN node should be in the list of '.
+ 'nodes for the "all" group. You can view other xCAT node groups '.
+ 'by selecting the group name in the "Groups" frame on the left '.
+ 'side of the web page.'
+ },
+ 'VMNI01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'xCAT MN does not have an interface defined for %s with address: %s.',
+ 'explain' => 'The xCAT MN does not have the specified IP address defined. This '.
+ 'is most likely caused by a typo in the configuration files. The '.
+ 'IVP driver script contains the values used in the test, and which '.
+ 'configuration file and property provided the value.',
+ 'userResp' => 'Use the information to identify the property in error and correct '.
+ 'the address in the configuration file.'
+ },
+ 'VMNI02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Unable to determine the routing prefix information for %s %s.',
+ 'explain' => 'While attempting to verify the information specified for the IVP, '.
+ 'the routing prefix for the xCAT MN IP address could not be determined. '.
+ 'This could indicate a problem with the IP interface for xCAT MN.',
+ 'userResp' => 'Use the information to identify the property in error and correct '.
+ 'the address in the configuration file.'
+ },
+ 'VMNI03' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Subnet mask specified as input is not valid: %s.',
+ 'explain' => 'The subnet mask specified as input to the IVP is not a valid subnet mask.',
+ 'userResp' => 'Please verify the subnet mask used as input to the installation '.
+ 'verification program.'
+ },
+ 'VMNI04' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'xCAT MN subnet mask for %s has a routing prefix of %s which '.
+ 'does not match the calculated routing prefix of %s for the subnet '.
+ 'mask passed as input: %s.',
+ 'explain' => 'The routing prefix for the xCAT MN does not match the calculated '.
+ 'routing prefix for the subnet mask that was specified as input '.
+ 'to the IVP.',
+ 'userResp' => 'Please verify the subnet mask used as input to the installation verification program.'
+ },
+ 'VMHS01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Unable to determine the signal shutdown time on %s. Query returned, rc: %s, output: %s',
+ 'explain' => 'The IVP program attempted to determine the signal shutdown duration on the z/VM host '.
+ 'and either encountered an unexpected return code or response from the command. '.
+ 'The response is expected to be in English.',
+ 'userResp' => 'Determine the cause of the error and correct it.'
+ },
+ 'VMHS02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'The signal shutdown time on %s is %s seconds which is less than the tested minimum of %s seconds.',
+ 'explain' => 'The signal shutdown time defines the time CP will wait for a virtual machine to respond to '.
+ 'a shutdown signal sent to it by SIGNAL, FORCE, or SHUTDOWN commands before forcing a virtual '.
+ 'machine off the z/VM system. A value of 0 causes CP to immediately force a virtual machine '.
+ 'without sending it a shutdown signal. xCAT and SMAPI use one or more of these commands in the '.
+ 'process of powering off a virtual machine.'.
+ "\n\n".
+ 'Linux systems cache their disk reads and writes to improve performance. For this reason, a sufficient '.
+ 'delay is recommended to allow the Linux operating system to clear the disk cache. '.
+ 'Failure to clear the cache can cause disk problems when the virtual machine logs back on '.
+ 'the z/VM system.',
+ 'userResp' => 'You should change the signal shutdown time for the z/VM host. The system configuration '.
+ 'file supports a SET SIGNAL SHUTDOWNTIME statement that allows you to set the time. '.
+ 'In addition, the CP class A and C SET SIGNAL SHUTDOWNTIME command can be used to '.
+ 'change the time for the current system IPL. '.
+ "\n\n".
+ 'The test run by the IVP checks for a minimum amount of time. You should choose a time that '.
+ 'allows sufficient time for the Linux virtual machines that are running on your system. This '.
+ 'will depend upon the performance of your system and the activity performed by the Linux virtual '.
+ 'machines. In general, setting a larger time interval such as 300 seconds (5 minutes) is safer '.
+ 'than an interval that is too short. In most cases, the virtual machines will shutdown upon '.
+ 'receiving the signal in a much shorter time and thus avoid the forced log off that results '.
+ 'from the time interval expiring.'
+ },
+ 'VMS01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Unable to determine the virtual storage size.',
+ 'explain' => 'An attempt to verify the virtual storage size of the z/VM virtual '.
+ 'machine running xCAT MN using the z/VM CP QUERY VIRTUAL STORAGE '.
+ 'command failed. This can indicate a command authorization problem.',
+ 'userResp' => 'Please ensure that the virtual machine is permitted to run the command.'
+ },
+ 'VMS02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Virtual machine storage size (%s) is less than the recommended '.
+ 'size of %s.',
+ 'explain' => 'The virtual storage size of the z/VM virtual machine which is '.
+ 'running xCAT MN is less than the recommended size.',
+ 'userResp' => 'Please update the user directory for that virtual machine to '.
+ 'increase its virtual storage.'
+ },
+ 'VMUP01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'MACID user prefix for the %s is \'%s\' and is not the expected value of \'%s\'',
+ 'explain' => 'The MACADDR user prefix portion of the base_mac property in '.
+ '/etc/neutron/neutron.conf does not match the value specified '.
+ 'on the z/VM VMLAN system configuration property in the z/VM '.
+ 'host. The IVP uses the z/VM CP Query VMLAN '.
+ 'command along with the information in the "VMLAN MAC address '.
+ 'assignment" portion of the command response, specifically the '.
+ 'user prefix information.',
+ 'userResp' => 'This error is most often caused by an error in the OpenStack configuration '.
+ 'property. Either the OpenStack property should be changed to match the z/VM '.
+ 'system or the z/VM system\'s value should be changed.',
+ },
+ 'VN01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Network %s was not found as a network.',
+ 'explain' => 'The specified network is not a known network on the host. The most '.
+ 'likely cause of this problem is a typo in the flat_networks and/or '.
+ 'network_vlan_ranges properties of the /etc/neutron/plugins/ml2/ml2_conf.ini file.',
+ 'userResp' => 'Correct the OpenStack configuration files.'
+ },
+ 'VN02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Network %s is not %s as expected.',
+ 'explain' => 'The specified network on the host is not configured with the '.
+ 'expected VLAN awareness. The most likely cause of this problem '.
+ 'is an error in the flat_networks and/or network_vlan_ranges '.
+ 'properties of the /etc/neutron/plugins/ml2/ml2_conf.ini file.',
+ 'userResp' => 'Correct the OpenStack configuration files.',
+ },
+ 'VNE01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Node %s is not defined to xCAT.',
+ 'explain' => 'The indicated node is not defined to xCAT. '.
+ 'This most often indicates a typo in a configuration file.',
+ 'userResp' => 'If using a driver script created by the IVP preparation script, '.
+ 'please review the driver script to determine the OpenStack '.
+ 'property and configuration file which specified the node. You can '.
+ 'do this by locating the node name in the driver script and then '.
+ 'reading the comments which indicate what property was used to set '.
+ 'the value in the driver script.'
+ },
+ 'VP01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Unable to get the directory statements for profile %s',
+ 'explain' => 'The profile specified as input is not in the z/VM directory. '.
+ 'The cause of this error is either a typo in the zvm_user_profile '.
+ 'property in the /etc/nova/nova.conf file or that the profile was not'.
+ 'defined to z/VM.',
+ 'userResp' => 'Correct the OpenStack configuration file.',
+ },
+ 'VR01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'REST API failed to successfully respond to request.\n' .
+ ' Response code: %s, Message: %s\n' .
+ ' Response content: %s',
+ 'explain' => 'A REST communication to the xCAT Management Node from the same '.
+ 'server on which the management node was running failed. This '.
+ 'can be caused by a typo in the zvm_xcat_username, zvm_xcat_password, '.
+ 'and/or zvm_xcat_server properties in /etc/nova/nova.conf file. The xCAT '.
+ 'management node obtains the value that it recognizes for the user name from the '.
+ 'XCAT_MN_admin property in DMSSICNF COPY. The user name properties '.
+ 'should match. It can also occur if there are configuration errors '.
+ 'or TCP/IP errors in the xCAT management node.',
+ 'userResp' => 'Review the REST response data that is provided with the message. '.
+ 'It should help isolate the problem.'
+ },
+ 'VU01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'user %s is not in the policy table or has no rule defined in the table.',
+ 'explain' => 'The specified xCAT user is not a known xCAT user. This is most likely '.
+ 'caused by a typo in the zvm_xcat_username property in the '.
+ '/etc/nova/nova.conf file. The xCAT management node obtains the value that it '.
+ 'recognizes for the user name from the XCAT_MN_admin property in DMSSICNF COPY. '.
+ "\n".
+ 'Another cause is if the user is defined in the policy table but does not '.
+ 'have a rule defined.',
+ 'userResp' => 'Correct the OpenStack configuration file, if it is incorrect. '.
+ 'Correct the xCAT POLICY table, if it is incorrect.',
+ },
+ 'VU02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'user %s is in the xCAT POLICY table but the rule property is not \'accept\' or '.
+ '\'allow\'. It is \'%s\'.',
+ 'explain' => 'The specified xCAT user is not defined in the xCAT POLICY table with the '.
+ 'correct rule. ',
+ 'userResp' => 'Correct the xCAT POLICY table entry for the user.',
+ },
+ 'VVO01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'vswitch %s does not exist.',
+ 'explain' => 'The specified virtual switch does not exist in the z/VM system.',
+ 'userResp' => 'The vswitch name was specified as the section name in the '.
+ '/etc/neutron/plugins/zvm/neutron_zvm_plugin.ini file before the '.
+ 'rdev_list property. The neutron agent creates the virtual switches '.
+ 'when it starts up. If the switch is not defined, you should determine '.
+ 'whether the neutron agent was started and is successfully communicating '.
+ 'with xCAT.'
+ },
+ 'VVO02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'vswitch %s does not use real device %s',
+ 'explain' => 'The /etc/neutron/plugins/zvm/neutron_zvm_plugin.ini file indicated that '.
+ 'the virtual switch has a real device associated with it at the specified '.
+ 'address which does not match the actual vswitch definition in z/VM.',
+ 'userResp' => 'This is most likely an error in the rdev_list property for the section '.
+ 'indicated by the vswitch name in the /etc/neutron/plugins/zvm/neutron_zvm_plugin.ini file. '.
+ 'Correct the OpenStack configuration file.',
+ },
+ 'VZN01' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'zHCP node %s did not respond to a ping.',
+ 'explain' => 'The indicated ZHCP node did not respond to a ping. '.
+ 'The virtual machine may be logged off the z/VM system '.
+ 'or there may be problems in the configuration of this server causing it '.
+ 'to fail to IPL, or configure its TCP/IP interfaces. '.
+ 'ZHCP is necessary to manage the z/VM host and its virtual servers. '.
+ 'The ZHCP node is associated with the host specified by the zvm_host property in the '.
+ '/etc/nova/nova.conf file.',
+ 'userResp' => 'There are a number of possibilities that you should consider: '.
+ "\n".
+ '* Verify that the virtual machine is logged on. '.
+ 'If it is not logged on then verify that you have performed the necessary steps to '.
+ 'tell SMAPI to start the server when SMAPI starts. '.
+ 'This is discussed in the z/VM Systems Management Application Programming manual.'.
+ "\n".
+ '* Obtain the console log from the virtual server and verify that the system has '.
+ 'not stopped itself due to an error. This is not a normal condition and '.
+ 'usually indicates a serious configuration error.',
+ },
+ 'VZN02' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'zHCP node %s is either not powered on or responding.',
+ 'explain' => 'The indicated ZHCP node did not respond to simple power status request. '.
+ 'There may be problems with the set up of this ZHCP.',
+ 'userResp' => 'Pay particular attention to whether there are SSL key problems. Another '.
+ 'possible cause is an error preventing ZHCP from communicating with the '.
+ 'z/VM CP. The ZHCP node is associated with the host specified by the zvm_host '.
+ 'property in the /etc/nova/nova.conf file.',
+ },
+ 'VZN03' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Unable to get the directory statements for %s. The statements should be for userid %s.',
+ 'explain' => 'The indicated ZHCP node did not provide the proper response to a request for '.
+ 'information on a user in the z/VM directory. '.
+ 'The IVP checks the directory statements to verify that a USER or IDENTITY statement '.
+ 'was returned with the userid that was specified in the xCAT zvm table. '.
+ 'In addition, the SMAPI servers or the directory manager '.
+ 'may not be configured to communicate with the ZHCP agent. '.
+ "\n".
+ 'The ZHCP node is associated with the host specified by the zvm_host property in the '.
+ '/etc/nova/nova.conf file.',
+ 'userResp' => 'Verify that:'.
+ "\n".
+ '* the zvm table has the userid property correctly listed for the '.
+ 'virtual machine that is running the ZHCP node. If not then correct it.'.
+ "\n".
+ '* the Directory manager is operational. This can be accomplished by issuing '.
+ 'a command to review a userid\'s directory entries to see if you get a valid response.'.
+ "\n".
+ '* the Directory manager is properly configuring to communicate with the SMAPI servers. '.
+ 'This is discussed in the z/VM Systems Management Application Programming manual.',
+ },
+ 'VZN04' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'zHCP node %s is encountering errors communicating with SMAPI, out: %s',
+ 'explain' => 'The indicated ZHCP node was not able to execute a simple query to the SMAPI '.
+ 'servers and receive an expected result. This indicates a possible error '.
+ 'in the SMAPI configuration.',
+ 'userResp' => 'You should review the SMAPI configuration to ensure all steps were '.
+ 'accomplished and that the virtual machine running the ZHCP agent is '.
+ 'authorized to communicate with the SMAPI servers and that '.
+ 'the SMAPI servers are running. For example, verify that '.
+ 'the VSMWORK1 AUTHLIST file in \'VMSYS:VSMWORK1.\' SFS directory lists '.
+ 'the virtual machine that is running the ZHCP agent and that the information in the file '.
+ 'is in the correct columns.',
+ },
+ 'VZN05' =>
+ { 'severity' => 4,
+ 'recAction' => 0,
+ 'text' => 'Unable to find a zHCP node related to host %s.',
+ 'explain' => 'The indicated host node does not have a ZHCP node which is defined and '.
+ 'associated with it. The IVP program expects each host to have an hcp property '.
+ 'defined and that property to be related to an xCAT node that represents '.
+ 'the ZHCP server and has the same host name as specified for the host\'s hcp property.',
+ 'userResp' => 'Define a node in xCAT for the ZHCP server.'
+ },
+ );
+
+my %reposList = (
+ 'VERIFYNODE' => \%verifyMsgs,
+ 'ZXCATIVP' => \%zxcativpMsgs,
+ );
+
+
+
+
+#-------------------------------------------------------
+
+=head3 buildMsg
+
+ Description : Build a message from a message repository file.
+ Arguments : Group identifier
+ Message identifier
+ 'BLANK_LINE' is a special identifier that does not appear in
+ the message repository but instead causes a blank line to
+ be printed to the display.
+ Message substitutions
+ Returns : Recommended action:
+ 0: Continue processing
+ 1: Fatal, end processing
+ severity - Severity of message and indicate whether it gets
+ a header to the message text (e.g. "Error (IVP:MAINT01) " )
+ 0 - no message header, unrated output
+ 1 - bypass message used by automated tests
+ 2 - information message with "Info" header
+ 3 - unknown message severity
+ 4 - warning message with "Warning" header
+ 5 - error message with "Error" header
+ Constructed message
+ Additional information (e.g. explanation, system action, user action)
+ Example : ( $rc, $sev, $msg, $extraInfo ) = xCAT::zvmMsgs->buildMsg('ZXCATIVP', 'IVP', $msgInfo, \@msgSubs);
+
+=cut
+
+#-------------------------------------------------------
+sub buildMsg {
+ my ( $class, $groupId, $msgId, $subs ) = @_;
+ my @msgSubs = ();
+ my $recAction = 0;
+ my %respMsgs;
+ my $respHash;
+ my $retMsg = '';
+ my $retExtra = '';
+ my $sev = 0;
+ my ( $init_tab, $subsequent_tab );
+
+ $Text::Wrap::unexpand = 0;
+
+ if ( defined $subs ) {
+ @msgSubs = @$subs;
+ }
+
+ # Get the hash of the messages.
+ if ( exists $reposList{$groupId} ) {
+ $respHash = $reposList{$groupId};
+ } else {
+ $respHash = \%verifyMsgs;
+ }
+ %respMsgs = %$respHash;
+
+ # Find the message
+ if ( $msgId eq 'BLANK_LINE' ) {
+ $retMsg = "\n";
+ } elsif ( !exists $respMsgs{$msgId} ) {
+ $retMsg = "Warning ($groupId:$msgId): Message was not found! Unable to find " .
+ "\'$msgId\' in \'$groupId\' messages.\n";
+ $sev = 3;
+ # Recommended Action is 'continue'.
+ } else {
+ # Build severity and message Id portion of the message.
+ my $msg = '';
+ if ( exists $respMsgs{$msgId}{'severity'} ) {
+ $sev = $respMsgs{$msgId}{'severity'};
+ if ( $respMsgs{$msgId}{'severity'} != 0 ) {
+ $msg = $sevInfo[ $respMsgs{$msgId}{'severity'} ] . " ($groupId:$msgId) ";
+ }
+ } else {
+ # Unknown severity
+ $msg = $sevInfo[1] . " ($groupId:$msgId) ";
+ $sev = 3;
+ }
+
+ # Determine the recommended action to return to the caller.
+ if ( exists $respMsgs{$msgId}{'recAction'} ) {
+ $recAction = $respMsgs{$msgId}{'recAction'};
+ }
+
+ # Build text portion of the message.
+ if ( exists $respMsgs{$msgId}{'text'} ) {
+ # Determine the number of '%s' in the message and pad @msgSubs
+ # so that we do not get a sprintf error due to having to few
+ # substitution values.
+ my $numSubs = 0;
+ while ( $respMsgs{$msgId}{'text'} =~ /\%s/g ) { $numSubs++ }
+ if ( $numSubs > 0 and $numSubs > ( scalar @msgSubs ) ) {
+ # Too few subs. Push on some empty strings so that sprintf does not complain.
+ for ( my $i = (scalar @msgSubs); $i <= $numSubs; $i++ ) {
+ push @msgSubs, '';
+ }
+ }
+
+ if ( @msgSubs ) {
+ # Ensure all elements in @msgSubs are defined.
+ for ( my $i = 0; $i < (scalar @msgSubs); $i++) {
+ if ( ! defined $msgSubs[$i] ) {
+ $msgSubs[$i] = '';
+ }
+ }
+
+ # Insert the substitutions
+ my $msgText = sprintf( $respMsgs{$msgId}{'text'}, @msgSubs);
+ $msg = "$msg$msgText";
+ } else {
+ $msg = $msg . $respMsgs{$msgId}{'text'};
+ }
+ }
+
+ # Set the subsequent wrap/tab value for formatting.
+ if ( exists $respMsgs{$msgId}{'initTab'} ) {
+ $init_tab = $respMsgs{$msgId}{'initTab'};
+ } else {
+ $init_tab = "";
+ }
+ if ( exists $respMsgs{$msgId}{'subTab'} ) {
+ $subsequent_tab = $respMsgs{$msgId}{'subTab'};
+ } else {
+ $subsequent_tab = "\t";
+ }
+
+ # Format the messages lines with proper indentation.
+ my $line;
+ chomp $msg;
+ my @msgLines = split( /\\n/, $msg );
+ for ( my $i = 0; $i < scalar @msgLines; $i++ ) {
+ $line = "$msgLines[$i]";
+ $retMsg = $retMsg . wrap( $init_tab, $subsequent_tab, $line ) . "\n";
+ }
+
+ if ( $respMsgs{$msgId}{'severity'} >= 1 ) {
+ # Build explanation portion of the known messages that are bypass,
+ # info, warning or error. These can have extra information.
+ if ( exists $respMsgs{$msgId}{'explain'} ) {
+ my $expLines = " Explanation: $respMsgs{$msgId}{'explain'}";
+ @msgLines = split( /\\n/, $expLines );
+ for ( my $i = 0; $i < scalar @msgLines; $i++ ) {
+ $line = "$msgLines[$i]";
+ if ( $i != 0 ) {
+ $line = "\t$line";
+ }
+ $retExtra = $retExtra . wrap( $init_tab, $subsequent_tab, $line ) . "\n";
+ }
+ }
+
+ # Build system action portion of the message.
+ my $sysAction;
+ if ( exists $respMsgs{$msgId}{'sysAct'} ) {
+ $sysAction = " System Action: $respMsgs{$msgId}{'sysAct'}";
+ } else {
+ if ( $recAction == 0 and exists $respMsgs{'NONFATAL_DEFAULTS'}{'sysAct'} ) {
+ $sysAction = " System Action: $respMsgs{'NONFATAL_DEFAULTS'}{'sysAct'}";
+ } elsif ( $recAction == 1 and exists $respMsgs{'FATAL_DEFAULTS'}{'sysAct'} ) {
+ $sysAction = " System Action: $respMsgs{'FATAL_DEFAULTS'}{'sysAct'}";
+ }
+ }
+ if ( defined $sysAction ) {
+ #@msgLines = split( /\\n/, $sysAction );
+ #$retMsg = $retMsg . wrap( "", "\t", @msgLines ) . "\n";
+
+ @msgLines = split( /\\n/, $sysAction );
+ for ( my $i = 0; $i < scalar @msgLines; $i++ ) {
+ $line = "$msgLines[$i]";
+ if ( $i != 0 ) {
+ $line = "\t$line";
+ }
+ $retExtra = $retExtra . wrap( $init_tab, $subsequent_tab, $line ) . "\n";
+ }
+ }
+
+ # Build user response portion of the message.
+ if ( exists $respMsgs{$msgId}{'userResp'} ) {
+ @msgLines = split( /\\n/, " User Response: $respMsgs{$msgId}{'userResp'}" );
+ #$retMsg = $retMsg . wrap( "", "\t", @msgLines ) . "\n";
+ for ( my $i = 0; $i < scalar @msgLines; $i++ ) {
+ $line = "$msgLines[$i]";
+ if ( $i != 0 ) {
+ $line = "\t$line";
+ }
+ $retExtra = $retExtra . wrap( $init_tab, $subsequent_tab, $line ) . "\n";
+ }
+ }
+ }
+ }
+
+ return ( $recAction, $sev, $retMsg, $retExtra );
+}
\ No newline at end of file
diff --git a/perl-xCAT/xCAT/zvmUtils.pm b/perl-xCAT/xCAT/zvmUtils.pm
index 2ef8880bd..893278fd5 100644
--- a/perl-xCAT/xCAT/zvmUtils.pm
+++ b/perl-xCAT/xCAT/zvmUtils.pm
@@ -1,4 +1,4 @@
-# IBM(c) 2013 EPL license http://www.eclipse.org/legal/epl-v10.html
+# IBM(c) 2013-2016 EPL license http://www.eclipse.org/legal/epl-v10.html
#-------------------------------------------------------
=head1
@@ -14,10 +14,37 @@ use xCAT::Utils;
use xCAT::Table;
use xCAT::NetworkUtils;
use File::Basename;
+use Net::Ping;
use strict;
use warnings;
+use Encode;
+use JSON;
+use Data::Dumper;
+use Cwd;
1;
+my $locOpenStackUpdateName = '/var/lib/sspmod/setnewname.py';
+
+# Files which contain OS distribution and version information.
+my $locEtcDebianVersion = '/etc/debian_version';
+my $locEtcFedoraRelease = '/etc/fedora-release';
+my $locEtcIssue = '/etc/issue';
+my $locEtcLsbRelease = '/etc/lsb-release';
+my $locEtcOsRelease = '/etc/os-release';
+my $locEtcRedhatRelease = '/etc/redhat-release';
+my $locEtcStarRelease = '/etc/*-release';
+my $locEtcSuseRelease = '/etc/SuSE-release';
+my $locEtcUnitedLinux = '/etc/UnitedLinux-release';
+my $locAllEtcVerFiles = "/etc/*-release /etc/issue /etc/debian_version";
+
+# Supported Operating System distros and versions
+my %supportedVersions = (
+ rhel5 => 1,
+ rhel6 => 1,
+ sles10 => 1,
+ sles11 => 1,
+ );
+
#-------------------------------------------------------
=head3 getNodeProps
@@ -27,20 +54,20 @@ use warnings;
Properties
Returns : Node properties from given table
Example : my $propVals = xCAT::zvmUtils->getNodeProps($tabName, $node, $propNames);
-
+
=cut
#-------------------------------------------------------
sub getNodeProps {
# Get inputs
- my ($class, $tabName, $node, @propNames) = @_;
+ my ( $class, $tabName, $node, @propNames ) = @_;
# Get table
my $tab = xCAT::Table->new($tabName);
# Get property values
- my $propVals = $tab->getNodeAttribs($node, [@propNames]);
+ my $propVals = $tab->getNodeAttribs( $node, [@propNames] );
return ($propVals);
}
@@ -55,21 +82,21 @@ sub getNodeProps {
Requested properties
Returns : Table entry properties
Example : my $propVals = xCAT::zvmUtils->getTabPropsByKey($tabName, $key, $keyValue, @reqProps);
-
+
=cut
#-------------------------------------------------------
sub getTabPropsByKey {
# Get inputs
- my ($class, $tabName, $key, $keyVal, @propNames) = @_;
+ my ( $class, $tabName, $key, $keyVal, @propNames ) = @_;
# Get table
my $tab = xCAT::Table->new($tabName);
my $propVals;
# Get table attributes matching given key
- $propVals = $tab->getAttribs({ $key => $keyVal }, @propNames);
+ $propVals = $tab->getAttribs( { $key => $keyVal }, @propNames );
return ($propVals);
}
@@ -80,14 +107,14 @@ sub getTabPropsByKey {
Arguments : Table name
Returns : All table entries
Example : my $entries = xCAT::zvmUtils->getAllTabEntries($tabName);
-
+
=cut
#-------------------------------------------------------
sub getAllTabEntries {
# Get inputs
- my ($class, $tabName) = @_;
+ my ( $class, $tabName ) = @_;
# Get table
my $tab = xCAT::Table->new($tabName);
@@ -109,20 +136,20 @@ sub getAllTabEntries {
Property value
Returns : Nothing
Example : xCAT::zvmUtils->setNodeProp($tabName, $node, $propName, $propVal);
-
+
=cut
#-------------------------------------------------------
sub setNodeProp {
# Get inputs
- my ($class, $tabName, $node, $propName, $propVal) = @_;
+ my ( $class, $tabName, $node, $propName, $propVal ) = @_;
# Get table
- my $tab = xCAT::Table->new($tabName, -create => 1, -autocommit => 0);
+ my $tab = xCAT::Table->new( $tabName, -create => 1, -autocommit => 0 );
# Set property
- $tab->setAttribs({ 'node' => $node }, { $propName => $propVal });
+ $tab->setAttribs( { 'node' => $node }, { $propName => $propVal } );
# Save table
$tab->commit;
@@ -140,20 +167,20 @@ sub setNodeProp {
Reference to property name/value hash
Returns : Nothing
Example : xCAT::zvmUtils->setNodeProps($tabName, $node, \%propHash);
-
+
=cut
#-------------------------------------------------------
sub setNodeProps {
# Get inputs
- my ($class, $tabName, $node, $propHash) = @_;
+ my ( $class, $tabName, $node, $propHash ) = @_;
# Get table
- my $tab = xCAT::Table->new($tabName, -create => 1, -autocommit => 0);
+ my $tab = xCAT::Table->new( $tabName, -create => 1, -autocommit => 0 );
# Set property
- $tab->setAttribs({ 'node' => $node }, $propHash);
+ $tab->setAttribs( { 'node' => $node }, $propHash );
# Save table
$tab->commit;
@@ -168,24 +195,24 @@ sub setNodeProps {
Description : Delete a table entry
Arguments : Table
Key name
- Key value
+ Key value
Returns : Nothing
Example : xCAT::zvmUtils->delTabEntry($tabName, $keyName, $keyVal);
-
+
=cut
#-------------------------------------------------------
sub delTabEntry {
# Get inputs
- my ($class, $tabName, $keyName, $keyVal) = @_;
+ my ( $class, $tabName, $keyName, $keyVal ) = @_;
# Get table
- my $tab = xCAT::Table->new($tabName, -create => 1, -autocommit => 0);
+ my $tab = xCAT::Table->new( $tabName, -create => 1, -autocommit => 0 );
# Delete entry from table
- my %key = ($keyName => $keyVal);
- $tab->delEntries(\%key);
+ my %key = ( $keyName => $keyVal );
+ $tab->delEntries( \%key );
# Save table
$tab->commit;
@@ -201,15 +228,15 @@ sub delTabEntry {
Arguments : String
Returns : Tabbed string
Example : my $str = xCAT::zvmUtils->tabStr($str);
-
+
=cut
#-------------------------------------------------------
sub tabStr {
# Get inputs
- my ($class, $inStr) = @_;
- my @lines = split("\n", $inStr);
+ my ( $class, $inStr ) = @_;
+ my @lines = split( "\n", $inStr );
# Tab output
my $outStr;
@@ -228,14 +255,14 @@ sub tabStr {
Arguments : String
Returns : Trimmed string
Example : my $str = xCAT::zvmUtils->trimStr($str);
-
+
=cut
#-------------------------------------------------------
sub trimStr {
# Get string
- my ($class, $str) = @_;
+ my ( $class, $str ) = @_;
# Trim right
$str =~ s/\s*$//;
@@ -254,14 +281,14 @@ sub trimStr {
Arguments : String
Returns : New string
Example : my $str = xCAT::zvmUtils->replaceStr($str, $pattern, $replacement);
-
+
=cut
#-------------------------------------------------------
sub replaceStr {
# Get string
- my ($class, $str, $pattern, $replacement) = @_;
+ my ( $class, $str, $pattern, $replacement ) = @_;
# Replace string
$str =~ s/$pattern/$replacement/g;
@@ -277,25 +304,24 @@ sub replaceStr {
Arguments : String
Returns : Nothing
Example : xCAT::zvmUtils->printLn($callback, $str);
-
+
=cut
#-------------------------------------------------------
sub printLn {
# Get inputs
- my ($class, $callback, $str) = @_;
+ my ( $class, $callback, $str ) = @_;
# Print string
my $rsp;
my $type = "I";
- if ($str =~ m/error/i) { # Set to print error if the string contains error
+ if ($str =~ m/(\(error\)|\s*failed)/i) { # Set to print error if the string contains (error) or starts with failed
$type = "E";
}
$rsp->{data}->[0] = "$str";
- xCAT::MsgUtils->message($type, $rsp, $callback);
-
+ xCAT::MsgUtils->message( $type, $rsp, $callback );
# xCAT::MsgUtils->message( "S", $str ); # Print to syslog
return;
@@ -309,20 +335,20 @@ sub printLn {
Arguments : String
Returns : Nothing
Example : xCAT::zvmUtils->printSyslog($str);
-
+
=cut
#-------------------------------------------------------
sub printSyslog {
# Get inputs
- my ($class, $str) = @_;
+ my ( $class, $str ) = @_;
# Prepend where this message came from
$str = $class . " " . $str;
# Print string
- xCAT::MsgUtils->message("S", $str);
+ xCAT::MsgUtils->message( "S", $str );
return;
}
@@ -336,19 +362,19 @@ sub printSyslog {
Returns : TRUE Node exists
FALSE Node does not exists
Example : my $out = xCAT::zvmUtils->isZvmNode($node);
-
+
=cut
#-------------------------------------------------------
sub isZvmNode {
# Get inputs
- my ($class, $node) = @_;
+ my ( $class, $node ) = @_;
# Look in 'zvm' table
- my $tab = xCAT::Table->new('zvm', -create => 1, -autocommit => 0);
+ my $tab = xCAT::Table->new( 'zvm', -create => 1, -autocommit => 0 );
- my @results = $tab->getAllAttribsWhere("node like '%" . $node . "%'", 'userid');
+ my @results = $tab->getAllAttribsWhere( "node = '" . $node . "'", 'userid' );
foreach (@results) {
# Return 'TRUE' if given node is in the table
@@ -370,14 +396,14 @@ sub isZvmNode {
Node
Returns : Hardware configuration file path
Example : my $hwcfg = xCAT::zvmUtils->getHwcfg($user, $node);
-
+
=cut
#-------------------------------------------------------
sub getHwcfg {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -392,10 +418,15 @@ sub getHwcfg {
my @parms;
# If it is SUSE - hwcfg-qeth file is in /etc/sysconfig/hardware
- if ($os =~ m/SUSE/i) {
- $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/hardware/hwcfg-qeth*"`;
- @parms = split('\n', $out);
- return ($parms[0]);
+ if ( $os =~ m/SUSE/i ) {
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/hardware/hwcfg-qeth*"`;
+ my $cmd = "$sudo ls /etc/sysconfig/hardware/hwcfg-qeth*";
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ @parms = split( '\n', $out );
+ return ( $parms[0] );
}
# If no file is found - Return nothing
@@ -410,20 +441,20 @@ sub getHwcfg {
Arguments : Node
Returns : IP address of given node
Example : my $ip = xCAT::zvmUtils->getIp($node);
-
+
=cut
#-------------------------------------------------------
sub getIp {
# Get inputs
- my ($class, $node) = @_;
+ my ( $class, $node ) = @_;
# Get IP address
# You need the extra space in the pattern,
# else it will confuse gpok2 with gpok21
- my $out = `cat /etc/hosts | egrep -i "$node | $node."`;
- my @parms = split(' ', $out);
+ my $out = `cat /etc/hosts | egrep -i "$node | $node."`;
+ my @parms = split( ' ', $out );
return $parms[0];
}
@@ -439,14 +470,14 @@ sub getIp {
Node
Returns : Network configuration file path
Example : my $ifcfg = xCAT::zvmUtils->getIfcfg($user, $node);
-
+
=cut
#-------------------------------------------------------
sub getIfcfg {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -461,17 +492,27 @@ sub getIfcfg {
my @parms;
# If it is Red Hat - ifcfg-qeth file is in /etc/sysconfig/network-scripts
- if ($os =~ m/Red Hat/i) {
- $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network-scripts/ifcfg-eth*"`;
- @parms = split('\n', $out);
- return ($parms[0]);
+ if ( $os =~ m/Red Hat/i ) {
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network-scripts/ifcfg-eth*"`;
+ my $cmd = "$sudo ls /etc/sysconfig/network-scripts/ifcfg-eth*";
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ @parms = split( '\n', $out );
+ return ( $parms[0] );
}
# If it is SUSE - ifcfg-qeth file is in /etc/sysconfig/network
- elsif ($os =~ m/SUSE/i) {
- $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network/ifcfg-qeth*"`;
- @parms = split('\n', $out);
- return ($parms[0]);
+ elsif ( $os =~ m/SUSE/i ) {
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network/ifcfg-qeth*"`;
+ my $cmd = "$sudo ls /etc/sysconfig/network/ifcfg-qeth*";
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ @parms = split( '\n', $out );
+ return ( $parms[0] );
}
# If no file is found - Return nothing
@@ -488,14 +529,14 @@ sub getIfcfg {
NIC address
Returns : Network configuration file path
Example : my $ifcfg = xCAT::zvmUtils->getIfcfgByNic($user, $node, $nic);
-
+
=cut
#-------------------------------------------------------
sub getIfcfgByNic {
# Get inputs
- my ($class, $user, $node, $nic) = @_;
+ my ( $class, $user, $node, $nic ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -510,42 +551,71 @@ sub getIfcfgByNic {
my @parms;
# If it is Red Hat - ifcfg-qeth file is in /etc/sysconfig/network-scripts
- if ($os =~ m/Red Hat/i) {
- $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network-scripts/ifcfg-eth*"`;
- @parms = split('\n', $out);
+ if ( $os =~ m/Red Hat/i ) {
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network-scripts/ifcfg-eth*"`;
+ my $cmd = "$sudo ls /etc/sysconfig/network-scripts/ifcfg-eth*";
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ @parms = split( '\n', $out );
# Go through each line
foreach (@parms) {
+ my $filename = $_;
# If the network file contains the NIC address
- $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo cat $_" | egrep -i "$nic"`;
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo cat $_" | egrep -i "$nic"`;
+ my $cmd = $sudo . ' cat $filename';
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i "$nic"`;
if ($out) {
# Return network file path
- return ($_);
+ return ($filename);
}
}
}
# If it is SLES 10 - ifcfg-qeth file is in /etc/sysconfig/network
- elsif ($os =~ m/SUSE Linux Enterprise Server 10/i) {
- $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network/ifcfg-qeth*" | grep -i "$nic"`;
- @parms = split('\n', $out);
- return ($parms[0]);
+ elsif ( $os =~ m/SUSE Linux Enterprise Server 10/i ) {
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network/ifcfg-qeth*" | grep -i "$nic"`;
+ my $cmd = $sudo . ' ls /etc/sysconfig/network/ifcfg-qeth*';
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i "$nic"`;
+ @parms = split( '\n', $out );
+ return ( $parms[0] );
}
# If it is SLES 11 - ifcfg-qeth file is in /etc/sysconfig/network
- elsif ($os =~ m/SUSE Linux Enterprise Server 11/i) {
+ elsif ( $os =~ m/SUSE Linux Enterprise Server 11/i ) {
# Get a list of ifcfg-eth files found
- $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network/ifcfg-eth*"`;
- my @file = split('\n', $out);
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network/ifcfg-eth*"`;
+ my $cmd = "$sudo ls /etc/sysconfig/network/ifcfg-eth*";
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ my @file = split( '\n', $out );
# Go through each ifcfg-eth file
foreach (@file) {
# If the network file contains the NIC address
- $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo cat $_" | grep -i "$nic"`;
+ #$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo cat $_" | grep -i "$nic"`;
+ my $cmd = $sudo . ' cat $_';
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i "$nic"`;
if ($out) {
# Return ifcfg-eth file path
@@ -567,24 +637,36 @@ sub getIfcfgByNic {
Node
Source file
Target file
- Returns : Nothing
- Example : xCAT::zvmUtils->sendFile($user, $node, $srcFile, $trgtFile);
-
+ Returns : Return code from SCP
+ Example : $rc = xCAT::zvmUtils->sendFile($user, $node, $srcFile, $trgtFile);
+
=cut
#-------------------------------------------------------
sub sendFile {
# Get inputs
- my ($class, $user, $node, $srcFile, $trgtFile) = @_;
+ my ( $class, $user, $node, $srcFile, $trgtFile ) = @_;
+
+ my $out;
+ my $rc;
# Create destination string
my $dest = "$user\@$node";
# SCP directory entry file over to HCP
- my $out = `/usr/bin/scp $srcFile $dest:$trgtFile`;
+ foreach my $wait ( 1, 2, 3, 5, 8, 15, 22, 34, 60 ) {
+ $out = `/usr/bin/scp $srcFile $dest:$trgtFile 2>&1`;
+ $rc = $?;
+ if ( $rc == 0 ) {
+ last;
+ }
- return;
+ xCAT::zvmUtils->printSyslog("SCP $srcFile $dest:$trgtFile - failed with rc: $rc, out: $out");
+ sleep( $wait );
+ }
+
+ return $rc;
}
#-------------------------------------------------------
@@ -596,26 +678,45 @@ sub sendFile {
Node
Returns : Root device address
Example : my $deviceAddr = xCAT::zvmUtils->getRootDeviceAddr($user, $node);
-
+
=cut
#-------------------------------------------------------
sub getRootDeviceAddr {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
+
+ my $sudo = "sudo";
+ if ($user eq "root") {
+ $sudo = "";
+ }
# Get the root device node
# LVM is not supported
- my $out = `ssh $user\@$node "mount" | grep "/ type" | sed 's/1//'`;
- my @parms = split(" ", $out);
- @parms = split("/", xCAT::zvmUtils->trimStr($parms[0]));
+ #my $out = `ssh $user\@$node "mount" | grep "/ type" | sed 's/1//'`;
+ my $cmd = $sudo . ' mount';
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i "/ type" | sed \'s/1//\'`;
+
+ my @parms = split( " ", $out );
+ @parms = split( "/", xCAT::zvmUtils->trimStr( $parms[0] ) );
my $devNode = $parms[0];
# Get disk address
- $out = `ssh $user\@$node "cat /proc/dasd/devices" | grep "$devNode" | sed 's/(ECKD)//' | sed 's/(FBA )//' | sed 's/0.0.//'`;
- @parms = split(" ", $out);
- return ($parms[0]);
+ #$out = `ssh $user\@$node "cat /proc/dasd/devices" | grep "$devNode" | sed 's/(ECKD)//' | sed 's/(FBA )//' | sed 's/0.0.//'`;
+ $cmd = $sudo . ' cat /proc/dasd/devices';
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i "$devNode" | sed "s/(ECKD)//" | sed "s/(FBA )//" | sed \'s/0.0.//\'`;
+
+ @parms = split( " ", $out );
+ return ( $parms[0] );
}
#-------------------------------------------------------
@@ -627,16 +728,17 @@ sub getRootDeviceAddr {
Node
Device address
Option (-d|-e)
- Returns : Nothing
+ Returns : successful: String indicating the enable was performed and ending with "Done".
+ unsuccessful: Error message from the last attempt
Example : my $out = xCAT::zvmUtils->disableEnableDisk($callback, $user, $node, $option, $devAddr);
-
+
=cut
#-------------------------------------------------------
sub disableEnableDisk {
# Get inputs
- my ($class, $user, $node, $option, $devAddr) = @_;
+ my ( $class, $user, $node, $option, $devAddr ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -644,12 +746,24 @@ sub disableEnableDisk {
}
# Disable/enable disk
- my $out;
- if ($option eq "-d" || $option eq "-e") {
- $out = `ssh $user\@$node "$sudo /sbin/chccwdev $option $devAddr"`;
+ my $out = '';
+ if ( $option eq "-d" || $option eq "-e" ) {
+ # Can't guarantee the success of online/offline disk, need to wait
+ # Until it's done because we may detach the disk after -d option
+ # or use the disk after the -e option
+ my @sleepTime = (1,2,3,5,8,15,22,34,60,60,60,60,60,90,120);
+ foreach (@sleepTime) {
+ my $cmd = "$sudo /sbin/chccwdev $option $devAddr 2>&1";
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) { # try again if an error
+ xCAT::zvmUtils->printSyslog( "$node: Error received on cmd: $cmd, output: $out" );
+ sleep($_);
+ } else {
+ return "ssh $user\@$node $sudo /sbin/chccwdev $option $devAddr... Done";
+ }
+ }
}
-
- return ($out);
+ return "Error: failed to ssh $user\@$node $sudo /sbin/chccwdev $option $devAddr, Output: $out";
}
#-------------------------------------------------------
@@ -659,16 +773,16 @@ sub disableEnableDisk {
Description : Get the MDISK statements in the user entry of a given node
Arguments : User (root or non-root)
Node
- Returns : MDISK statements
+ Returns : MDISK statements array or or string containing (Error)...
Example : my @mdisks = xCAT::zvmUtils->getMdisks($callback, $user, $node);
-
+
=cut
#-------------------------------------------------------
sub getMdisks {
# Get inputs
- my ($class, $callback, $user, $node) = @_;
+ my ( $class, $callback, $user, $node ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
@@ -679,23 +793,34 @@ sub getMdisks {
}
# Get HCP
- my @propNames = ('hcp', 'userid');
- my $propVals = xCAT::zvmUtils->getNodeProps('zvm', $node, @propNames);
+ my @propNames = ( 'hcp', 'userid' );
+ my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
my $hcp = $propVals->{'hcp'};
# Get node userID
my $userId = $propVals->{'userid'};
- my $out = `ssh $user\@$hcp "$sudo $dir/getuserentry $userId" | grep "MDISK"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh $user\@$hcp "$sudo $dir/getuserentry $userId"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo $dir/getuserentry $userId\"", $hcp, "getMdisks", $out, $node );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "MDISK"`;
# Get MDISK statements
- my @lines = split('\n', $out);
+ my @lines = split( '\n', $out );
my @disks;
foreach (@lines) {
+ # skip comment lines that start with * or whitespace *
+ if ( $_ =~ m/^\s*\*/) {
+ next;
+ }
$_ = xCAT::zvmUtils->trimStr($_);
# Save MDISK statements
- push(@disks, $_);
+ push( @disks, $_ );
}
return (@disks);
@@ -708,16 +833,16 @@ sub getMdisks {
Description : Get the DEDICATE statements in the user entry of a given node
Arguments : User (root or non-root)
Node
- Returns : DEDICATE statements
+ Returns : DEDICATE statements array or string containing (Error)...
Example : my @dedicates = xCAT::zvmUtils->getDedicates($callback, $user, $node);
-
+
=cut
#-------------------------------------------------------
sub getDedicates {
# Get inputs
- my ($class, $callback, $user, $node) = @_;
+ my ( $class, $callback, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -728,23 +853,30 @@ sub getDedicates {
my $dir = '/opt/zhcp/bin';
# Get zHCP
- my @propNames = ('hcp', 'userid');
- my $propVals = xCAT::zvmUtils->getNodeProps('zvm', $node, @propNames);
+ my @propNames = ( 'hcp', 'userid' );
+ my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
my $hcp = $propVals->{'hcp'};
# Get node userId
my $userId = $propVals->{'userid'};
- my $out = `ssh $user\@$hcp "$sudo $dir/smcli Image_Query_DM -T $userId" | egrep -i "DEDICATE"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh $user\@$hcp "$sudo $dir/smcli Image_Query_DM -T $userId"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "commandString", $hcp, "getMdisks", $out, $node );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "DEDICATE"`;
# Get DEDICATE statements
- my @lines = split('\n', $out);
+ my @lines = split( '\n', $out );
my @dedicates;
foreach (@lines) {
$_ = xCAT::zvmUtils->trimStr($_);
# Save statements
- push(@dedicates, $_);
+ push( @dedicates, $_ );
}
return (@dedicates);
@@ -752,23 +884,79 @@ sub getDedicates {
#-------------------------------------------------------
+=head3 getCommands
+
+ Description : Get the COMMAND statements in the user entry of a given node
+ Arguments : User (root or non-root)
+ Node
+ Returns : COMMAND statements array or or string containing (Error)...
+ Example : my @commands = xCAT::zvmUtils->getCommands($callback, $user, $node);
+
+=cut
+
+#-------------------------------------------------------
+sub getCommands {
+
+ # Get inputs
+ my ( $class, $callback, $user, $node ) = @_;
+
+ my $sudo = "sudo";
+ if ($user eq "root") {
+ $sudo = "";
+ }
+
+ # Directory where executables are
+ my $dir = '/opt/zhcp/bin';
+
+ # Get zHCP
+ my @propNames = ( 'hcp', 'userid' );
+ my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
+ my $hcp = $propVals->{'hcp'};
+
+ # Get node userId
+ my $userId = $propVals->{'userid'};
+
+ my $outmsg;
+ my $rc;
+ my $out = `ssh $user\@$hcp "$sudo $dir/smcli Image_Query_DM -T $userId"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo $dir/smcli Image_Query_DM -T $userId\"", $hcp, "getCommands", $out, $node );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "COMMAND"`;
+
+ # Get COMMAND statements
+ my @lines = split( '\n', $out );
+ my @commands;
+ foreach (@lines) {
+ $_ = xCAT::zvmUtils->trimStr($_);
+
+ # Save statements
+ push( @commands, $_ );
+ }
+
+ return (@commands);
+}
+
+#-------------------------------------------------------
+
=head3 getUserEntryWODisk
- Description : Get the user entry of a given node without MDISK statments,
+ Description : Get the user entry of a given node without MDISK statments,
and save it to a file
Arguments : User (root or non-root)
Node
File name to save user entry under
- Returns : Nothing
+ Returns : Nothing, or string containing (Error)...
Example : my $out = xCAT::zvmUtils->getUserEntryWODisk($callback, $user, $node, $file);
-
+
=cut
#-------------------------------------------------------
sub getUserEntryWODisk {
# Get inputs
- my ($class, $callback, $user, $node, $file) = @_;
+ my ( $class, $callback, $user, $node, $file ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -779,30 +967,37 @@ sub getUserEntryWODisk {
my $dir = '/opt/zhcp/bin';
# Get node properties from 'zvm' table
- my @propNames = ('hcp', 'userid');
- my $propVals = xCAT::zvmUtils->getNodeProps('zvm', $node, @propNames);
+ my @propNames = ( 'hcp', 'userid' );
+ my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
# Get HCP
my $hcp = $propVals->{'hcp'};
- if (!$hcp) {
- xCAT::zvmUtils->printLn($callback, "Error: Missing node HCP");
+ if ( !$hcp ) {
+ xCAT::zvmUtils->printLn( $callback, "Error: Missing node HCP" );
return;
}
# Get node userID
my $userId = $propVals->{'userid'};
- if (!$userId) {
- xCAT::zvmUtils->printLn($callback, "Error: Missing node ID");
+ if ( !$userId ) {
+ xCAT::zvmUtils->printLn( $callback, "Error: Missing node ID" );
return;
}
- my $out = `ssh $user\@$hcp "$sudo $dir/smcli Image_Query_DM -T $userId" | sed '\$d' | grep -v "MDISK"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh $user\@$hcp "$sudo $dir/smcli Image_Query_DM -T $userId"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo $dir/smcli Image_Query_DM -T $userId\"", $hcp, "getUserEntryWODisk", $out, $node );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | sed '\$d' | grep -a -i -v "MDISK"`;
# Create a file to save output
- open(DIRENTRY, ">$file");
+ open( DIRENTRY, ">$file" );
# Save output
- my @lines = split('\n', $out);
+ my @lines = split( '\n', $out );
foreach (@lines) {
# Trim line
@@ -825,15 +1020,15 @@ sub getUserEntryWODisk {
String
Returns : String appended with hostname
Example : my $str = xCAT::zvmUtils->appendHostname($hostname, $str);
-
+
=cut
#-------------------------------------------------------
sub appendHostname {
- my ($class, $hostname, $str) = @_;
+ my ( $class, $hostname, $str ) = @_;
# Append hostname to every line
- my @outLn = split("\n", $str);
+ my @outLn = split( "\n", $str );
$str = "";
foreach (@outLn) {
$str .= "$hostname: " . $_ . "\n";
@@ -850,20 +1045,20 @@ sub appendHostname {
Arguments : Output string
Returns : 0 Good output
-1 Bad output
- Example : my $rtn = xCAT::zvmUtils->checkOutput($callback, $out);
-
+ Example : my $rtn = xCAT::zvmUtils->checkOutput( $out );
+
=cut
#-------------------------------------------------------
sub checkOutput {
- my ($class, $callback, $out) = @_;
+ my ( $class, $out ) = @_;
# Check output string
- my @outLn = split("\n", $out);
+ my @outLn = split( "\n", $out );
foreach (@outLn) {
- # If output contains 'Failed', return -1
- if ($_ =~ m/Failed/i || $_ =~ m/Error/i) {
+ # If output contains 'Failed', or Error return -1
+ if ( $_ =~ m/Failed/i || $_ =~ m/Error/i ) {
return -1;
}
}
@@ -880,18 +1075,17 @@ sub checkOutput {
Reason (passed as a reference)
Returns : 0 Good output
-1 Bad output
- Example : my $rtn = xCAT::zvmUtils->checkOutput($callback, $out, \$reason);
-
+ Example : my $rtn = xCAT::zvmUtils->checkOutput( $out, \$reason );
+
=cut
#-------------------------------------------------------
sub checkOutputExtractReason {
- my ($class, $callback, $out, $reason) = @_;
+ my ( $class, $out, $reason ) = @_;
# Check output string
my @outLn = split("\n", $out);
foreach (@outLn) {
-
# If output contains 'ERROR: ', return -1 and pass back the reason.
if ($_ =~ /(.*?ERROR: )/) {
$$reason = substr($_, index($_, "ERROR: ") + length("ERROR: "));
@@ -902,6 +1096,79 @@ sub checkOutputExtractReason {
return 0;
}
+
+#-------------------------------------------------------
+
+=head3 checkSSH_Rc
+
+ Description : Check for SSH errors, and command return code failure
+
+ Arguments : $?
+ command that was issued (do not pass in a password in cmd string, just mask it out)
+ node the SSH is targeting
+ function name the SSH call was done in
+ optional command output
+ optional final target node (used to prefix "Node: " to error message. Helps in tracing hcp calls on behalf of a node)
+ optional syslog supression, "NONE", "SSHONLY" defaults to syslog message of any SSH or command error
+
+ Returns : rc = 0 Good output
+ rc = 255 Error occurred in SSH
+ rc > 0 Command error
+
+ $outmsg = error message string if $rc !=0
+ plus syslog entry for non zero errors
+
+
+ Example : ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "Command being issued", $hcp, "testfunc", $out, $node, "NONE");
+
+=cut
+
+#-------------------------------------------------------
+sub checkSSH_Rc {
+ my ( $class, $rc, $cmd, $tgtNode, $functionName, $cmdOutput, $finalTargetNode, $syslogOptions ) = @_;
+
+ my $msgTxt = '';
+ my $logit = 2;
+
+ if (!defined $cmdOutput) {
+ $cmdOutput = '';
+ } elsif ( $cmdOutput ne '' ) {
+ $cmdOutput = " Output: " . $cmdOutput . " ";
+ }
+
+ if (!defined $finalTargetNode) {
+ $finalTargetNode = '';
+ } else {
+ $finalTargetNode = "Node: " . $finalTargetNode . " ";
+ }
+ if (defined $syslogOptions) {
+ if ( $syslogOptions =~ m/NONE/i ) {
+ $logit = 0;
+ } elsif ( $syslogOptions =~ m/SSHONLY/i ) {
+ $logit = 1;
+ }
+ }
+
+
+ $rc = $rc >> 8;
+ if ( $rc == 255 ) {
+ # SSH failure to communicate with $tgtNode.
+ $msgTxt = "$finalTargetNode" . "(Error) In $functionName(), SSH communication to $tgtNode failed for command: $cmd$cmdOutput";
+ if ($logit > 0 ) {
+ xCAT::zvmUtils->printSyslog("$msgTxt");
+ }
+ return ($rc, $msgTxt);
+ } elsif ( $rc != 0 ) {
+ # Generic failure of the command.
+ $msgTxt = "$finalTargetNode" . "(Error) In $functionName(), command to $tgtNode failed with return code $rc for: $cmd$cmdOutput";
+ if ($logit > 1 ) {
+ xCAT::zvmUtils->printSyslog("$msgTxt");
+ }
+ return ($rc, $msgTxt);
+ }
+ return 0;
+}
+
#-------------------------------------------------------
=head3 getDeviceNode
@@ -912,12 +1179,12 @@ sub checkOutputExtractReason {
Disk address
Returns : Device node
Example : my $devNode = xCAT::zvmUtils->getDeviceNode($user, $node, $tgtAddr);
-
+
=cut
#-------------------------------------------------------
sub getDeviceNode {
- my ($class, $user, $node, $tgtAddr) = @_;
+ my ( $class, $user, $node, $tgtAddr ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -925,7 +1192,13 @@ sub getDeviceNode {
}
# Determine device node
- my $out = `ssh $user\@$node "$sudo cat /proc/dasd/devices" | grep ".$tgtAddr("`;
+ #my $out = `ssh $user\@$node "$sudo cat /proc/dasd/devices" | grep ".$tgtAddr("`;
+ my $cmd = $sudo . ' cat /proc/dasd/devices';
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i ".$tgtAddr("`;
my @words = split(' ', $out);
my $tgtDevNode;
@@ -951,12 +1224,12 @@ sub getDeviceNode {
Device node
Returns : Virtual device address
Example : my $addr = xCAT::zvmUtils->getDeviceNodeAddr($user, $node, $deviceNode);
-
+
=cut
#-------------------------------------------------------
sub getDeviceNodeAddr {
- my ($class, $user, $node, $deviceNode) = @_;
+ my ( $class, $user, $node, $deviceNode ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -966,7 +1239,13 @@ sub getDeviceNodeAddr {
# Find device node and determine virtual address
# /proc/dasd/devices look similar to this:
# 0.0.0100(ECKD) at ( 94: 0) is dasda : active at blocksize: 4096, 1802880 blocks, 7042 MB
- my $addr = `ssh $user\@$node "$sudo cat /proc/dasd/devices" | grep -i "is $deviceNode"`;
+ #my $addr = `ssh $user\@$node "$sudo cat /proc/dasd/devices" | grep -i "is $deviceNode"`;
+ my $cmd = $sudo . ' cat /proc/dasd/devices';
+ my $addr = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $addr ) == -1) {
+ return $addr;
+ }
+ $addr = `echo "$addr" | egrep -a -i "is $deviceNode"`;
$addr =~ s/ +/ /g;
$addr =~ s/^0.0.([0-9a-f]*).*/$1/;
chomp($addr);
@@ -985,12 +1264,12 @@ sub getDeviceNodeAddr {
Returns : 0 Address used
-1 Address not used
Example : my $ans = xCAT::zvmUtils->isAddressUsed($user, $node, $address);
-
+
=cut
#-------------------------------------------------------
sub isAddressUsed {
- my ($class, $user, $node, $address) = @_;
+ my ( $class, $user, $node, $address ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -998,7 +1277,13 @@ sub isAddressUsed {
}
# Search for disk address
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q v dasd" | grep "DASD $address"`;
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q v dasd" | grep "DASD $address"`;
+ my $cmd = $sudo . ' /sbin/vmcp q v dasd';
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i "DASD $address"`;
if ($out) {
return 0;
}
@@ -1015,12 +1300,12 @@ sub isAddressUsed {
zHCP
Returns : MACID
Example : my $macId = xCAT::zvmUtils->getMacID($user, $hcp);
-
+
=cut
#-------------------------------------------------------
sub getMacID {
- my ($class, $user, $hcp) = @_;
+ my ( $class, $user, $hcp ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -1029,11 +1314,11 @@ sub getMacID {
# Check /opt/zhcp/conf directory on HCP
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo test -d /opt/zhcp/conf && echo 'Directory exists'"`;
- if ($out =~ m/Directory exists/i) {
+ if ( $out =~ m/Directory exists/i ) {
# Check next_macid file
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo test -e /opt/zhcp/conf/next_macid && echo 'File exists'"`;
- if ($out =~ m/File exists/i) {
+ if ( $out =~ m/File exists/i ) {
# Do nothing
} else {
@@ -1060,17 +1345,17 @@ sub getMacID {
=head3 generateMacId
- Description : Generate a new MACID
+ Description : Generate a new MACID
Arguments : User (root or non-root)
zHCP
Returns : Nothing
Example : my $macId = xCAT::zvmUtils->generateMacId($user, $hcp);
-
+
=cut
#-------------------------------------------------------
sub generateMacId {
- my ($class, $user, $hcp) = @_;
+ my ( $class, $user, $hcp ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -1079,11 +1364,11 @@ sub generateMacId {
# Check /opt/zhcp/conf directory on HCP
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo test -d /opt/zhcp/conf && echo 'Directory exists'"`;
- if ($out =~ m/Directory exists/i) {
+ if ( $out =~ m/Directory exists/i ) {
# Check next_macid file
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo test -e /opt/zhcp/conf/next_macid && echo 'File exists'"`;
- if ($out =~ m/File exists/i) {
+ if ( $out =~ m/File exists/i ) {
# Do nothing
} else {
@@ -1109,14 +1394,14 @@ sub generateMacId {
if ($macId) {
# Convert hexadecimal - decimal
- $int = hex($macId);
- $macId = sprintf("%d", $int);
+ $int = hex($macId);
+ $macId = sprintf( "%d", $int );
# Generate new MAC suffix
$macId = $macId - 1;
# Convert decimal - hexadecimal
- $macId = sprintf("%X", $macId);
+ $macId = sprintf( "%X", $macId );
# Save new MACID
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo echo $macId > /opt/zhcp/conf/next_macid"`;
@@ -1133,14 +1418,14 @@ sub generateMacId {
Arguments : User (root or non-root)
Node
MAC suffix
- Returns : MAC address
+ Returns : MAC address or string containing (Error)...
Example : my $mac = xCAT::zvmUtils->createMacAddr($user, $node, $suffix);
-
+
=cut
#-------------------------------------------------------
sub createMacAddr {
- my ($class, $user, $node, $suffix) = @_;
+ my ( $class, $user, $node, $suffix ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -1149,23 +1434,31 @@ sub createMacAddr {
# Get node properties from 'zvm' table
my @propNames = ('hcp');
- my $propVals = xCAT::zvmUtils->getNodeProps('zvm', $node, @propNames);
+ my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
# Get HCP
my $hcp = $propVals->{'hcp'};
- if (!$hcp) {
+ if ( !$hcp ) {
return -1;
}
# Get USER Prefix
- my $prefix = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmcp q vmlan" | egrep -i "USER Prefix:"`;
+ my $outmsg;
+ my $rc;
+ my $prefix;
+ my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmcp q vmlan"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo /sbin/vmcp q vmlan\"", $hcp, "createMacAddr", $out, $node );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $prefix = `echo "$out" | egrep -a -i "USER Prefix:"`;
$prefix =~ s/(.*?)USER Prefix:(.*)/$2/;
$prefix =~ s/^\s+//;
$prefix =~ s/\s+$//;
- # Get MACADDR Prefix instead if USER Prefix is not defined
+ # Get MACADDR Prefix instead if USER Prefix is not defined, use saved out data
if (!$prefix) {
- $prefix = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmcp q vmlan" | egrep -i "MACADDR Prefix:"`;
+ $prefix = `echo "$out" | egrep -a -i "MACADDR Prefix:"`;
$prefix =~ s/(.*?)MACADDR Prefix:(.*)/$2/;
$prefix =~ s/^\s+//;
$prefix =~ s/\s+$//;
@@ -1179,18 +1472,18 @@ sub createMacAddr {
my $mac = $prefix . $suffix;
# If length is less than 12, append a zero
- if (length($mac) != 12) {
+ if ( length($mac) != 12 ) {
$mac = "0" . $mac;
}
# Format MAC address
$mac =
- substr($mac, 0, 2) . ":"
- . substr($mac, 2, 2) . ":"
- . substr($mac, 4, 2) . ":"
- . substr($mac, 6, 2) . ":"
- . substr($mac, 8, 2) . ":"
- . substr($mac, 10, 2);
+ substr( $mac, 0, 2 ) . ":"
+ . substr( $mac, 2, 2 ) . ":"
+ . substr( $mac, 4, 2 ) . ":"
+ . substr( $mac, 6, 2 ) . ":"
+ . substr( $mac, 8, 2 ) . ":"
+ . substr( $mac, 10, 2 );
return $mac;
}
@@ -1204,14 +1497,14 @@ sub createMacAddr {
Node
Returns : Operating system name
Example : my $osName = xCAT::zvmUtils->getOs($user, $node);
-
+
=cut
#-------------------------------------------------------
sub getOs {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -1219,9 +1512,15 @@ sub getOs {
}
# Get operating system
- my $out = `ssh -o ConnectTimeout=10 $user\@$node "$sudo cat /etc/*release" | egrep -v "LSB_VERSION"`;
- my @results = split('\n', $out);
- return (xCAT::zvmUtils->trimStr($results[0]));
+ #my $out = `ssh -o ConnectTimeout=10 $user\@$node "$sudo cat /etc/*release" | egrep -v "LSB_VERSION"`;
+ my $cmd = $sudo . ' cat /etc/*release';
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
+ $out = `echo "$out" | egrep -a -i -v "LSB_VERSION"`;
+ my @results = split( '\n', $out );
+ return ( xCAT::zvmUtils->trimStr( $results[0] ) );
}
#-------------------------------------------------------
@@ -1233,14 +1532,14 @@ sub getOs {
Node
Returns : Architecture of node
Example : my $arch = xCAT::zvmUtils->getArch($user, $node);
-
+
=cut
#-------------------------------------------------------
sub getArch {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -1248,9 +1547,14 @@ sub getArch {
}
# Get host using VMCP
- my $arch = `ssh $user\@$node "$sudo uname -p"`;
+ #my $arch = `ssh $user\@$node "$sudo uname -m"`;
+ my $cmd = "$sudo uname -m";
+ my $arch = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $arch ) == -1) {
+ return $arch;
+ }
- return (xCAT::zvmUtils->trimStr($arch));
+ return ( xCAT::zvmUtils->trimStr($arch) );
}
#-------------------------------------------------------
@@ -1262,14 +1566,14 @@ sub getArch {
Profile name
Returns : User profile
Example : my $profile = xCAT::zvmUtils->getUserProfile($user, $hcp, $name);
-
+
=cut
#-------------------------------------------------------
sub getUserProfile {
# Get inputs
- my ($class, $user, $hcp, $profile) = @_;
+ my ( $class, $user, $hcp, $profile ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -1283,10 +1587,8 @@ sub getUserProfile {
# Set directory for cache
my $cache = '/var/opt/zhcp/cache';
-
# If the cache directory does not exist
if (!(`ssh $user\@$hcp "$sudo test -d $cache && echo Exists"`)) {
-
# Create cache directory
$out = `ssh $user\@$hcp "$sudo mkdir -p $cache"`;
}
@@ -1305,7 +1607,7 @@ sub getUserProfile {
# If the current time is greater than 5 minutes of the file timestamp
my $interval = 300; # 300 seconds = 5 minutes * 60 seconds/minute
- if ($curTime > $fileTime + $interval) {
+ if ( $curTime > $fileTime + $interval ) {
# Get user profiles and save it in a file
$out = `ssh $user\@$hcp "$sudo $hcpDir/smcli Profile_Query_DM -T $profile > $file"`;
@@ -1323,6 +1625,67 @@ sub getUserProfile {
#-------------------------------------------------------
+=head3 getVswitchIdsFromDirectory
+
+ Description : Get the nicdef switch names of a given node
+ Arguments : User (root or non-root)
+ zHCP
+ Userid
+ Returns : Vswitch names array or or string containing (Error)...
+ Example : my $vSwitchNamers = xCAT::zvmCPUtils->getVswitchIdsFromDirectory($user, $hcp, $userId);
+
+=cut
+
+#-------------------------------------------------------
+sub getVswitchIdsFromDirectory {
+
+ # Get inputs
+ my ( $class, $user, $hcp ,$userId ) = @_;
+
+ my $sudo = "sudo";
+ if ($user eq "root") {
+ $sudo = "";
+ }
+ my @vswitch;
+
+ # Get VSwitchs in directory
+ # only get lines that have SYSTEM switchname in them
+ # smcli Image_Definition_Query_DM -T xcat -k nicdef
+ # NICDEF=VDEV=0600 TYPE=QDIO LAN=SYSTEM SWITCHNAME=XCATVSW1
+ # NICDEF=VDEV=0700 TYPE=QDIO LAN=SYSTEM SWITCHNAME=XCATVSW2
+ #
+
+ my $outmsg;
+ my $rc;
+ xCAT::zvmUtils->printSyslog("Calling: ssh $user\@$hcp $sudo /opt/zhcp/bin/smcli Image_Definition_Query_DM -T $userId -k NICDEF | egrep -i 'SWITCHNAME'");
+ my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli Image_Definition_Query_DM -T $userId -k NICDEF"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo /opt/zhcp/bin/smcli Image_Definition_Query_DM -T $userId -k NICDEF\"", $hcp, "getVswitchIdsFromDirectory", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i 'SWITCHNAME'`;
+ # if there is nothing found, log that and return;
+ if ( !length($out) ) {
+ xCAT::zvmUtils->printSyslog("No SWITCHNAME found in NICDEF statement for userid $userId");
+ return (@vswitch);
+ }
+ xCAT::zvmUtils->printSyslog("$userId output: $out");
+ my @lines = split( '\n', $out );
+ my @parms;
+ my $vswitchToken = '';
+
+ foreach (@lines) {
+ @parms = split( ' ', $_ );
+ $vswitchToken = $parms[3];
+ @parms = split( '=', $vswitchToken );
+ push( @vswitch, $parms[1] );
+ }
+
+ return (@vswitch);
+}
+
+#-------------------------------------------------------
+
=head3 inArray
Description : Checks if a value exists in an array
@@ -1330,15 +1693,15 @@ sub getUserProfile {
Search array
Returns : The searched expression
Example : my $rtn = xCAT::zvmUtils->inArray($needle, @haystack);
-
+
=cut
#-------------------------------------------------------
sub inArray {
# Get inputs
- my ($class, $needle, @haystack) = @_;
- return grep { $_ eq $needle } @haystack;
+ my ( $class, $needle, @haystack ) = @_;
+ return grep{ $_ eq $needle } @haystack;
}
#-------------------------------------------------------
@@ -1347,54 +1710,352 @@ sub inArray {
Description : Get the operating system of a given node
Arguments : User (root or non-root)
- Node
- Returns : Operating system name
+ Node or IP Address
+ Callback handle (optional). Allows the routine,
+ to write error messages when SSH fails.
+ Returns : Operating system name & version as a single word.
+ Otherwise, an empty string.
Example : my $os = xCAT::zvmUtils->getOsVersion($user, $node);
-
+ my $os = xCAT::zvmUtils->getOsVersion($user, $node, $callback);
+
=cut
#-------------------------------------------------------
sub getOsVersion {
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node, $callback ) = @_;
+
+ my $osVer = '';
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
- my $os = '';
- my $version = '';
+ # Contact the system to extract the possible files which contain pertinent data.
+ #my $releaseInfo = `ssh -qo ConnectTimeout=2 $user\@$node "$sudo ls /dev/null $locAllEtcVerFiles 2>/dev/null | xargs grep ''"`;
+ my $cmd = $sudo . ' ls /dev/null '. $locAllEtcVerFiles . ' 2>/dev/null';
+ my $releaseInfo = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd);
+ if (xCAT::zvmUtils->checkOutput( $releaseInfo ) == -1) {
+ return '';
+ }
+ $releaseInfo = `echo "$releaseInfo" | xargs grep ''`;
+ $osVer = buildOsVersion( $callback, $releaseInfo, 'all' );
+
+ return $osVer;
+}
+
+#-------------------------------------------------------
+
+=head3 getOSFromIP
+
+ Description : Get the operating system name and
+ version for the system at the specified
+ IP Address.
+ Arguments : Callback handle
+ z/VM userid of the system
+ IP Address
+ Type of IP address (not currently used)
+ Returns : Operating system name & version as a single word.
+ Otherwise, an empty string.
+ Example : my $os = xCAT::zvmUtils->getOSFromIP( $callback, $userid, $ipAddr, $ipVersion };
+
+=cut
+
+#-------------------------------------------------------
+sub getOSFromIP {
+ my ( $class, $callback, $activeSystem, $ipAddr, $ipVersion ) = @_;
+
+ my $osVer = '';
+ my $rc = 0;
# Get operating system
- my $release = `ssh -o ConnectTimeout=2 $user\@$node "$sudo cat /etc/*release"`;
- my @lines = split('\n', $release);
- if (grep(/SUSE Linux Enterprise Server/, @lines)) {
- $os = 'sles';
- $version = `echo "$release" | grep "VERSION ="`;
- $version =~ s/\s*$//;
- $version =~ s/^\s*//;
- $version =~ tr/\.//;
- $version =~ s/[^0-9]*([0-9]+).*/$1/;
- $os = $os . $version;
-
- # Append service level
- $version = `echo "$release" | grep "LEVEL ="`;
- $version =~ s/\s*$//;
- $version =~ s/^\s*//;
- $version =~ tr/\.//;
- $version =~ s/[^0-9]*([0-9]+).*/$1/;
- $os = $os . 'sp' . $version;
- } elsif (grep(/Red Hat Enterprise Linux Server/, @lines)) {
- $os = 'rhel';
- $version = $lines[0];
- $version =~ tr/\.//;
- $version =~ s/([A-Za-z\s\(\)]+)//g;
- $os = $os . $version;
+ my $releaseInfo = `ssh -qo ConnectTimeout=2 $ipAddr "ls /dev/null $locAllEtcVerFiles 2>/dev/null"`;
+ $rc = $? >> 8;
+ if ( $rc == 0 ) {
+ $releaseInfo = `echo "$releaseInfo" | xargs grep ''`;
+ $osVer = buildOsVersion( $callback, $releaseInfo, 'all' );
+ } else {
+ if ( $callback ) {
+ # We have a callback so we can write an error message.
+ if ( $rc == 255 ) {
+ my $rsp;
+ push @{$rsp->{data}}, "Unable to communicate with $activeSystem at $ipAddr using ssh.";
+ xCAT::MsgUtils->message( "E", $rsp, $callback );
+ } else {
+ my $rsp;
+ push @{$rsp->{data}}, "Received an unexpected ssh return code $rc from $activeSystem at $ipAddr.";
+ xCAT::MsgUtils->message( "E", $rsp, $callback );
+ }
+ }
}
- return xCAT::zvmUtils->trimStr($os);
+ return $osVer;
+}
+
+#-------------------------------------------------------
+
+=head3 stripHeader
+
+ Description : Scans an input string to find only
+ lines that match a specified header string
+ and return an array of those lines without
+ the prefix.
+ Arguments : Multi-line string to scan
+ String to match
+ Returns : Array of matching lines.
+ Example : my @lines = stripHeader( $releaseInfo, '^/etc/os-release:' );
+ ($ver) = stripHeader( $releaseInfo, "^$locEtcUnitedLinux:" );
+
+=cut
+
+#-------------------------------------------------------
+sub stripHeader {
+ my ( $inputLines, $matchString ) = @_;
+ my @outputLines;
+
+ my @lines = split( /\n/, $inputLines );
+ foreach my $line ( @lines ){
+ if ( $line =~ m/$matchString/ ) {
+ $line =~ s/$matchString//g;
+ chomp $line;
+ if ( $line eq '' ) { next }
+ push @outputLines, $line;
+ }
+ }
+
+ return @outputLines;
+}
+
+
+#-------------------------------------------------------
+
+=head3 buildOsVersion
+
+ Description : Build the OS version string from the
+ provided data files.
+
+ Note: Only RHEL and SLES are supported
+ z/VM xCAT supported distributions.
+ This routine has code for other distributions
+ supported by common xCAT. If z/VM
+ ever supports another distribution
+ then we need to verify that the code
+ gets the correct version information.
+ Arguments : Callback (or undef)
+ Operating system data file(s) output
+ Type of data to return:
+ 'all' - $os$ver.$rel
+ 'all_comma' - $os,$ver.$rel
+ 'os' - $os
+ 'version' - $ver
+ 'release' - $rel
+ '' - $os$ver
+ Returns : Operating system name & version as a
+ single word.
+ Example : my $osVer = buildOsVersion( $callback, $releaseInfo, $type );
+
+=cut
+
+#-------------------------------------------------------
+sub buildOsVersion {
+ my $callback = shift;
+ my $releaseInfo = shift;
+ my $type = shift;
+
+ my $os = 'unknown'; # OS indicator, e.g. "rhel", "SLES"
+ my $ver = ''; # Version indicator, e.g. "7.1",
+ my $version = '';
+ my $rel = '';
+ my $line = '';
+ my @lines;
+
+ # Test strings that were used when we added the original support. These
+ # strings are what we used to simulate the other common Linux distros.
+ #$releaseInfo = "$locEtcSuseRelease:SUSE Linux Enterprise Server 11 (s390x)\n$locEtcSuseRelease:VERSION = 11\n$locEtcSuseRelease:PATCHLEVEL = 4.32";
+ #$releaseInfo = "$locEtcDebianVersion:1.0\n$locEtcIssue:debian release";
+ #$releaseInfo = "$locEtcUnitedLinux:2.1a";
+ #$releaseInfo = "$locEtcLsbRelease:Ubuntu\n$locEtcLsbRelease: DISTRIB_ID=Ubuntu\n$locEtcLsbRelease: DISTRIB_RELEASE=4.1";
+
+ my @relOut = split('\n', $releaseInfo);
+ if ( grep( /^$locEtcOsRelease:/, @relOut ) ) {
+ my $version = '';
+ my $version_id;
+ my $id;
+ my $id_like;
+ my $name;
+ my $prettyname;
+ my $verrel = '';
+
+ my @text = stripHeader( $releaseInfo, "^$locEtcOsRelease:" );
+ foreach my $line ( @text ) {
+ if ( $line =~ /^\s*VERSION=\"?([0-9\.]+).*/ ) {
+ $version = $1;
+ }
+ if($line =~ /^\s*VERSION_ID=\"?([0-9\.]+).*/){
+ $version_id = $1;
+ }
+
+ if ( $line =~ /^\s*Base release\s?([0-9\.]+).*/ ) {
+ $version = $1;
+ $id = 'BASE';
+ }
+
+ if ( $line =~ /^\s*ID=\"?([0-9a-z\_\-\.]+).*/ ) {
+ $id = $1;
+ }
+ if ( $line =~ /^\s*ID_LIKE=\"?([0-9a-z\_\-\.]+).*/ ) {
+ $id_like = $1;
+ }
+
+ if ( $line =~ /^\s*NAME=\"?(.*)/ ) {
+ $name = $1;
+ }
+ if($line =~ /^\s*PRETTY_NAME=\"?(.*)/){
+ $prettyname = $1;
+ }
+ }
+
+ $os = $id;
+ if ( !$os and $id_like ) {
+ $os = $id_like;
+ }
+
+ $verrel = $version;
+ if ( !$verrel and $version_id ) {
+ $verrel = $version_id;
+ }
+
+ if( !$name and $prettyname ){
+ $name = $prettyname;
+ }
+
+ # Note: xcat::Utils->osver() sets this value with an 's' but zvm.pm
+ # does not use it. So for now, we don't set 's'.
+ #if ( $os =~ /rhel/ and $name =~ /Server/i ) {
+ # # $os = "rhels";
+ #}
+
+ if ( $verrel =~ /([0-9]+)\.?(.*)/ ) {
+ $ver = $1;
+ $rel = $2;
+ }
+ } elsif ( grep( /^$locEtcRedhatRelease:/, @relOut ) ) {
+ my @text = stripHeader( $releaseInfo, "^$locEtcRedhatRelease:" );
+ my $line = $text[0];
+ chomp( $line );
+ $os = "rh";
+ my $verrel = $line;
+ $ver = $line;
+
+ if ( $type ) {
+ $verrel =~ s/[^0-9]*([0-9.]+).*/$1/;
+ ($ver,$rel) = split /\./, $verrel;
+ } else {
+ $ver=~ tr/\.//;
+ $ver =~ s/[^0-9]*([0-9]+).*/$1/;
+ }
+
+ if ( $line =~ /AS/ ) { $os = 'rhas' }
+ elsif ( $line =~ /ES/ ) { $os = 'rhes' }
+ elsif ( $line =~ /WS/ ) { $os = 'rhws' }
+ elsif ( $line =~ /Server/ ) {
+ if ( $type ) {
+ $os = 'rhel';
+ # Note: xcat::Utils->osver() sets this value with an 's' but zvm.pm
+ # does not use it. So for now, we don't set 's'.
+ #$os = 'rhels';
+ } else {
+ $os = 'rhserver';
+ }
+ } elsif ( $line =~ /Client/ ) {
+ if ( $type ) {
+ $os = 'rhel';
+ } else {
+ $os = 'rhclient';
+ }
+ } elsif ( grep( /$locEtcFedoraRelease:/, @relOut ) ) { $os = 'rhfc' }
+ } elsif ( grep( /^$locEtcSuseRelease:/, @relOut ) ) {
+ my @lines = stripHeader( $releaseInfo, "^$locEtcSuseRelease:" );
+ if ( grep /SLES|Enterprise Server/, @lines ) { $os = "sles" }
+ if ( grep /SLEC/, @lines ) { $os = "slec" }
+ $ver = $lines[0];
+ $ver =~ tr/\.//;
+ $ver =~ s/[^0-9]*([0-9]+).*/$1/;
+
+ $rel = $lines[2];
+ $rel =~ tr/\.//;
+ $rel =~ s/[^0-9]*([0-9]+).*/$1/;
+ } elsif ( grep( /^$locEtcUnitedLinux:/, @relOut ) ) {
+ # Note: Not a z/VM xCAT supported distribution.
+ # If we ever support this then we need to verify this code
+ # gets the correct version information.
+ ($ver) = stripHeader( $releaseInfo, "^$locEtcUnitedLinux:" );
+ $os = "ul";
+ $ver =~ tr/\.//;
+ $ver =~ s/[^0-9]*([0-9]+).*/$1/;
+ } elsif ( grep( /$locEtcLsbRelease:/, @relOut ) ) {
+ # Ubuntu release
+ my @text = stripHeader( $releaseInfo, "^$locEtcLsbRelease:" );
+ chomp( @text );
+ my $distrib_id = '';
+ my $distrib_rel = '';
+
+ foreach ( @text ) {
+ if ( $_ =~ /^\s*DISTRIB_ID=(.*)$/ ) {
+ $distrib_id = $1; # last DISTRIB_ID value in file used
+ } elsif ( $_ =~ /^\s*DISTRIB_RELEASE=(.*)$/ ) {
+ $distrib_rel = $1; # last DISTRIB_RELEASE value in file used
+ }
+ }
+
+ if ( $distrib_id =~ /^(Ubuntu|"Ubuntu")\s*$/ ) {
+ $os = "ubuntu";
+
+ if ( $distrib_rel =~ /^(.*?)\s*$/ ) { # eliminate trailing blanks, if any
+ $distrib_rel = $1;
+ }
+ if ( $distrib_rel =~ /^"(.*?)"$/ ) { # eliminate enclosing quotes, if any
+ $distrib_rel = $1;
+ }
+ $ver = $distrib_rel;
+ }
+ } elsif ( grep( /^$locEtcDebianVersion:/, @relOut ) ) {
+ # Debian release
+ if ( grep( /^$locEtcIssue:/, @relOut ) ) {
+ ($line) = stripHeader( $releaseInfo, "^$locEtcIssue:" );
+ if ( $line =~ /debian.*/i ) {
+ $os = "debian";
+ ($ver) = stripHeader( $releaseInfo, "^$locEtcDebianVersion:" );
+ }
+ }
+ }
+
+ my $outString = '';
+ if ( $type eq 'all_comma' ) {
+ if ( $rel ne "") {
+ $outString = "$os,$ver.$rel";
+ } else {
+ $outString = "$os,$ver";
+ }
+ } elsif ( $type eq 'all' ) {
+ if ( $rel ne "") {
+ $outString = "$os$ver.$rel";
+ } else {
+ $outString = "$os$ver";
+ }
+ } elsif ( $type eq 'os' ) {
+ $outString = $os;
+ } elsif ( $type eq 'version' ) {
+ $outString = $ver;
+ } elsif ( $type eq 'release' ) {
+ $outString = $os;
+ } else {
+ $outString = "$os$ver";
+ }
+
+ return $outString;
}
#-------------------------------------------------------
@@ -1406,14 +2067,13 @@ sub getOsVersion {
Node
Returns : zFCP device info
Example : my $info = xCAT::zvmUtils->getZfcpInfo($user, $node);
-
+
=cut
#-------------------------------------------------------
sub getZfcpInfo {
-
# Get inputs
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -1421,14 +2081,22 @@ sub getZfcpInfo {
}
# Get zFCP device info
- my $info = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/lszfcp -D"`;
+ #my $info = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/lszfcp -D"`;
+ my $cmd = "$sudo /sbin/lszfcp -D";
+ my $info = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ # will not check for connection errors here
my @zfcp = split("\n", $info);
if (!$info || $info =~ m/No zfcp support/i || $info =~ m/No fcp devices found/i) {
return;
}
# Get SCSI device and their attributes
- my $scsi = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /usr/bin/lsscsi"`;
+ #my $scsi = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /usr/bin/lsscsi"`;
+ $cmd = "$sudo /usr/bin/lsscsi";
+ my $scsi = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $info ) == -1) {
+ return $info;
+ }
$info = "";
my @args;
@@ -1441,16 +2109,16 @@ sub getZfcpInfo {
foreach (@zfcp) {
@args = split(" ", $_);
- $id = $args[1];
+ $id = $args[1];
@args = split("/", $args[0]);
$device = $args[0];
- $wwpn = $args[1];
- $lun = $args[2];
+ $wwpn = $args[1];
+ $lun = $args[2];
# Make sure WWPN and LUN do not have 0x prefix
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
- $lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
+ $lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
# Find the device name
$tmp = `echo "$scsi" | egrep -i $id`;
@@ -1458,7 +2126,13 @@ sub getZfcpInfo {
chomp($tmp);
# Find the size in MiB
- $size = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /usr/bin/sg_readcap $tmp" | egrep -i "Device size:"`;
+ #$size = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /usr/bin/sg_readcap $tmp" | egrep -i "Device[[:space:]]size:"`;
+ my $cmd = $sudo . ' /usr/bin/sg_readcap ' . $tmp;
+ $size = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $size ) == -1) {
+ return $size;
+ }
+ $size = `echo "$size" | egrep -a -i "Device[[:space:]]size:"`;
$size =~ s/Device size: //g;
@args = split(",", $size);
$size = xCAT::zvmUtils->trimStr($args[1]);
@@ -1479,19 +2153,19 @@ sub getZfcpInfo {
Returns : 1 Node exists
0 Node does not exists
Example : my $out = xCAT::zvmUtils->isHypervisor($node);
-
+
=cut
#-------------------------------------------------------
sub isHypervisor {
# Get inputs
- my ($class, $node) = @_;
+ my ( $class, $node ) = @_;
# Look in 'zvm' table
- my $tab = xCAT::Table->new("hypervisor", -create => 1, -autocommit => 0);
+ my $tab = xCAT::Table->new( "hypervisor", -create => 1, -autocommit => 0 );
- my @results = $tab->getAllAttribsWhere("node like '%" . $node . "%'", 'type');
+ my @results = $tab->getAllAttribsWhere( "node = '" . $node . "'", 'type' );
foreach (@results) {
# Return 'TRUE' if given node is in the table
@@ -1503,6 +2177,37 @@ sub isHypervisor {
return 0;
}
+#-------------------------------------------------------
+
+=head3 isOSVerSupported
+
+ Description : Determine if the specified OS version supported.
+ Arguments : OS version string (e.g. RHEL6, RHEL6.1, SLES11sp2)
+ Returns : 1 - version is supported
+ 0 - version is not supported
+ Example : my $supported = xCAT::zvmUtils->isOSVerSupported( $os );
+
+=cut
+
+#-------------------------------------------------------
+sub isOSVerSupported {
+ my ( $class, $osVer ) = @_;
+
+ # Keep just the OS distro name and the version, ie. drop any release info.
+ $osVer = lc( $osVer );
+ if ( $osVer =~ /([a-z]+[0-9]+)/ ) {
+ $osVer = $1;
+ }
+
+ # Check against our list of supported versions.
+ if ( $supportedVersions{$osVer} ) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
#-------------------------------------------------------
=head3 getSudoer
@@ -1512,18 +2217,17 @@ sub isHypervisor {
Returns : Sudoer user name
Sudo keyword
Example : my ($sudoer, $sudo) = xCAT::zvmUtils->getSudoer();
-
+
=cut
#-------------------------------------------------------
sub getSudoer {
-
# Get inputs
- my ($class) = @_;
+ my ( $class ) = @_;
# Use sudo or not on zHCP
my @propNames = ('username');
- my $propVals = xCAT::zvmUtils->getTabPropsByKey('passwd', 'key', 'sudoer', @propNames);
+ my $propVals = xCAT::zvmUtils->getTabPropsByKey( 'passwd', 'key', 'sudoer', @propNames );
my $sudo = "sudo";
my $user = $propVals->{'username'};
@@ -1549,12 +2253,12 @@ sub getSudoer {
Returns : vdev An address which is free to use
-1 No free address is left
Example : my $vdev = xCAT::zvmUtils->getFreeAddress($user, $node, $type);
-
+
=cut
#-------------------------------------------------------
sub getFreeAddress {
- my ($class, $user, $node, $type) = @_;
+ my ( $class, $user, $node, $type ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -1566,43 +2270,47 @@ sub getFreeAddress {
my $freeAddressHex = sprintf('%04X', $freeAddress);
# All device type names in VM, do not contain CPU
- my $deviceTypesVm = 'CONS|CTCA|DASD|FCP|GRAF|LINE|MSGD|OSA|PRT|PUN|RDR|SWCH|TAPE';
-
+ #my $deviceTypesVm = 'CONS|CTCA|DASD|FCP|GRAF|LINE|MSGD|OSA|PRT|PUN|RDR|SWCH|TAPE';
+ my $deviceTypesVm = '^CONS|^CTCA|^DASD|^FCP|^GRAF|^LINE|^MSGD|^OSA|^PRT|^PUN|^RDR|^SWCH|^TAPE';
# All device type names in user directory, do not contain CPU
my $deviceTypesUserDir = 'CONSOLE|MDISK|NICDEF|SPOOL|RDEVICE';
+
# Search for all address that is in use
my $allUsedAddr;
if ($type eq 'vmcp') {
-
# When the node is up, vmcp can be used
- $allUsedAddr = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q v all | awk '$1 ~/^($deviceTypesVm)/ {print $2}' | sort"`;
+ #$allUsedAddr = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q v all | awk '\$1 ~/^($deviceTypesVm)/ {print \$2}' | sort"`;
+ my $cmd = $sudo . '/sbin/vmcp q v all';
+ my $allUsedAddr = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $allUsedAddr ) == -1) {
+ return -1;
+ }
+ $allUsedAddr = `echo '$allUsedAddr' | egrep -a -i "$deviceTypesVm"`;
} else {
-
# When the node is down, use zHCP to get its user directory entry
# Get HCP
my @propNames = ('hcp', 'userid');
- my $propVals = xCAT::zvmUtils->getNodeProps('zvm', $node, @propNames);
+ my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
my $hcp = $propVals->{'hcp'};
# Get node userID
my $userId = $propVals->{'userid'};
# Get user directory entry
- my $userDirEntry = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $userId"'`;
+ my $userDirEntry = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $userId"`;
# Get profile if user directory entry include a profile
if ($userDirEntry =~ "INCLUDE ") {
- my $profileName = `cat $userDirEntry | awk '$1 ~/^(INCLUDE)/ {print $2}`;
+ my $profileName = `cat $userDirEntry | awk '\$1 ~/^(INCLUDE)/ {print \$2}'`;
$profileName = xCAT::zvmUtils->trimStr($profileName);
$userDirEntry .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $profileName"`;
}
# Get all defined device address
- $allUsedAddr = `cat $userDirEntry | awk '$1 ~/^($deviceTypesUserDir)/ {print $2}' | sort`;
-
+ $allUsedAddr = `cat $userDirEntry | awk '\$1 ~/^($deviceTypesUserDir)/ {print \$2}' | sort`;
# Get all linked device address
- $allUsedAddr .= `cat $userDirEntry | awk '$1 ~/^(LINK)/ {print $4}' | sort`;
+ $allUsedAddr .= `cat $userDirEntry | awk '\$1 ~/^(LINK)/ {print \$4}' | sort`;
}
# Loop to get the lowest free address
@@ -1626,14 +2334,14 @@ sub getFreeAddress {
Arguments : User (root or non-root)
zHCP (to query on)
node
- Returns : In nanoseconds for used CPU time
+ Returns : In nanoseconds for used CPU time or string containing (Error)...
Example : my $out = xCAT::zvmUtils->getUsedCpuTime($hcp, $node);
-
+
=cut
#-------------------------------------------------------
sub getUsedCpuTime {
- my ($class, $user, $hcp, $node) = @_;
+ my ( $class, $user, $hcp , $node ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
@@ -1646,7 +2354,14 @@ sub getUsedCpuTime {
my $userId = xCAT::zvmCPUtils->getUserId($user, $node);
# Call IUO function to query CPU used time
- my $time = `ssh $user\@$hcp "$sudo $dir/smcli Image_Performance_Query -T $userId -c 1" | egrep -i "Used CPU time:"`;
+ my $outmsg;
+ my $rc;
+ my $time = `ssh $user\@$hcp "$sudo $dir/smcli Image_Performance_Query -T $userId -c 1"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo $dir/smcli Image_Performance_Query -T $userId -c 1\"", $hcp, "getUsedCpuTime", $time, $node );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $time = `echo "$time" | egrep -a -i "Used CPU time:"`;
$time =~ s/^Used CPU time:(.*)/$1/;
$time =~ s/"//g;
$time =~ s/^\s+//;
@@ -1669,30 +2384,33 @@ sub getUsedCpuTime {
Node
Returns : Running time
Example : my $out = xCAT::zvmUtils->getUpTime($user, $node);
-
+
=cut
#-------------------------------------------------------
sub getUpTime {
- my ($class, $user, $node) = @_;
+ my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
- my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo uptime"`;
+ #my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo uptime"`;
+ my $cmd = "$sudo uptime";
+ my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
+ if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
+ return $out;
+ }
$out = xCAT::zvmUtils->trimStr($out);
$out =~ /.*up +(?:(\d+) days?,? +)?(\d+):(\d+),.*/;
my $uptime;
if (!$1 && !$2) {
-
# Special case for less than 1 hour, will display X min
$out =~ /.*up +(\d+) min,.*/;
$uptime = "0 days $3 min";
} elsif (!$1) {
-
# Special case for less than 1 day, will display X hr X min
$uptime = "0 days $2 hr $3 min";
} else {
@@ -1710,24 +2428,22 @@ sub getUpTime {
Arguments : Bytes
Returns : Size string
Example : my $out = xCAT::zvmUtils->getSizeFromByte($bytes);
-
+
=cut
#-------------------------------------------------------
sub getSizeFromByte {
- my ($class, $bytes) = @_;
+ my ( $class, $bytes ) = @_;
- my $size = ($bytes) / (1024 * 1024);
- if ($size > (1024 * 5)) {
+ my $size = ($bytes)/(1024*1024);
+ if ($size > (1024*5)) {
$size = ($size / 1024);
-
# If the size > 5G, will use G to represent
- $size = sprintf("%.1f", $size);
+ $size = sprintf("%.1f",$size);
$size = $size . 'G';
} else {
-
# If the size < 5G, will use M to represent
- $size = sprintf("%d", $size);
+ $size = sprintf("%d",$size);
$size = $size . 'M';
}
@@ -1743,7 +2459,7 @@ sub getSizeFromByte {
Arguments : Node
Returns : Size string
Example : my $out = xCAT::zvmUtils->getSizeFromCyl($cyl);
-
+
=cut
#-------------------------------------------------------
@@ -1751,7 +2467,7 @@ sub getSizeFromCyl {
my ($class, $cyl) = @_;
my $bytes = ($cyl * 737280);
- my $size = xCAT::zvmUtils->getSizeFromByte($bytes);
+ my $size = xCAT::zvmUtils->getSizeFromByte($bytes);
return ($size);
}
@@ -1764,15 +2480,15 @@ sub getSizeFromCyl {
Arguments : Page
Returns : Size string
Example : my $out = xCAT::zvmUtils->getSizeFromPage($page);
-
+
=cut
#-------------------------------------------------------
sub getSizeFromPage {
- my ($class, $page) = @_;
+ my ( $class, $page ) = @_;
my $bytes = ($page * 4096);
- my $size = xCAT::zvmUtils->getSizeFromByte($bytes);
+ my $size = xCAT::zvmUtils->getSizeFromByte($bytes);
return ($size);
}
@@ -1785,9 +2501,9 @@ sub getSizeFromPage {
Description : Get total count of logical CPUs in the LPAR
Arguments : User (root or non-root)
zHCP
- Returns : Total CPU count
+ Returns : Total CPU count or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getLparCpuTotal($user, $hcp);
-
+
=cut
#-------------------------------------------------------
@@ -1799,7 +2515,14 @@ sub getLparCpuTotal {
$sudo = "";
}
- my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo" | grep "LPAR CPUs Total"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo cat /proc/sysinfo\"", $hcp, "getLparCpuTotal", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "LPAR CPUs Total"`;
my @results = split(' ', $out);
return ($results[3]);
@@ -1812,9 +2535,9 @@ sub getLparCpuTotal {
Description : Get count of used logical CPUs in the LPAR
Arguments : User (root or non-root)
zHCP
- Returns : Used CPU count
+ Returns : Used CPU count or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getLparCpuUsed($user, $hcp);
-
+
=cut
#-------------------------------------------------------
@@ -1826,7 +2549,14 @@ sub getLparCpuUsed {
$sudo = "";
}
- my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo" | grep "LPAR CPUs Configured"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo cat /proc/sysinfo\"", $hcp, "getLparCpuUsed", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "LPAR CPUs Configured"`;
my @results = split(' ', $out);
return ($results[3]);
@@ -1839,9 +2569,9 @@ sub getLparCpuUsed {
Description : Get the model of this CEC (LPAR)
Arguments : User (root or non-root)
zHCP
- Returns : Model of this CEC
+ Returns : Model of this CEC or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getCecModel($user, $hcp);
-
+
=cut
#-------------------------------------------------------
@@ -1853,7 +2583,14 @@ sub getCecModel {
$sudo = "";
}
- my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo" | grep "^Type:"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo cat /proc/sysinfo\"", $hcp, "getCecModel", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "^Type:"`;
my @results = split(' ', $out);
return ($results[1]);
@@ -1866,21 +2603,28 @@ sub getCecModel {
Description : Get the vendor of this CEC (LPAR)
Arguments : User (root or non-root)
zHCP
- Returns : Vendor of this CEC
+ Returns : Vendor of this CEC or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getCecVendor($user, $hcp);
-
+
=cut
#-------------------------------------------------------
sub getCecVendor {
- my ($class, $user, $hcp) = @_;
+ my ( $class, $user, $hcp ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
- my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo" | grep "Manufacturer"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo cat /proc/sysinfo\"", $hcp, "getCecVendor", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "Manufacturer"`;
my @results = split(' ', $out);
return ($results[1]);
@@ -1893,9 +2637,9 @@ sub getCecVendor {
Description : Get the info(name & version) for this hypervisor
Arguments : User (root or non-root)
zHCP
- Returns : Name & version of this hypervisor
+ Returns : Name & version of this hypervisor or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getHypervisorInfo($user, $hcp);
-
+
=cut
#-------------------------------------------------------
@@ -1907,7 +2651,14 @@ sub getHypervisorInfo {
$sudo = "";
}
- my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo" | grep "VM00 Control Program"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo cat /proc/sysinfo\"", $hcp, "getHypervisorInfo", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "VM00 Control Program"`;
my @results = split(' ', $out);
my $str = "$results[3] $results[4]";
@@ -1922,9 +2673,9 @@ sub getHypervisorInfo {
Description : Get the total physical memory of this LPAR
Arguments : User (root or non-root)
zHCP
- Returns : Total physical memory
+ Returns : Total physical memory or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getLparMemoryTotal($user, $hcp);
-
+
=cut
#-------------------------------------------------------
@@ -1936,7 +2687,14 @@ sub getLparMemoryTotal {
$sudo = "";
}
- my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Info_Query" | grep "real storage"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Info_Query"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo /opt/zhcp/bin/smcli System_Info_Query\"", $hcp, "getLparMemoryTotal", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "real storage"`;
my @results = split(' ', $out);
return ($results[5]);
@@ -1949,9 +2707,9 @@ sub getLparMemoryTotal {
Description : Get the offline physical memory of this LPAR
Arguments : User (root or non-root)
zHCP
- Returns : Offline physical memory
+ Returns : Offline physical memory or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getLparMemoryOffline($user, $hcp);
-
+
=cut
#-------------------------------------------------------
@@ -1963,7 +2721,14 @@ sub getLparMemoryOffline {
$sudo = "";
}
- my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Info_Query" | grep "real storage"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Info_Query"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo /opt/zhcp/bin/smcli System_Info_Query\"", $hcp, "getLparMemoryOffline", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "real storage"`;
my @results = split(' ', $out);
return ($results[14]);
@@ -1976,9 +2741,9 @@ sub getLparMemoryOffline {
Description : Get the used physical memory of this LPAR
Arguments : User (root or non-root)
zHCP
- Returns : Used physical memory
+ Returns : Used physical memory or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getLparMemoryUsed($user, $hcp);
-
+
=cut
#-------------------------------------------------------
@@ -1990,11 +2755,18 @@ sub getLparMemoryUsed {
$sudo = "";
}
- my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Performance_Info_Query " | grep "Used memory pages:"`;
+ my $outmsg;
+ my $rc;
+ my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Performance_Info_Query "`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo /opt/zhcp/bin/smcli System_Performance_Info_Query \"", $hcp, "getLparMemoryUsed", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $out = `echo "$out" | egrep -a -i "Used memory pages:"`;
my @results = split(':', $out);
- my $page = xCAT::zvmUtils->trimStr($results[1]);
- my $size = xCAT::zvmUtils->getSizeFromPage($page);
+ my $page = xCAT::zvmUtils->trimStr( $results[1] );
+ my $size = xCAT::zvmUtils->getSizeFromPage( $page );
return ($size);
}
@@ -2003,13 +2775,13 @@ sub getLparMemoryUsed {
=head3 getDiskPoolUsed
- Description : Get the used size of specified disk pool
+ Description : Get the used size of specified disk pool
Arguments : User (root or non-root)
zHCP
Disk pool
- Returns : Used size of specified disk pool
+ Returns : Used size of specified disk pool
Example : my $out = xCAT::zvmCPUtils->getDiskPoolUsed($user, $hcp, $diskpool);
-
+
=cut
#-------------------------------------------------------
@@ -2031,9 +2803,8 @@ sub getDiskPoolUsed {
foreach (@lines) {
@results = split(' ', $_);
if ($results[1] =~ '^9336') {
-
# Change the format from blocks (512 byte) to cylinder (737280)
- my $cyls = ($results[3] * 512) / (737280);
+ my $cyls = ($results[3] * 512)/(737280);
$used += $cyls;
} elsif ($results[1] =~ '^3390') {
$used += $results[3];
@@ -2047,13 +2818,13 @@ sub getDiskPoolUsed {
=head3 getDiskPoolFree
- Description : Get the free size of specified disk pool
+ Description : Get the free size of specified disk pool
Arguments : User (root or non-root)
- zHCP
+ zHCP
Disk pool
- Returns : Free size of specified disk pool
+ Returns : Free size of specified disk pool
Example : my $out = xCAT::zvmCPUtils->getDiskPoolFree($user, $hcp, $diskpool);
-
+
=cut
#-------------------------------------------------------
@@ -2075,9 +2846,8 @@ sub getDiskPoolFree {
foreach (@lines) {
@results = split(' ', $_);
if ($results[1] =~ '^9336') {
-
# Change the format from blocks (512 byte) to cylinder (737280)
- my $cyls = ($results[3] * 512) / (737280);
+ my $cyls = ( $results[3] * 512 ) / ( 737280 );
$free += $cyls;
} elsif ($results[1] =~ '^3390') {
$free += $results[3];
@@ -2093,23 +2863,23 @@ sub getDiskPoolFree {
Description : Get the max memory of a given node
Arguments : User (root or non-root)
- zHCP
+ zHCP
Node
Returns : Max memory
Example : my $maxMemory = xCAT::zvmCPUtils->getMaxMemory($user, $hcp, $node);
-
+
=cut
#-------------------------------------------------------
sub getMaxMemory {
- my ($class, $user, $hcp, $node) = @_;
+ my ($class, $user, $hcp , $node) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
- my $userId = xCAT::zvmCPUtils->getUserId($user, $node);
+ my $userId = xCAT::zvmCPUtils->getUserId( $user, $node );
# Query the maximum memory allowed in user directory entry
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli Image_Definition_Query_DM -T $userId -k STORAGE_MAXIMUM"`;
@@ -2118,6 +2888,436 @@ sub getMaxMemory {
return ($results[1]);
}
+
+#-------------------------------------------------------
+
+=head3 handlePowerUp
+
+ Description : Handle power up of nodes whose IP information
+ may change on power up. The routine will weed out
+ non-s390x architectures and do processing for nodes whose
+ status in the zvm table is "POWER_UP=1".
+ Arguments : Callback
+ Nodes that are to be handled.
+ Returns : None
+ Example : xCAT::zvmUtils->handlePowerUp( $callback, $nodes, \%args );
+
+=cut
+
+#-------------------------------------------------------
+sub handlePowerUp {
+ my ( $class, $callback, $nodes, $argsRef ) = @_;
+ my %propHash; # Property hash used to fill in various tables
+ my %sysInfo; # Hash to hold system information
+ my %args = %$argsRef; # Command arguments, verbose is one such operand
+
+ my $nodetypeTab = xCAT::Table->new('nodetype');
+ my $nodetypeHash = $nodetypeTab->getNodesAttribs( $nodes, ['arch'] );
+ my $zvmTab = xCAT::Table->new('zvm');
+ my $zvmHash = $zvmTab->getNodesAttribs( $nodes, ['hcp', 'status', 'userid'] );
+
+ foreach my $node ( keys %{$nodetypeHash} ) {
+ next if ( $nodetypeHash->{$node}->[0]->{'arch'} !~ 's390x' );
+ my $status = $zvmHash->{$node}->[0]->{'status'};
+ if ( $status =~ 'POWER_UP=1' ) {
+ my $userid = $zvmHash->{$node}->[0]->{'userid'};
+ my $rc = xCAT::zvmUtils->findAccessIP( $callback,
+ $userid,
+ $zvmHash->{$node}->[0]->{'hcp'},
+ \%sysInfo,
+ \%args );
+ if ( $rc == 0 ) {
+ # Got what we needed so we can update tables with the current information.
+ if ( $args{'verbose'} == 1 ) {
+ my $rsp;
+ push @{$rsp->{data}}, "Updating xCAT tables with IP information for $node:\n" .
+ " ip: $sysInfo{$userid}{'ipAddr'}, hostname: $sysInfo{$userid}{'hostname'}\n".
+ " macAddr: $sysInfo{$userid}{'macAddr'}, switch: $sysInfo{$userid}{'switch'}\n".
+ " Network Adapter VDEV: $sysInfo{$userid}{'adapterAddr'}";
+ xCAT::MsgUtils->message( "I", $rsp, $callback );
+ }
+
+ substr( $sysInfo{$userid}{'macAddr'}, 10, 0 ) = ':';
+ substr( $sysInfo{$userid}{'macAddr'}, 8, 0 ) = ':';
+ substr( $sysInfo{$userid}{'macAddr'}, 6, 0 ) = ':';
+ substr( $sysInfo{$userid}{'macAddr'}, 4, 0 ) = ':';
+ substr( $sysInfo{$userid}{'macAddr'}, 2, 0 ) = ':';
+ %propHash = (
+ 'disable' => 0,
+ 'interface' => $sysInfo{$userid}{'vdev'},
+ 'mac' => $sysInfo{$userid}{'macAddr'},
+ );
+ xCAT::zvmUtils->setNodeProps( 'mac', $node, \%propHash );
+
+ %propHash = (
+ 'disable' => 0,
+ 'hostnames' => $sysInfo{$userid}{'hostname'},
+ 'ip' => $sysInfo{$userid}{'ipAddr'},
+ );
+ xCAT::zvmUtils->setNodeProps( 'hosts', $node, \%propHash );
+
+ $status =~ s/POWER_UP=1/POWER_UP=0/g;
+ %propHash = (
+ 'status' => $status,
+ );
+ xCAT::zvmUtils->setNodeProps( 'zvm', $node, \%propHash );
+
+ my $out = `/opt/xcat/sbin/makehosts $node 2>&1`;
+ if ( $out ne '' ) {
+ my $rsp;
+ push @{$rsp->{data}}, "'makehosts' failed for $node. " .
+ "'makehosts' response: $out";
+ xCAT::MsgUtils->message( "E", $rsp, $callback );
+ }
+
+ # Inform OpenStack of the hostname.
+ if ( -e $locOpenStackUpdateName ) {
+ # Call the python change instance name command
+ my $renamed = 0;
+ my $args = "--nodename $node --hostname $sysInfo{$userid}{'hostname'}";
+ xCAT::MsgUtils->message( "S", "Invoking $locOpenStackUpdateName $args" );
+ my $out = `python $locOpenStackUpdateName $args`;
+ xCAT::MsgUtils->message( "S", "Returned from OpenStack node name update for $node with $out" );
+ if ( $out ) {
+ if ( $out =~ m/^Success!/ ) {
+ $renamed = 1;
+ if ( $args{'verbose'} == 1 ) {
+ my $rsp;
+ push @{$rsp->{data}}, "Renamed the OpenStack instance.";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ }
+ }
+ }
+
+ if ( !$renamed ) {
+ # Return an information message but do not fail the nodeset with an error
+ # message. This error is minor to the overall operation.
+ my $rsp;
+ push @{$rsp->{data}}, "Unable to update the OpenStack node name: $node";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ }
+ }
+ } else {
+ my $rsp;
+ push @{$rsp->{data}}, "Did not find sufficient IP information for $node.";
+ xCAT::MsgUtils->message( "I", $rsp, $callback );
+ }
+ }
+ }
+}
+
+
+#-------------------------------------------------------
+
+=head3 findAccessIP
+
+ Description : Obtain TCP/IP and hostname information about
+ the virtual machine related to the node.
+ Arguments : Callback in case we want to produce a message
+ Virtual machine userid
+ ZHCP node handling the z/VM host node
+ Hash to contain information on the system
+ Command invocation argument hash. 'ipfilter' and
+ 'verbose' keys are used in this routine.
+ SUDO issuer ($sudoer) or 'root' user for the SSH into ZHCP.
+ This parameter avoids the call to getsudoer() to obtain
+ the sudo and sudoer value. 'root' user does not use 'sudo'.
+ Returns : 0 - No error
+ non-zero - Error detected or filtered out as a usable IP address
+ Example : $rc = findAccessIP( $callback, 'linux001', $hcp
+ \%sysInfo, \%args );
+
+=cut
+
+#-------------------------------------------------------
+sub findAccessIP
+{
+ my $class = shift; # Perl class
+ my $callback = shift; # Callback for messaging
+ my $activeSystem = shift; # Userid of the system being queried
+ my $hcp = shift; # HCP
+ my $sysInfoRef = shift; # Hash reference for system IP information
+ my $argsRef = shift; # Command arguments, verbose, ipFilter
+ my %args = %$argsRef; # Access hash for easier reference
+ my $sudoer = shift; # SUDO issuer
+
+ my %adapter; # Adapter hash info, used mainly for verbose processing
+ my @failureInfo; # Information on IP contact failures
+ my $hostname = ''; # Hostname from the target node
+ my @hostnameCmds = ( # List of host name resolution commands to be issued in a virtual OS.
+ 'hostname --fqdn',
+ 'hostname --long',
+ 'hostname',
+ );
+ my %ips; # Hash of IP info obtained from the various calls
+ my $out; # Output buffer work area
+ my $rc; # Return code
+ my $rsp; # Message work buffer
+ my $sudo = ''; # Assume we are not going to use SUDO on ZHCP call.
+
+ # Use sudo or not
+ if ( $sudoer eq '' ) {
+ # Looks in the passwd table for a key = sudoer.
+ ($sudoer, $sudo) = xCAT::zvmUtils->getSudoer();
+ } elsif ( $sudoer ne 'root' ) {
+ # Non-root user specified so we will invoke 'sudo' on the SSH call to ZHCP.
+ $sudo = 'sudo';
+ }
+
+ # Get the list of IP addresses currently in use by the virtual machine.
+ $out = `ssh -q $sudoer\@$hcp $sudo /opt/zhcp/bin/smcli "Virtual_Network_Adapter_Query_Extended -T '$activeSystem' -k 'image_device_number=*'"`;
+ $rc = $? >> 8;
+ if ($rc == 255) {
+ push @{$rsp->{data}}, "Unable to communicate with the zhcp system: $hcp";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ goto FINISH_findAccessIP;
+ } elsif ( $rc == 1 ) {
+ my ( $smcliRC, $smcliRS, $smcliDesc );
+ my $errorOut = `echo "$out" | egrep -i '(^ Return Code: |^ Reason Code: |^ Description: )'`;
+ my @errorLines = split( "\n", $errorOut );
+ foreach my $errorLine ( @errorLines ) {
+ if ( $errorLine =~ /^ Return Code: / ) {
+ ($smcliRC) = $errorLine =~ /^ Return Code: (.*)/;
+ }
+ if ( $errorLine =~ /^ Reason Code: / ) {
+ ($smcliRS) = $errorLine =~ /^ Reason Code: (.*)/;
+ }
+ if ( $errorLine =~ /^ Description: / ) {
+ ($smcliDesc) = $errorLine =~ /^ Description: (.*)/;
+ }
+ }
+ if (( $smcliRC == 212 ) && ( $smcliRS == 8 )) {
+ if ( $args{'verbose'} == 1 ) {
+ push @{$rsp->{data}}, "For userid $activeSystem, the virtual machine does not have any network adapters.";
+ xCAT::MsgUtils->message( "I", $rsp, $callback );
+ }
+ push @failureInfo, "The virtual machine does not have any network adapters";
+ goto FINISH_findAccessIP;
+ } else {
+ push @{$rsp->{data}}, "An unexpected return code $smcliRC and reason code $smcliRS was received from " .
+ "the zhcp server $hcp for an smcli Virtual_Network_Adapter_Query_Extended " .
+ "request. Error description: $smcliDesc";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ goto FINISH_findAccessIP;
+ }
+
+ } elsif ( $rc != 0 ) {
+ push @{$rsp->{data}}, "An unexpected return code $rc was received from " .
+ "the zhcp server $hcp for an smcli Virtual_Network_Adapter_Query_Extended " .
+ "request. SMAPI servers may be unavailable. " .
+ "Received response: $out";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ goto FINISH_findAccessIP;
+ }
+
+ my $filteredOut = `echo "$out" | egrep -i '(adapter_address=|adapter_status=|mac_address=|mac_ip_address=|mac_ip_version=|lan_name=|lan_owner=)'`;
+ my @ipOut = split( "\n", $filteredOut );
+ my ($adapterAddr, $adapterStatus, $ipAddr, $ipVersion, $lanName, $lanOwner, $macAddr );
+ foreach my $ipLine ( @ipOut ) {
+ if ( $ipLine =~ /adapter_address=/ ) {
+ ($adapterAddr) = $ipLine =~ /adapter_address=(.*)/;
+ $adapter{$adapterAddr}{'ipCnt'} = 0;
+ $adapter{$adapterAddr}{'macCnt'} = 0;
+ ($lanName, $lanOwner) = '';
+ } elsif ( $ipLine =~ /adapter_status=/ ) {
+ ($adapterStatus) = $ipLine =~ /adapter_status=(.*)/;
+ $adapter{$adapterAddr}{'status'} = $adapterStatus;
+ } elsif ( $ipLine =~ /^lan_name=/ ) {
+ ($lanName) = $ipLine =~ /lan_name=(.*)/;
+ #} elsif ( $ipLine =~ /^lan_owner=/ ) {
+ # ($lanOwner) = $ipLine =~ /lan_owner=(.*)/;
+ } elsif ( $ipLine =~ /^mac_address=/ ) {
+ ($macAddr) = $ipLine =~ /mac_address=(.*)/;
+ ($ipVersion, $ipAddr) = '';
+ $adapter{$adapterAddr}{'macCnt'} += 1;
+ } elsif ( $ipLine =~ /^mac_ip_address=/ ) {
+ ($ipAddr) = $ipLine =~ /mac_ip_address=(.*)/;
+ } elsif ( $ipLine =~ /^mac_ip_version=/ ) {
+ ($ipVersion) = $ipLine =~ /mac_ip_version=(.*)/;
+ }
+ if ( $ipVersion ne '' and $ipAddr ne '' ) {
+ $ips{$ipAddr}{'adapterAddr'} = $adapterAddr;
+ $ips{$ipAddr}{'ipVersion'} = $ipVersion;
+ $ips{$ipAddr}{'lanName'} = $lanName if $lanName;
+ #$ips{$ipAddr}{'lanOwner'} = $lanOwner if $lanOwner;
+ $ips{$ipAddr}{'macAddr'} = $macAddr;
+ $adapter{$adapterAddr}{'ipCnt'} += 1;
+ }
+ }
+
+ my $adapterCnt = keys %adapter;
+ push @{$rsp->{data}}, "For userid $activeSystem, $adapterCnt adapters were detected." if ( $args{'verbose'} == 1 );
+ foreach $adapterAddr ( keys %adapter ) {
+ if ( $adapter{$adapterAddr}{'macCnt'} > 0 ) {
+ if ( $adapter{$adapterAddr}{'ipCnt'} != 0 ) {
+ push @{$rsp->{data}}, " Adapter $adapterAddr: $adapter{$adapterAddr}{'macCnt'} MACs with $adapter{$adapterAddr}{'ipCnt'} associated IP address(es)" if ( $args{'verbose'} == 1 );
+ } else {
+ push @{$rsp->{data}}, " Adapter $adapterAddr: $adapter{$adapterAddr}{'macCnt'} MACs but no associated IP addresses" if ( $args{'verbose'} == 1 );
+ push @failureInfo, "Adapter $adapterAddr: $adapter{$adapterAddr}{'macCnt'} MACs but no associated IP addresses";
+ }
+ } elsif ( $adapter{$adapterAddr}{'status'} eq '00' ) {
+ push @{$rsp->{data}}, " Adapter $adapterAddr: Not coupled" if ( $args{'verbose'} == 1 );
+ push @failureInfo, "Adapter $adapterAddr: Not coupled";
+ } elsif ( $adapter{$adapterAddr}{'status'} eq '01' ) {
+ push @{$rsp->{data}}, " Adapter $adapterAddr: Not active" if ( $args{'verbose'} == 1 );
+ push @failureInfo, "Adapter $adapterAddr: Not active";
+ } else {
+ push @{$rsp->{data}}, " Adapter $adapterAddr: No MACs with associated IP addresses" if ( $args{'verbose'} == 1 );
+ push @failureInfo, "Adapter $adapterAddr: No MACs with associated IP addresses";
+ }
+ }
+ xCAT::MsgUtils->message( "I", $rsp, $callback ) if ( $args{'verbose'} == 1 );
+
+ if ( !%ips ) {
+ if ( keys %adapter eq 0 ) {
+ push @failureInfo, "No adapters were found";
+ } else {
+ push @failureInfo, "No IP addresses were detected";
+ }
+
+ goto FINISH_findAccessIP;
+ }
+
+ # Contact the IPs to see which one, if any, lets us in.
+ foreach $ipAddr ( keys %ips ) {
+ $rc = 0;
+ if ( $ips{$ipAddr}{'ipVersion'} eq '6' ) {
+ # IPv6 is not currently supported.
+ next;
+ }
+
+ if ( $args{'ipfilter'} ) {
+ if ( $ipAddr !~ m/$args{'ipfilter'}/i ) {
+ if ( $args{'verbose'} == 1 ) {
+ push @{$rsp->{data}}, "For userid $activeSystem, filtered out IP: $ipAddr";
+ xCAT::MsgUtils->message( "I", $rsp, $callback );
+ }
+ push @failureInfo, "$ipAddr - filtered out by the specified IP filter";
+ next;
+ }
+ }
+
+ # Ping the address to see if it is responsive.
+ if ( $ips{$ipAddr}{'ipVersion'} eq '4' ) {
+ $out = `ping -c1 $ipAddr`;
+ $rc = $?;
+ } elsif ( $ips{$ipAddr}{'ipVersion'} eq '6' ) {
+ # IPv6 is not currently supported.
+ $rc = 3;
+ #$out = `ping6 -c1 $ipAddr`;
+ #$rc = $?;
+ next;
+ } else {
+ push @{$rsp->{data}}, "Userid $activeSystem, IP address: $ipAddr has an unsupported IP version: $ips{$ipAddr}";
+ xCAT::MsgUtils->message( "E", $rsp, $callback );
+ next;
+ }
+ if ( $rc != 0 or $out !~ / 0% packet loss,/ ) {
+ if ( $args{'verbose'} == 1 ) {
+ push @{$rsp->{data}}, "For userid $activeSystem, ping failed for $ipAddr";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ }
+ push @failureInfo, "$ipAddr - Unable to ping, rc: $rc";
+ next;
+ }
+
+ # SSH into the system to verify access.
+ my $line = `ssh -q $ipAddr pwd 2>/dev/null`;
+ $rc = $? >> 8;
+ if ( $rc == 255 ) {
+ if ( $args{'verbose'} == 1 ) {
+ push @{$rsp->{data}}, "For userid $activeSystem, Unable to ssh into: $ipAddr";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ }
+ push @failureInfo, "$ipAddr - Unable to ssh into system";
+ next;
+ }
+
+ # Determine the fully qualified host name to use.
+ my $fqdn = '';
+
+ # Attempt to get it from the system's OS using one of a number of commands.
+ # If we can't get a fully qualified DNS names (with periods) then accept the short name.
+ my $shortName = '';
+ foreach my $cmd ( @hostnameCmds ) {
+ my $hostname = `ssh -q $ipAddr $cmd 2>/dev/null`;
+ my $rc = $? >> 8;
+ if ( $rc == 255 ) {
+ if ( $args{'verbose'} == 1 ) {
+ my $rsp;
+ push @{$rsp->{data}}, "For userid $activeSystem, Unable to ssh into: $ipAddr";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ push @failureInfo, "$ipAddr - Unable to ssh into system";
+ last;
+ }
+ last;
+ } elsif ( $rc == 0 ) {
+ # verify the hostname is a fully qualified name.
+ chomp $hostname;
+ if ( $hostname =~ /\./ ) {
+ $fqdn = $hostname;
+ last;
+ } else {
+ $hostname =~ s/^\s+//;
+ if (( $hostname ne '' ) && ( $hostname !~ /\s/ )) {
+ # Single word returned without periods. Must be a short name.
+ $shortName = $hostname;
+ }
+ # Keep looking for a long name but we will remember the short name
+ # in case we can't find a long name.
+ }
+ } else {
+ if ( $args{'verbose'} == 1 ) {
+ my $rsp;
+ push @{$rsp->{data}}, "For userid $activeSystem, \'$cmd\' returned, rc: $rc.";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ }
+ }
+ }
+ if (( $shortName eq '' ) && ( $rc != 255 )) {
+ push @failureInfo, "$ipAddr - hostname query commands failed to return required information";
+ }
+
+ if (( $fqdn eq '' ) && ( $shortName ne '' )) {
+ if ( $args{'verbose'} == 1 ) {
+ my $rsp;
+ push @{$rsp->{data}}, "For userid $activeSystem, Unable to determine the fully qualified domain name but found a short name. The short name will be used.";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ }
+ $fqdn = $shortName;
+ }
+
+ # Found the last piece of info needed.
+ # Note: If hostname is empty because we could not find it, the ultimate response will
+ # be a failing return code.
+ $sysInfoRef->{$activeSystem}{'adapterAddr'} = $ips{$ipAddr}{'adapterAddr'};;
+ $sysInfoRef->{$activeSystem}{'ipAddr'} = $ipAddr;
+ $sysInfoRef->{$activeSystem}{'ipVersion'} = $ips{$ipAddr};
+ $sysInfoRef->{$activeSystem}{'macAddr'} = $ips{$ipAddr}{'macAddr'};
+ $sysInfoRef->{$activeSystem}{'switch'} = $ips{$ipAddr}{'lanName'};
+ $sysInfoRef->{$activeSystem}{'hostname'} = $fqdn;
+ last;
+ }
+
+FINISH_findAccessIP:
+ if ( $sysInfoRef->{$activeSystem}{'hostname'} ) {
+ $rc = 0;
+ } else {
+ $rc = 1;
+ if ( @failureInfo ) {
+ my $rsp;
+ my $failureString = join( ',\n', @failureInfo );
+ push @{$rsp->{data}}, "Unable to access $activeSystem for the following reasons:\n$failureString";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+
+ $failureString = join( ', ', @failureInfo );
+ xCAT::zvmUtils->printSyslog( "findAccessIP() Unable to access $activeSystem for the following reasons: $failureString" );
+ }
+ }
+ return $rc;
+}
+
+
#-------------------------------------------------------
=head3 smapi4xcat
@@ -2128,12 +3328,12 @@ sub getMaxMemory {
Returns : 0 EXEC not found
1 EXEC found
Example : my $out = xCAT::zvmUtils->smapi4xcat($user, $hcp);
-
+
=cut
#-------------------------------------------------------
sub smapi4xcat {
- my ($class, $user, $hcp) = @_;
+ my ( $class, $user, $hcp ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
@@ -2151,7 +3351,7 @@ sub smapi4xcat {
# Levels 621 and greater support SMAPI EXEC
my $out = `ssh $user\@$hcp "$sudo $dir/smcli Query_API_Functional_Level -T $hcpUserId"`;
$out = xCAT::zvmUtils->trimStr($out);
- if (!($out =~ m/V6.2/i || $out =~ m/V6.1/i || $out =~ m/V5.4/i)) {
+ if ( !($out =~ m/V6.2/i || $out =~ m/V6.1/i || $out =~ m/V5.4/i) ) {
return 1;
}
@@ -2159,7 +3359,7 @@ sub smapi4xcat {
# EXEC found if RC = 8 and RS = 3002
$out = `ssh $user\@$hcp "$sudo $dir/smcli xCAT_Commands_IUO -T $hcpUserId -c ''"`;
$out = xCAT::zvmUtils->trimStr($out);
- if ($out =~ m/Return Code: 8/i && $out =~ m/Reason Code: 3002/i) {
+ if ( $out =~ m/Return Code: 8/i && $out =~ m/Reason Code: 3002/i ) {
return 1;
}
@@ -2177,14 +3377,16 @@ sub smapi4xcat {
Privilege
Profile
Cpu
+ ipl
+ logonby
Returns : If successful, return file path. Otherwise, return -1
- Example : my $out = xCAT::zvmUtils->generateUserEntryFile($userId, $password, $memorySize, $privilege, $profileName, $cpuCount);
-
+ Example : my $out = xCAT::zvmUtils->generateUserEntryFile($userId, $password, $memorySize, $privilege, $profileName, $cpuCount, $ipl, $logonby);
+
=cut
#-------------------------------------------------------
sub generateUserEntryFile {
- my ($class, $userId, $password, $memorySize, $privilege, $profileName, $cpuCount) = @_;
+ my ( $class, $userId, $password, $memorySize, $privilege, $profileName, $cpuCount, $ipl, $logonby) = @_;
# If a file of this name already exists, just override it
my $file = "/tmp/$userId.txt";
@@ -2192,8 +3394,19 @@ sub generateUserEntryFile {
# Add additional CPUs
my $i;
- for ($i = 1 ; $i < $cpuCount ; $i++) {
- $content = $content . sprintf("CPU %02X\n", $i)
+ for ( $i = 1; $i < $cpuCount; $i++ ) {
+ $content = $content.sprintf("CPU %02X\n", $i);
+ }
+
+ if ( $ipl ne "") {
+ # the caller need validate this $ipl param
+ $content = $content.sprintf("IPL %04s\n", $ipl);
+ }
+
+ if ( $logonby ne "") {
+ # the caller need validate the $logonby param
+ my $log = "LOGONBY ".$logonby."\n";
+ $content = $content.$log;
}
unless (open(FILE, ">$file")) {
@@ -2213,14 +3426,14 @@ sub generateUserEntryFile {
Description : Obtain the SSI and system status
Arguments : User (root or non-root)
zHCP
- Returns : SSI cluster name
+ Returns : SSI cluster name or string containing (Error)...
Example : my $out = xCAT::zvmUtils->querySSI($user, $hcp);
-
+
=cut
#-------------------------------------------------------
sub querySSI {
- my ($class, $user, $hcp) = @_;
+ my ( $class, $user, $hcp ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
@@ -2230,7 +3443,14 @@ sub querySSI {
$sudo = "";
}
- my $ssi = `ssh -o ConnectTimeout=10 $user\@$hcp "$sudo $dir/smcli SSI_Query" | egrep -i "ssi_name"`;
+ my $outmsg;
+ my $rc;
+ my $ssi = `ssh -o ConnectTimeout=10 $user\@$hcp "$sudo $dir/smcli SSI_Query"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=10 $user\@$hcp \"$sudo $dir/smcli SSI_Query\"", $hcp, "querySSI", $ssi );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ $ssi = `echo "$ssi" | egrep -a -i "ssi_name"`;
$ssi =~ s/ssi_name = //;
$ssi =~ s/\s*$//;
$ssi =~ s/^\s*//;
@@ -2248,25 +3468,27 @@ sub querySSI {
Command to execute
Returns : Output returned from executing command
Example : my $out = xCAT::zvmUtils->rExecute($user, $node, $cmd);
-
+
=cut
#-------------------------------------------------------
sub rExecute {
- my ($class, $user, $node, $cmd) = @_;
+ my ( $class, $user, $node, $cmd ) = @_;
my $out;
my $sudo = "sudo";
- if ($user eq "root") {
+ if ($user eq "root") {
# Just execute the command if root
- $out = `ssh $user\@$node "$cmd"`;
+ #$out = `ssh $user\@$node "$cmd"`;
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
return $out;
}
-
# Encapsulate command in single quotes
$cmd = "'" . $cmd . "'";
- $out = `ssh $user\@$node "$sudo sh -c $cmd"`;
+ #$out = `ssh $user\@$node "$sudo sh -c $cmd"`;
+ $cmd = "$sudo sh -c $cmd";
+ $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
return $out;
}
@@ -2277,14 +3499,14 @@ sub rExecute {
Description : Get a list of used FCP devices in the zFCP pools
Arguments : User (root or non-root)
zHCP
- Returns : List of known FCP devices
+ Returns : List of known FCP devices, or hash with key "Error" containing error message
Example : my %devices = xCAT::zvmUtils->getUsedFcpDevices($user, $zhcp);
-
+
=cut
#-------------------------------------------------------
sub getUsedFcpDevices {
- my ($class, $user, $hcp) = @_;
+ my ( $class, $user, $hcp ) = @_;
# Directory where zFCP pools are
my $pool = "/var/opt/zhcp/zfcp";
@@ -2297,7 +3519,16 @@ sub getUsedFcpDevices {
# Grep the pools for used or allocated zFCP devices
my %usedDevices;
my @args;
- my @devices = split("\n", `ssh $user\@$hcp "$sudo cat $pool/*.conf" | egrep -i "used|allocated"`);
+ my $outmsg;
+ my $rc;
+ my $out = `ssh $user\@$hcp "$sudo cat $pool/*.conf"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo cat $pool/*.conf\"", $hcp, "getUsedFcpDevices", $out );
+ if ($rc != 0) {
+ $usedDevices{"Error"} = $outmsg;
+ return %usedDevices;
+ }
+ $out = `echo "$out" | egrep -a -i "used|allocated"`;
+ my @devices = split("\n", $out);
foreach (@devices) {
@args = split(",", $_);
@@ -2310,7 +3541,7 @@ sub getUsedFcpDevices {
# Push used or allocated devices into hash
if ($args[6]) {
- $usedDevices{ uc($args[6]) } = 1;
+ $usedDevices{uc($args[6])} = 1;
}
}
@@ -2325,58 +3556,78 @@ sub getUsedFcpDevices {
Arguments : Sudoer user name
Sudo keyword
zHCP hostname
+ Install root directory
Local directory to remotely mount
Mount access ('ro' for read only, 'rw' for read write)
Directory as known to zHCP (out)
Returns : 0 - Mounted, or zHCP and MN are on the same system
- 1 - Mount failed
- Example : establishMount( $callback, $::SUDOER, $::SUDO, $hcp, "$installRoot/$provMethod", "ro", \$remoteDeployDir );
-
+ 1 - Mount failed, errors returned in $callback
+ Example : establishMount( $callback, $::SUDOER, $::SUDO, $hcp, $installRoot, $provMethod, "ro", \$remoteDeployDir );
+
=cut
#-------------------------------------------------------
sub establishMount {
-
# Get inputs
- my ($class, $callback, $sudoer, $sudo, $hcp, $localDir, $access, $mountedPt) = @_;
+ my ($class, $callback, $sudoer, $sudo, $hcp, $installRoot, $localDir, $access, $mountedPt) = @_;
my $out;
# If the target system is not on this system then establish the NFS mount point.
- my $hcpIP = xCAT::NetworkUtils->getipaddr($hcp);
- if (!defined $hcpIP) {
- xCAT::zvmUtils->printLn($callback, "(Error) Unable to obtain the IP address of the hcp node");
+ my $hcpIP = xCAT::NetworkUtils->getipaddr( $hcp );
+ if (! defined $hcpIP) {
+ xCAT::zvmUtils->printLn( $callback, "(Error) Unable to obtain the IP address of the hcp node" );
return 1;
}
- my $masterIp = xCAT::TableUtils->get_site_Master();
+ # Get internal master IP if xcat and zhcp are on a 10. network
+ my $masterIp = xCAT::TableUtils->get_site_attribute("internalmaster");
+
+ # Use "internalmaster", if it is set. Otherwise, look at "master" property.
if (!defined $masterIp) {
- xCAT::zvmUtils->printLn($callback, "$hcp: (Error) Unable to obtain the management node IP address from the site table");
- return 1;
+
+ $masterIp = xCAT::TableUtils->get_site_attribute("master");
+ if (! defined $masterIp) {
+ xCAT::zvmUtils->printLn( $callback, "$hcp: (Error) Unable to obtain the management node IP address from the site table" );
+ return 1;
+ }
}
if ($masterIp eq $hcpIP) {
-
# xCAT MN and zHCP are on the same box and will use the same directory without the need for an NFS mount.
- $$mountedPt = $localDir;
+ $$mountedPt = "$installRoot/$localDir";
} else {
-
# Determine the hostname for this management node
my $masterHostname = Sys::Hostname::hostname();
- if (!defined $masterHostname) {
-
+ if (! defined $masterHostname) {
# For some reason, the xCAT MN's hostname is not known. We pass along the IP address instead.
$masterHostname = $masterIp;
}
- xCAT::zvmUtils->printSyslog("establishMount() Preparing the NFS mount point on zHCP ($hcpIP) to xCAT MN $masterHostname($masterIp) for $localDir");
+ $$mountedPt = "/mnt/$masterHostname$installRoot/$localDir";
+
+ # If the mount point already exists then return because we are done.
+ my $outmsg;
+ my $rc;
+ $out = `ssh $sudoer\@$hcp "$sudo mount"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $sudoer\@$hcp \"$sudo mount\"", $hcp, "establishMount", $out );
+ if ($rc != 0) {
+ xCAT::zvmUtils->printLn( $callback, "$outmsg" );
+ return 1;
+ }
+ $rc = `echo "$out" | egrep -a -i $$mountedPt > /dev/null; echo \\\$?"`;
+ if ($rc == 0) {
+ return 0;
+ }
+
+ xCAT::zvmUtils->printSyslog( "establishMount() Preparing the NFS mount point on zHCP ($hcpIP) to xCAT MN $masterHostname($masterIp) for $localDir" );
# Prepare the staging mount point on zHCP, if they need to be established
- $$mountedPt = "/mnt/$masterHostname$localDir";
- my $rc = `ssh $sudoer\@$hcp "$sudo mkdir -p $$mountedPt && mount -t nfs -o $access $masterIp:$localDir $$mountedPt; echo \\\$?"`;
+ $rc = `ssh $sudoer\@$hcp "$sudo mkdir -p $$mountedPt && mount -t nfs -o $access $masterIp:/$localDir $$mountedPt; echo \\\$?"`;
- # Return code = 0 (mount succeeded) or 32 (mount already exists)
- if ($rc != '0' && $rc != '32') {
- xCAT::zvmUtils->printLn($callback, "$hcp: (Error) Unable to establish zHCP mount point: $$mountedPt");
+ # Return code = 0 (mount succeeded)
+ if ($rc != '0') {
+ xCAT::zvmUtils->printLn( $callback, "$hcp: (Error) Unable to establish zHCP mount point: $$mountedPt" );
+ xCAT::zvmUtils->printSyslog( "establishMount() Unable to establish zHCP mount point: $$mountedPt, rc: $rc" );
return 1;
}
}
@@ -2388,16 +3639,18 @@ sub establishMount {
=head3 getFreeRepoSpace
- Description : Get the free space of image repository under /install
+ Description : Get the free space of image repository under /install.
Arguments : Node
- Returns : The available space for /install
+ Returns : The available space for /install (e.g. "2.1G ").
+ The value is returned as a perl string (e.g. "0 ") to
+ avoid perl returning null instead of "0" in the case
+ of no space available.
Example : my $free = getFreeRepoSpace($callback, $node);
-
+
=cut
#-------------------------------------------------------
sub getFreeRepoSpace {
-
# Get inputs
my ($class, $user, $node) = @_;
@@ -2408,18 +3661,22 @@ sub getFreeRepoSpace {
# Check if node is the management node
my @entries = xCAT::TableUtils->get_site_attribute("master");
- my $master = xCAT::zvmUtils->trimStr($entries[0]);
- my $ip = xCAT::NetworkUtils->getipaddr($node);
+ my $master = xCAT::zvmUtils->trimStr($entries[0]);
+ my $ip = xCAT::NetworkUtils->getipaddr($node);
$ip = xCAT::zvmUtils->trimStr($ip);
my $mn = 0;
if ($master eq $ip) {
-
# If the master IP and node IP match, then it is the management node
my $out = `$sudo /bin/df -h /install | sed 1d`;
- # causing problems on other platforms $out =~ s/\h+/ /g;$out =~ s/\h+/ /g;
+ # Comment out the horizontal whitespace escape, it was causing "Restarting xCATd Unrecognized escape"
+ # $out =~ s/\h+/ /g;
+
my @results = split(' ', $out);
- return ($results[3]);
+ if ( $results[3] eq "0" ) {
+ $results[3] = "0M";
+ }
+ return $results[3];
}
return;
@@ -2442,22 +3699,24 @@ sub getFreeRepoSpace {
- LUN
- Size requested
- Owner
- - Tag
+ - Tag
Returns : Results hash including:
- - Return code (0 = Success, -1 = Failure)
+ - Return code (0 = Success, -1 = Failure, errors returned in $callback)
- zFCP device (if one is requested)
- WWPN
- LUN
Example : my $resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $header, $user, $hcp, $pool, $criteriaRef);
-
+
=cut
#-------------------------------------------------------
sub findAndUpdatezFcpPool {
-
# Get inputs
my ($class, $callback, $header, $user, $hcp, $pool, $criteriaRef) = @_;
+ my $outmsg;
+ my $rc;
+ my $out;
# Determine if sudo is used
my $sudo = "sudo";
if ($user eq "root") {
@@ -2470,22 +3729,22 @@ sub findAndUpdatezFcpPool {
# Directory where FCP disk pools are on zHCP
my $zfcpDir = "/var/opt/zhcp/zfcp";
- my %results = ('rc' => -1); # Default to error
+ my %results = ('rc' => -1); # Default to error
# Extract criteria
- my %criteria = %$criteriaRef;
- my $status = defined($criteria{status}) ? $criteria{status} : "";
+ my %criteria = %$criteriaRef;
+ my $status = defined($criteria{status}) ? $criteria{status} : "";
my $fcpDevice = defined($criteria{fcp}) ? $criteria{fcp} : "";
- my $wwpn = defined($criteria{wwpn}) ? $criteria{wwpn} : "";
- my $lun = defined($criteria{lun}) ? $criteria{lun} : "";
- my $size = defined($criteria{size}) ? $criteria{size} : "";
- my $owner = defined($criteria{owner}) ? $criteria{owner} : "";
- my $tag = defined($criteria{tag}) ? $criteria{tag} : "";
+ my $wwpn = defined($criteria{wwpn}) ? $criteria{wwpn} : "";
+ my $lun = defined($criteria{lun}) ? $criteria{lun} : "";
+ my $size = defined($criteria{size}) ? $criteria{size} : "";
+ my $owner = defined($criteria{owner}) ? $criteria{owner} : "";
+ my $tag = defined($criteria{tag}) ? $criteria{tag} : "";
# Check required arguments: pool, status
# If you do not know what to update, why update!
if (!$pool && !$status) {
- return \%results;
+ return \%results;
}
# Check status
@@ -2495,17 +3754,17 @@ sub findAndUpdatezFcpPool {
}
# Check FCP device syntax
- if ($fcpDevice && ($fcpDevice !~ /^auto/i) && ($fcpDevice =~ /[^0-9a-f]/i)) {
+ if ($fcpDevice && ($fcpDevice !~ /^auto/i) && ($fcpDevice =~ /[^0-9a-f;]/i)) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) Invalid FCP channel address $fcpDevice.");
return \%results;
}
- # Check WWPN and LUN syntax
- if ($wwpn && ($wwpn =~ /[^0-9a-f;"]/i)) {
- xCAT::zvmUtils->printLn($callback, "$header: (Error) Invalid world wide portname $wwpn.");
+ # Owner must be specified if status is used
+ if ($status =~ m/used/i && !$owner) {
+ xCAT::zvmUtils->printLn( $callback, "$header: (Error) Owner must be specified if status is used." );
return \%results;
- } if ($lun && ($lun =~ /[^0-9a-f]/i)) {
- xCAT::zvmUtils->printLn($callback, "$header: (Error) Invalid logical unit number $lun.");
+ } elsif ($status =~ m/free/i && $owner) {
+ xCAT::zvmUtils->printLn( $callback, "$header: (Error) Owner must not be specified if status is free." );
return \%results;
}
@@ -2513,15 +3772,13 @@ sub findAndUpdatezFcpPool {
my $originSize = $size;
if ($size) {
if ($size =~ m/G/i) {
-
# Convert to MegaBytes
$size =~ s/\D//g;
$size = int($size) * 1024
} elsif ($size =~ m/M/i || !$size) {
-
# Do nothing
} else {
- xCAT::zvmUtils->printLn($callback, "$header: (Error) Size not recognized. Size can be M(egabytes) or G(igabytes).");
+ xCAT::zvmUtils->printLn( $callback, "$header: (Error) Size not recognized. Size can be M(egabytes) or G(igabytes)." );
return \%results;
}
}
@@ -2535,20 +3792,26 @@ sub findAndUpdatezFcpPool {
# Make sure WWPN and LUN do not have 0x prefix
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
- $lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
+ $lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
+
+ # Check WWPN and LUN syntax
+ if ( $wwpn && ($wwpn =~ /[^0-9a-f;]/i) ) {
+ xCAT::zvmUtils->printLn( $callback, "$header: (Error) Invalid world wide portname $wwpn." );
+ return \%results;
+ } if ( $lun && ($lun =~ /[^0-9a-f]/i) ) {
+ xCAT::zvmUtils->printLn( $callback, "$header: (Error) Invalid logical unit number $lun." );
+ return \%results;
+ }
}
# Find disk pool (create one if non-existent)
- my $out;
if (!(`ssh $user\@$hcp "$sudo test -d $zfcpDir && echo Exists"`)) {
-
# Create pool directory
$out = `ssh $user\@$hcp "$sudo mkdir -p $zfcpDir"`;
}
# Find if disk pool exists
if (!(`ssh $user\@$hcp "$sudo test -e $zfcpDir/$pool.conf && echo Exists"`)) {
-
# Return if xCAT is expected to find a FCP device, but no disk pool exists.
xCAT::zvmUtils->printLn($callback, "$header: (Error) FCP storage pool does not exist");
return \%results;
@@ -2556,30 +3819,34 @@ sub findAndUpdatezFcpPool {
# Find a free disk in the pool
# FCP devices are contained in /var/opt/zhcp/zfcp/.conf
- my $range = "";
+ my $range = "";
my $sizeFound = "*";
my @info;
if (!$useWwpnLun) {
-
# Find a suitable pair of WWPN and LUN in device pool based on requested size
# Sample pool configuration file:
# #status,wwpn,lun,size,range,owner,channel,tag
# used,1000000000000000,2000000000000110,8g,3B00-3B3F,ihost1,1a23,$root_device$
# free,1000000000000000,2000000000000111,,3B00-3B3F,,,
# free,1230000000000000;4560000000000000,2000000000000112,,3B00-3B3F,,,
- my @devices = split("\n", `ssh $user\@$hcp "$sudo cat $zfcpDir/$pool.conf" | egrep -i ^free`);
+ $out = `ssh $user\@$hcp "$sudo cat $zfcpDir/$pool.conf"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo cat $zfcpDir/$pool.conf\"", $hcp, "findAndUpdatezFcpPool", $out );
+ if ($rc != 0) {
+ xCAT::zvmUtils->printLn($callback, "$outmsg");
+ return \%results;
+ }
+ $out = `echo "$out" | egrep -a -i ^free`;
+ my @devices = split("\n", $out);
$sizeFound = 0;
foreach (@devices) {
@info = split(',', $_);
# Check if the size is sufficient. Convert size into MB.
if ($info[3] =~ m/G/i) {
-
# Convert to MegaBytes
$info[3] =~ s/\D//g;
$info[3] = int($info[3]) * 1024
} elsif ($info[3] =~ m/M/i) {
-
# Do nothing
$info[3] =~ s/\D//g;
} else {
@@ -2589,42 +3856,47 @@ sub findAndUpdatezFcpPool {
# Find optimal disk based on requested size
if ($sizeFound && $info[3] >= $size && $info[3] < $sizeFound) {
$sizeFound = $info[3];
- $wwpn = $info[1];
- $lun = $info[2];
- $range = $info[4];
+ $wwpn = $info[1];
+ $lun = $info[2];
+ $range = $info[4];
} elsif (!$sizeFound && $info[3] >= $size) {
$sizeFound = $info[3];
- $wwpn = $info[1];
- $lun = $info[2];
- $range = $info[4];
+ $wwpn = $info[1];
+ $lun = $info[2];
+ $range = $info[4];
}
}
# Do not continue if no devices can be found
- if (!$wwpn && !$lun) {
+ if (!$wwpn || !$lun) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) A suitable device of $size" . "M or larger could not be found");
return \%results;
}
} else {
-
# Find given WWPN and LUN. Do not continue if device is used
- my $select = `ssh $user\@$hcp "$sudo cat $zfcpDir/$pool.conf" | grep -i "$wwpn,$lun"`;
+ my $select = `ssh $user\@$hcp "$sudo cat $zfcpDir/$pool.conf"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo cat $zfcpDir/$pool.conf\"", $hcp, "findAndUpdatezFcpPool", $select );
+ if ($rc != 0) {
+ xCAT::zvmUtils->printLn($callback, "$outmsg");
+ return \%results;
+ }
+ $select = `echo "$select" | egrep -a -i "$wwpn,$lun"`;
chomp($select);
+ if (!$select) {
+ xCAT::zvmUtils->printLn($callback, "$header: (Error) zFCP device 0x$wwpn/0x$lun could not be found in zFCP pool $pool");
+ return \%results;
+ }
@info = split(',', $select);
if ($size) {
if ($info[3] =~ m/G/i) {
-
# Convert to MegaBytes
$info[3] =~ s/\D//g;
$info[3] = int($info[3]) * 1024
- } elsif ($info[3] =~ m/M/i) {
-
+ } else {
# Do nothing
$info[3] =~ s/\D//g;
- } else {
- next;
}
# Do not continue if specified device does not have enough capacity
@@ -2638,15 +3910,104 @@ sub findAndUpdatezFcpPool {
$range = $info[4];
}
- # If there are multiple paths, take the 1st one
- # Handle multi-pathing in postscript because autoyast/kickstart does not support it.
- my $origWwpn = $wwpn;
- if ($wwpn =~ m/;/i) {
- @info = split(';', $wwpn);
- $wwpn = xCAT::zvmUtils->trimStr($info[0]);
+ xCAT::zvmUtils->printLn($callback, "$header: Found FCP device 0x$wwpn/0x$lun");
+
+ if ( ($status =~ m/used/i) && ($fcpDevice =~ /^auto/i) ) {
+ # select an eligible FCP device
+ $fcpDevice = xCAT::zvmUtils->selectFcpDevice($callback, $header, $user, $hcp, $fcpDevice, $range, $owner);
+ if (!$fcpDevice) {
+ return \%results;
+ }
+ } elsif ($status =~ m/free/i) {
+ # Owner and FCP channel make no sense when status is free
+ $fcpDevice = "";
+ $owner = "";
}
- xCAT::zvmUtils->printLn($callback, "$header: Found FCP device 0x$wwpn/0x$lun");
+ # Mark WWPN and LUN as used, free, or reserved and set the owner/channel appropriately
+ # This config file keeps track of the owner of each device, which is useful in nodeset
+ $size = $size . "M";
+ my $select = `ssh $user\@$hcp "$sudo cat $zfcpDir/$pool.conf"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo cat $zfcpDir/$pool.conf\"", $hcp, "findAndUpdatezFcpPool", $select );
+ if ($rc != 0) {
+ xCAT::zvmUtils->printLn($callback, "$outmsg");
+ return \%results;
+ }
+ $select = `echo "$select" | egrep -a -i "$lun"`;
+ chomp($select);
+ if ($select) {
+ @info = split(',', $select);
+
+ if (!$info[3]) {
+ $info[3] = $size;
+ }
+
+ # Do not update if WWPN/LUN pair is specified but the pair does not exist
+ if (!($info[1] =~ m/$wwpn/i)) {
+ xCAT::zvmUtils->printLn($callback, "$header: (Error) FCP device $wwpn/$lun does not exists");
+ return \%results;
+ }
+
+ # Entry order: status,wwpn,lun,size,range,owner,channel,tag
+ # The following are never updated: wwpn, lun, size, and range
+ my $update = "$status,$info[1],$info[2],$info[3],$info[4],$owner,$fcpDevice,$tag";
+ my $expression = "'s#" . $select . "#" .$update . "#i'";
+ $out = `ssh $user\@$hcp "$sudo sed --in-place -e $expression $zfcpDir/$pool.conf"`;
+ } else {
+ # Insert device entry into file
+ $out = `ssh $user\@$hcp "$sudo echo \"$status,$wwpn,$lun,$size,,$owner,$fcpDevice,$tag\" >> $zfcpDir/$pool.conf"`;
+ }
+
+ # Generate results hash
+ %results = (
+ 'rc' => 0,
+ 'fcp' => $fcpDevice,
+ 'wwpn' => $wwpn,
+ 'lun' => $lun
+ );
+ return \%results;
+}
+
+#-------------------------------------------------------
+
+=head3 selectFcpDevice
+
+ Description : Select an eligible FCP device for attaching a zFCP device to a node
+ Arguments : Message header
+ User (root or non-root)
+ zHCP
+ candidate FCP devices or auto
+ FCP device range
+ zFCP device owner
+ Returns : selected FCP device or empty if no one is selected, errors returned in $callback
+ Example : my $fcpDevice = xCAT::zvmUtils->selectFcpDevice($callback, $header, $user, $hcp, $fcpDevice, $range, $owner);
+
+=cut
+
+#-------------------------------------------------------
+sub selectFcpDevice {
+ # Get inputs
+ my ($class, $callback, $header, $user, $hcp, $fcpDevice, $range, $owner) = @_;
+
+ # Determine if sudo is used
+ my $sudo = "sudo";
+ if ($user eq "root") {
+ $sudo = "";
+ }
+
+ # Directory where executables are on zHCP
+ my $dir = "/opt/zhcp/bin";
+
+ # Directory where FCP disk pools are on zHCP
+ my $zfcpDir = "/var/opt/zhcp/zfcp";
+
+ my %results = ('rc' => -1); # Default to error
+
+ # Check FCP device syntax
+ if ($fcpDevice && ($fcpDevice !~ /^auto/i) && ($fcpDevice =~ /[^0-9a-f]/i)) {
+ xCAT::zvmUtils->printLn($callback, "$header: (Error) Invalid FCP channel address $fcpDevice.");
+ return;
+ }
# Find a free FCP device based on the given range
if ($fcpDevice =~ m/^auto/i) {
@@ -2662,18 +4023,16 @@ sub findAndUpdatezFcpPool {
}
if (!$found) {
-
# If the node has an eligible FCP device, use it
my @deviceList = xCAT::zvmUtils->getDedicates($callback, $user, $owner);
foreach (@deviceList) {
-
# Check if this devide is eligible (among the range specified for disk $lun)
- @info = split(' ', $_);
+ my @info = split(' ', $_);
my $candidate = $info[2];
foreach (@ranges) {
($min, $max) = split('-', $_);
if (hex($candidate) >= hex($min) && hex($candidate) <= hex($max)) {
- $found = 1;
+ $found = 1;
$fcpDevice = uc($candidate);
last;
@@ -2688,18 +4047,28 @@ sub findAndUpdatezFcpPool {
}
if (!$found) {
-
# If the node has no eligible FCP device, find a free one for it.
my %usedDevices = xCAT::zvmUtils->getUsedFcpDevices($user, $hcp);
+ if (exists $usedDevices{"Error"}) {
+ xCAT::zvmUtils->printLn($callback, "$header: $usedDevices{Error}");
+ return;
+ }
my $hcpUserId = xCAT::zvmCPUtils->getUserId($user, $hcp);
$hcpUserId =~ tr/a-z/A-Z/;
# Find a free FCP channel
- $out = `ssh $user\@$hcp "$sudo $dir/smcli System_WWPN_Query -T $hcpUserId" | egrep -i "FCP device number|Status"`;
- my @devices = split("\n", $out);
- for (my $i = 0 ; $i < @devices ; $i++) {
-
+ my $outmsg;
+ my $rc;
+ my $out = `ssh $user\@$hcp "$sudo $dir/smcli System_WWPN_Query -T $hcpUserId"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo $dir/smcli System_WWPN_Query -T $hcpUserId\"", $hcp, "selectFcpDevice", $out );
+ if ($rc != 0) {
+ xCAT::zvmUtils->printLn($callback, "$outmsg");
+ return;
+ }
+ $out = `echo "$out" | egrep -a -i "FCP device number|Status"`;
+ my @devices = split( "\n", $out );
+ for (my $i = 0; $i < @devices; $i++) {
# Extract the device number and status
$fcpDevice = $devices[$i];
$fcpDevice =~ s/^FCP device number:(.*)/$1/;
@@ -2714,7 +4083,6 @@ sub findAndUpdatezFcpPool {
# Only look at free FCP devices
if ($fcpStatus =~ m/free/i) {
-
# If the device number is within the specified range, exit out of loop
# Range: 3B00-3C00;4B00-4C00;5E12-5E12
foreach (@ranges) {
@@ -2722,7 +4090,7 @@ sub findAndUpdatezFcpPool {
if (hex($fcpDevice) >= hex($min) && hex($fcpDevice) <= hex($max)) {
$fcpDevice = uc($fcpDevice);
- # Used found FCP channel if not in use or allocated
+ # Use found FCP channel if not in use or allocated
if (!$usedDevices{$fcpDevice}) {
$found = 1;
last;
@@ -2742,14 +4110,14 @@ sub findAndUpdatezFcpPool {
# Do not continue if no FCP channel is found
if (!$found) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) A suitable FCP channel could not be found");
- return \%results;
+ return;
}
}
# If there are multiple devices (multipathing), take the 1st one
if ($fcpDevice) {
if ($fcpDevice =~ m/;/i) {
- @info = split(';', $fcpDevice);
+ my @info = split(';', $fcpDevice);
$fcpDevice = xCAT::zvmUtils->trimStr($info[0]);
}
@@ -2759,43 +4127,7 @@ sub findAndUpdatezFcpPool {
}
}
- # Mark WWPN and LUN as used, free, or reserved and set the owner/channel appropriately
- # This config file keeps track of the owner of each device, which is useful in nodeset
- $size = $size . "M";
- my $select = `ssh $user\@$hcp "$sudo cat $zfcpDir/$pool.conf" | grep -i "$lun" | grep -i "$wwpn"`;
- chomp($select);
- if ($select) {
- @info = split(',', $select);
-
- if (!$info[3]) {
- $info[3] = $size;
- }
-
- # Do not update if WWPN/LUN pair is specified but the pair does not exist
- if (!($info[1] =~ m/$wwpn/i)) {
- xCAT::zvmUtils->printLn($callback, "$header: (Error) FCP device $wwpn/$lun does not exists");
- return \%results;
- }
-
- # Entry order: status,wwpn,lun,size,range,owner,channel,tag
- # The following are never updated: wwpn, lun, size, and range
- my $update = "$status,$info[1],$info[2],$info[3],$info[4],$owner,$fcpDevice,$tag";
- my $expression = "'s#" . $select . "#" . $update . "#i'";
- $out = `ssh $user\@$hcp "$sudo sed --in-place -e $expression $zfcpDir/$pool.conf"`;
- } else {
-
- # Insert device entry into file
- $out = `ssh $user\@$hcp "$sudo echo \"$status,$origWwpn,$lun,$size,,$owner,$fcpDevice,$tag\" >> $zfcpDir/$pool.conf"`;
- }
-
- # Generate results hash
- %results = (
- 'rc' => 0,
- 'fcp' => $fcpDevice,
- 'wwpn' => $wwpn,
- 'lun' => $lun
- );
- return \%results;
+ return $fcpDevice;
}
#-------------------------------------------------------
@@ -2807,16 +4139,16 @@ sub findAndUpdatezFcpPool {
zHCP
WWPN
LUN
- Returns : Storage pool where zFCP device resides
+ Returns : Storage pool where zFCP device resides, or string containing (Error)...
Example : my $pool = xCAT::zvmUtils->findzFcpDevicePool($user, $hcp, $wwpn, $lun);
-
+
=cut
#-------------------------------------------------------
sub findzFcpDevicePool {
# Get inputs
- my ($class, $user, $hcp, $wwpn, $lun) = @_;
+ my ( $class, $user, $hcp, $wwpn, $lun ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -2827,11 +4159,19 @@ sub findzFcpDevicePool {
my $zfcpDir = "/var/opt/zhcp/zfcp";
# Find the pool that contains the SCSI/FCP device
- my @pools = split("\n", `ssh $user\@$hcp "$sudo grep -i -l \"$wwpn,$lun\" $zfcpDir/*.conf"`);
+ my $out;
+ my $outmsg;
+ my $rc;
+ $out = `ssh $user\@$hcp "$sudo grep -i -l \\\"$wwpn,$lun\\\" $zfcpDir/*.conf"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo grep -i -l \\\"$wwpn,$lun\\\" $zfcpDir/*.conf\"", $hcp, "findzFcpDevicePool", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ my @pools = split("\n", $out);
my $pool = "";
if (scalar(@pools)) {
$pool = basename($pools[0]);
- $pool =~ s/\.[^.]+$//; # Do not use extension
+ $pool =~ s/\.[^.]+$//; # Do not use extension
}
return $pool;
@@ -2847,16 +4187,16 @@ sub findzFcpDevicePool {
Storage pool
WWPN
LUN
- Returns : Architecture of node
- Example : my $deviceRef = xCAT::zvmUtils->findzFcpDeviceAttr($user, $hcp, $wwpn, $lun);
-
+ Returns : Architecture of node or string containing (Error)...
+ Example : my $deviceRef = xCAT::zvmUtils->findzFcpDeviceAttr($user, $hcp, $pool, $wwpn, $lun);
+
=cut
#-------------------------------------------------------
sub findzFcpDeviceAttr {
# Get inputs
- my ($class, $user, $hcp, $pool, $wwpn, $lun) = @_;
+ my ( $class, $user, $hcp, $pool, $wwpn, $lun ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
@@ -2868,7 +4208,15 @@ sub findzFcpDeviceAttr {
# Find the SCSI/FCP device
# Entry order: status,wwpn,lun,size,range,owner,channel,tag
- my @info = split("\n", `ssh $user\@$hcp "$sudo grep \"$wwpn,$lun\" $zfcpDir/$pool.conf"`);
+ my $out;
+ my $outmsg;
+ my $rc;
+ $out = `ssh $user\@$hcp "$sudo grep -i \"$wwpn,$lun\" $zfcpDir/$pool.conf"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo grep -i \"$wwpn,$lun\" $zfcpDir/$pool.conf\"", $hcp, "findzFcpDeviceAttr", $out );
+ if ($rc != 0) {
+ return $outmsg;
+ }
+ my @info = split("\n", $out);
my $entry = $info[0];
chomp($entry);
@@ -2881,13 +4229,13 @@ sub findzFcpDeviceAttr {
@info = split(',', $entry);
%attrs = (
'status' => $info[0],
- 'wwpn' => $info[1],
- 'lun' => $info[2],
- 'size' => $info[3],
- 'range' => $info[4],
- 'owner' => $info[5],
- 'fcp' => $info[6],
- 'tag' => $info[7]
+ 'wwpn' => $info[1],
+ 'lun' => $info[2],
+ 'size' => $info[3],
+ 'range' => $info[4],
+ 'owner' => $info[5],
+ 'fcp' => $info[6],
+ 'tag' => $info[7]
);
return \%attrs;
@@ -2904,22 +4252,21 @@ sub findzFcpDeviceAttr {
DHCP is used or not (0 or 1)
Returns : NIC, device channel, and layer (2 or 3)
Example : my ($nic, $channel, $layer) = xCAT::zvmUtils->findUsablezHcpNetwork($user, $hcp, $userId, $dhcp);
-
+
=cut
#-------------------------------------------------------
sub findUsablezHcpNetwork {
-
- # Get inputs
- my ($class, $user, $hcp, $userId, $dhcp) = @_;
+ # Get inputs
+ my ( $class, $user, $hcp, $userId, $dhcp ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
- my $nic = ''; # Usuable NIC on zHCP
- my $channel = ''; # Device channel where NIC is attached
+ my $nic = ''; # Usuable NIC on zHCP
+ my $channel = ''; # Device channel where NIC is attached
my $layer;
my $i;
my @words;
@@ -2936,26 +4283,23 @@ sub findUsablezHcpNetwork {
my @lines = split('\n', $out);
# Go through each line
- for ($i = 0 ; $i < @lines ; $i++) {
-
+ for ($i = 0; $i < @lines; $i++) {
# Go through each network device attached to zHCP
foreach (@hcpNetworks) {
# If network device is found
if ($lines[$i] =~ m/ $_/i) {
-
# Get network layer
$layer = xCAT::zvmCPUtils->getNetworkLayer($user, $hcp, $_);
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() NIC:$_ layer:$layer");
# If template using DHCP, layer must be 2
if ((!$dhcp && $layer != 2) || (!$dhcp && $layer == 2) || ($dhcp && $layer == 2)) {
-
# Save network name
$nic = $_;
# Get network virtual address
- @words = split(' ', $lines[$i]);
+ @words = split(' ', $lines[$i]);
# Get virtual address (channel)
# Convert subchannel to decimal
@@ -2964,7 +4308,6 @@ sub findUsablezHcpNetwork {
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() Candidate found NIC:$nic channel:$channel layer:$layer");
return ($nic, $channel, $layer);
} else {
-
# Go to next network available
$nic = '';
}
@@ -2974,7 +4317,6 @@ sub findUsablezHcpNetwork {
# If network device is not found
if (!$nic) {
-
# Check for user profile
my $profileName = `echo "$userEntry" | grep "INCLUDE"`;
if ($profileName) {
@@ -2984,31 +4326,28 @@ sub findUsablezHcpNetwork {
my $userProfile = xCAT::zvmUtils->getUserProfile($user, $hcp, $words[1]);
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() $userProfile");
- # Get the NICDEF statement containing the HCP network
+ # Get the NICDEF statement
$out = `echo "$userProfile" | grep "NICDEF"`;
@lines = split('\n', $out);
# Go through each line
- for ($i = 0 ; $i < @lines ; $i++) {
-
+ for ($i = 0; $i < @lines; $i++) {
# Go through each network device attached to zHCP
foreach (@hcpNetworks) {
# If network device is found
if ($lines[$i] =~ m/ $_/i) {
-
# Get network layer
$layer = xCAT::zvmCPUtils->getNetworkLayer($user, $hcp, $_);
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() NIC:$_ layer:$layer");
# If template using DHCP, layer must be 2
if ((!$dhcp && $layer != 2) || (!$dhcp && $layer == 2) || ($dhcp && $layer == 2)) {
-
# Save network name
$nic = $_;
# Get network virtual address
- @words = split(' ', $lines[$i]);
+ @words = split(' ', $lines[$i]);
# Get virtual address (channel)
# Convert subchannel to decimal
@@ -3017,15 +4356,848 @@ sub findUsablezHcpNetwork {
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() Candidate found NIC:$nic channel:$channel layer:$layer");
return ($nic, $channel, $layer);
} else {
-
# Go to next network available
$nic = '';
}
}
- } # End of foreach
- } # End of for
- } # End of if
+ } # End of foreach
+ } # End of for
+ } # End of if
}
return;
}
+
+#-------------------------------------------------------
+
+=head3 printInfo
+
+ Description : Print a long string to stdout as information without checking anything
+ Arguments : String
+ Returns : Nothing
+ Example : xCAT::zvmUtils->printInfo($callback, $str);
+
+=cut
+
+#-------------------------------------------------------
+sub printInfo {
+
+ # Get inputs
+ my ( $class, $callback, $str ) = @_;
+
+ # Print string
+ my $rsp;
+
+ $rsp->{data}->[0] = "$str";
+ xCAT::MsgUtils->message( "I", $rsp, $callback );
+
+ return;
+}
+
+#-------------------------------------------------------
+
+=head3 getSpecialCloneInfo
+
+ Description : Look in the /var/opt/xcat/doclone.txt file (if exists) and return a
+ hash of the keys and values found that match the image name parameter
+ Arguments : User friendly image name
+
+ Returns : hash of keys and values found or empty hash
+ Example : my %cloneinfo = xCAT::zvmUtils->getSpecialCloneInfo($callback, $user, $node);
+ if (%cloneinfo) {
+ %cloneinfo has at least one key
+ } else {
+ %cloneinfo empty, no keys
+ }
+
+=cut
+
+#-------------------------------------------------------
+sub getSpecialCloneInfo {
+
+ # Get inputs
+ my ( $class, $imagename ) = @_;
+ my %cloneInfoHash = (); # create empty hash
+
+ # Directory where doclone.txt is
+ my $dir = '/var/opt/xcat/';
+ my $clonefile = 'doclone.txt';
+ my $out;
+
+ # Does the file exist? If so read and look for this image name
+ if (-e "$dir$clonefile") {
+ # look for this image name and ignore case
+ $out = `cat $dir$clonefile | grep -v '^\\s*/[*]'| grep -v '^\\s*[*]'| grep -E -i -w "IMAGE_NAME[[:blank:]]*=[[:blank:]]*$imagename"`;
+
+ my @lines = split( '\n', $out );
+ my $count = @lines;
+
+ # loop for any lines found
+ for (my $i=0; $i < $count; $i++) {
+ # Break out each key=value; item
+ my @parms = split( ';', $lines[$i]);
+ my $parmcount = @parms;
+ # get the key and value for this item, store in hash
+ for (my $j=0; $j < $parmcount; $j++) {
+ my @keyvalue = split('=', $parms[$j]);
+ my $key = $keyvalue[0];
+ $key =~ s/^\s+|\s+$//g; # get rid of leading and trailing blanks
+ next if ( length( $key ) == 0 ); # Skip incorrect key=value data
+
+ my $value = $keyvalue[1];
+ $value =~ s/^\s+|\s+$//g;
+ next if ( length( $value ) == 0 ); # Skip incorrect key=value data
+ #uppercase both key and value;
+ $key = uc $key;
+ $value = uc $value;
+ $cloneInfoHash{ $key } = $value;
+ }
+ }
+ }
+ return (%cloneInfoHash);
+}
+
+#-------------------------------------------------------
+
+=head3 pingNode
+
+ Description : Execute a Perl ping for this node
+ Arguments : Node name
+
+ Returns : "ping" if found; or "noping" (if not found)
+ Example : my $out = xCAT::zvmUtils->pingNode($node);
+
+=cut
+
+#-------------------------------------------------------
+sub pingNode {
+
+ # Get input node
+ my ( $class, $node ) = @_;
+
+ my $timeout = 2; # how many seconds to wait for response. Default was 5
+ # call system ping and max count of pings 2
+ my $out = `ping -W $timeout -c 2 -q $node`;
+ if ($? != 0) {
+ # Ping failed, try to get result with execcmdonVM.
+ my $result = xCAT::zvmUtils->execcmdonVM($::SUDOER, $node, 'date');
+ if (xCAT::zvmUtils->checkOutput( $result ) == -1) {
+ return $result;
+ }
+ if ($result) {
+ return ("ping");
+ }
+ return ("noping");
+ }
+ return ("ping");
+}
+
+#-------------------------------------------------------
+
+=head3 onlineZhcpPunch
+
+ Description : Online punch device and load VMCP module on zHCP
+ Arguments : User (root or non-root)
+ zHCP
+ Returns : Operation results (Done/Failed)
+ Example : my $out = xCAT::zvmUtils->onlineZhcpPunch($user, $hcp);
+
+=cut
+
+#-------------------------------------------------------
+sub onlineZhcpPunch {
+
+ # Get input node
+ my ( $class, $user, $hcp ) = @_;
+
+ my $out = "";
+ my $subResp = "";
+ my $rc = "";
+
+ my $sudo = "sudo";
+ if ($user eq "root") {
+ $sudo = "";
+ }
+
+ # Online zHCP's punch
+ $out = `ssh $user\@$hcp "$sudo cat /sys/bus/ccw/drivers/vmur/0.0.000d/online" 2>&1`;
+ $rc = $? >> 8;
+ if ( $rc == 255 ) {
+ # SSH failure to communicate with zHCP.
+ $subResp = "Failed to communicate with the zHCP system to get the punch device status";
+ } elsif ( $rc != 0 ) {
+ # Generic failure of the command.
+ chomp( $out );
+ xCAT::zvmUtils->printSyslog( "onlineZhcpPunch() Failed to get the punch device status on zHCP rc: $rc, out: $out" );
+ $subResp = "Failed to online the punch device on zHCP rc: $rc, out: $out";
+ }
+
+ if ( $subResp eq "" ) {
+ if ($out != 1) {
+ chomp( $out = `ssh $user\@$hcp "$sudo /sbin/cio_ignore -r 000d; /sbin/chccwdev -e 000d"`);
+ $rc = $? >> 8;
+ if ( $rc == 0 ) {
+ $subResp = "Done";
+ } elsif ( $rc == 255 ) {
+ # SSH failure to communicate with zHCP.
+ $subResp = "Failed to communicate with the zHCP system to online the punch device";
+ } else {
+ if ( !( $out =~ m/Done$/i ) ) {
+ xCAT::zvmUtils->printSyslog("onlineZhcpPunch() failed to online the zHCP's punch, cmd output: $out.");
+ $subResp = "Failed to online the zHCP's punch rc: $rc, out: $out";
+ }
+ }
+ `ssh $user\@$hcp "$sudo which udevadm &> /dev/null && udevadm settle || udevsettle"`;
+ } else {
+ $subResp = "Done";
+ }
+ }
+ return $subResp
+}
+
+#-------------------------------------------------------
+=head3 genCfgdrive
+
+ Description : Generate a final config drive to punch
+ Arguments : Configure file directory
+
+ Returns : Generated config drive file path
+ Example : my $out = xCAT::zvmUtils->genCfgdrive($path);
+
+=cut
+
+#-------------------------------------------------------
+sub genCfgdrive {
+
+ # Get input node
+ my ( $class, $cfgpath ) = @_;
+ my $node = basename($cfgpath);
+
+ my $out = xCAT::zvmUtils->injectMNKey($cfgpath);
+ if ( $out =~ m/Failed/i ) {
+ xCAT::zvmUtils->printSyslog("genCfgdrive() Failed to generate the final cfgdrive.tgz for target node: $node, out: $out");
+ return "";
+ } else {
+ xCAT::zvmUtils->printSyslog("genCfgdrive() Successfully generated the final cfgdrive.tgz for target node: $node");
+ return "$cfgpath/cfgdrive.tgz";
+ }
+}
+
+#-------------------------------------------------------
+=head3 injectMNKey
+
+ Description : Inject xCAT MN's public key to the meta_data.json for target vm
+ Arguments : Configure file directory
+
+ Returns : A message indicate whether the MN's key in injected success or not
+ Example : my $out = xCAT::zvmUtils->injectMNKey($path);
+
+=cut
+
+#-------------------------------------------------------
+
+sub injectMNKey {
+
+ # Get input node
+ my ( $class, $cfgpath ) = @_;
+ my $subResp = "";
+
+ if ( -e "$cfgpath/cfgdrive.tgz" ) {
+ system("tar -zxf $cfgpath/cfgdrive.tgz -C $cfgpath ");
+ } else {
+ $subResp = "injectMNKey() Failed to find the cfgdrive.tgz under $cfgpath for target node";
+ return $subResp;
+ }
+
+ # Get xcat key, store it to a hash var for later use
+ open(my $keyFile, '<', "/root/.ssh/id_rsa.pub");
+ my $mnKey = <$keyFile>;
+ close($keyFile);
+ my @set = ('0' ..'9', 'A' .. 'F');
+ my $mnKeyName = join '' => map $set[rand @set], 1 .. 8;
+ my %mnKeyHash = ("name" => $mnKeyName, "type" => "ssh", "data" => $mnKey,);
+
+ # Read the file content to a variable named md_json,and close the source file
+ my $jsonText;
+ my $MDfile;
+ if(open($MDfile, '<', "$cfgpath/openstack/latest/meta_data.json")) {
+ while(<$MDfile>) {
+ $jsonText .= "$_";
+ }
+ } else {
+ $subResp = "injectMNKey() Failed to open the meta data file for processing";
+ close($MDfile);
+ return $subResp;
+ }
+ close($MDfile);
+
+ # Get the public_keys from meta_data.json, if it not exist, add xCAT's key to meta_data.json directly,
+ # if already exist, compare if the xCAT's key is same or not with existing one, append xCAT key if not same
+ my $md_json = decode_json($jsonText);
+ if (exists $md_json->{"public_keys"}) {
+ my $publicKeys = $md_json->{"public_keys"};
+ # Check if xCAT key already exist , append it if not exist.
+ foreach my $pubkey ( keys %$publicKeys ) {
+ if ( $publicKeys->{$pubkey} eq $mnKey ) {
+ last;
+ }
+ $publicKeys->{$mnKeyName} = $mnKey;
+ my @tkeys = $md_json->{"keys"};
+ push @tkeys, {%mnKeyHash};
+ #push $md_json->{"keys"}, {%mnKeyHash};
+ }
+ } else {
+ # Set the public_keys and keys with xCAT's key info in meta_data.json
+ $md_json->{"public_keys"}->{$mnKeyName} = $mnKey;
+ $md_json->{"keys"}[0] = {%mnKeyHash};
+ }
+
+ # Save the changed meta_data.json to new file
+ open my $fh, ">", "$cfgpath/meta_data.json";
+ print $fh encode_json($md_json);
+ close $fh;
+
+ # Replace the meta_data.json file in original config drive with the modified one
+ system( "find $cfgpath/openstack -name meta_data.json -print | xargs -i cp $cfgpath/meta_data.json {}");
+ `rm -f $cfgpath/meta_data.json`;
+
+ # Tar the file generate the final one
+ my $oldpath=cwd();
+ chdir($cfgpath);
+ system ( "tar -zcf cfgdrive.tgz openstack ec2");
+ chdir($oldpath);
+
+ $subResp = "Done";
+ return $subResp;
+}
+
+#-------------------------------------------------------
+
+=head3 execcmdthroughIUCV
+
+ Description : Execute a command to node with IUCV client.
+ Arguments : User (root or non-root).
+ zHCP (opencloud user)
+ VM's userid
+ command [parms..] the comands and parms with the command which need to execute.
+ callback
+
+ Returns : command result, if success.
+ if an error:
+ and $callback then $callback gets error message
+ returns with string containing (Error) and message
+ Example : my $out = xCAT::zvmUtils->execcmdthroughIUCV($user, $hcp, $userid, $command);
+
+=cut
+
+#-------------------------------------------------------
+sub execcmdthroughIUCV {
+ my ($class, $user, $hcp, $userid, $commandwithparm, $callback) = @_;
+ my $result = '';
+ my $rsp;
+ my $msg;
+ my $iucvpath = '/opt/zhcp/bin/IUCV';
+ my $isCallback = 0;
+ if (defined $callback) {
+ $isCallback = 1;
+ }
+ $result= `ssh $user\@$hcp $::SUDO $iucvpath/iucvclnt $userid "\'$commandwithparm\'" 2>&1`;
+
+ my $rc = $? >> 8;
+ $result = xCAT::zvmUtils->trimStr( $result );
+ if ( $isCallback || $rc == 0 ){
+ xCAT::zvmUtils->printSyslog("$userid: IUCV command: ssh $user\@$hcp $::SUDO $iucvpath/iucvclnt $userid $commandwithparm. return $rc\n $result");
+ } else {
+ xCAT::zvmUtils->printSyslog("$userid: IUCV command: ssh $user\@$hcp $::SUDO $iucvpath/iucvclnt $userid $commandwithparm.");
+ }
+ if ( $rc == 0 ) {
+ if ($result eq ''){
+ return "Done";
+ }
+ return $result;
+ } elsif ( $rc == 1 ) {
+ $msg = "Issued command was not authorized or a generic Linux error occurred. error details $result";
+ push @{$rsp->{data}}, $msg;
+ } elsif ( $rc == 2 ) {
+ $msg = "parameter to iucvclient error, $result";
+ push @{$rsp->{data}}, $msg
+ } elsif ( $rc == 4 ) {
+ $msg = "IUCV socket error, error details $result";
+ push @{$rsp->{data}}, $msg;
+ } elsif ( $rc == 8 ) {
+ $msg = "Command executed failed, error details $result";
+ push @{$rsp->{data}}, $msg;
+ } elsif ( $rc == 16 ) {
+ $msg = "File Transport failed, error details $result";
+ push @{$rsp->{data}}, $msg;
+ } elsif ( $rc == 32 ) {
+ $msg = "File Transport failed, error details $result";
+ push @{$rsp->{data}}, $msg;
+ }
+
+ # Error occurred
+ if ($isCallback){
+ xCAT::MsgUtils->message( "E", $rsp, $callback );
+ }
+ return "(Error) $msg";
+}
+
+#-------------------------------------------------------
+
+=head3 cleanIUCV
+
+ Description : rollback IUCV to clean all the files that copy to it.
+ Arguments : User (root or non-root).
+ VM's node
+ VM's system
+
+ Returns : Nothing
+ Example : xCAT::zvmUtils->cleanIUCV( $user, $hcp, $userid);
+
+=cut
+
+#-------------------------------------------------------
+sub cleanIUCV {
+ my ($class, $user, $node, $os) = @_;
+
+ my $sudo = "sudo";
+ if ($user eq "root") {
+ $sudo = "";
+ }
+
+ my $result = '';
+ my $outmsg = '';
+ my $cmd = '';
+ my $rc;
+ my $trgtiucvpath = "/usr/bin/iucvserv";
+ my $trgtiucvservicepath_rh6_sl11 = "/etc/init.d/iucvserd";
+ my $trgtiucvservicepath_rh7 = "/lib/systemd/system/iucvserd.service";
+ my $trgtiucvservicepath_ubuntu16 = "/lib/systemd/system/iucvserd.service";
+ my $trgtiucvservicepath_sl12 = "/usr/lib/systemd/system/iucvserd.service";
+
+ #clean iucv server file
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvpath 2>&1";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvpath 2>&1`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "cleanIUCV", $result, $result, $node );
+ # Continue processing even if an error.
+
+ #clean iucv server service file
+ if ( $os =~ m/sles11/i or $os =~ m/rhel6/i ) {
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_rh6_sl11 2>&1";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_rh6_sl11 2>&1`;
+ }
+ elsif ( $os =~ m/sles12/i ) {
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_sl12 2>&1";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_sl12 2>&1`;
+ }
+ elsif ( $os =~ m/rhel7/i){
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_rh7 2>&1";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_rh7 2>&1`;
+ } elsif ( $os =~ m/ubuntu16/i){
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_ubuntu16 2>&1";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_ubuntu16 2>&1`;
+ }
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "cleanIUCV", $result, $node );
+ # Continue processing even if an error.
+
+ #clean iucv server authorized file
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvpath 2>&1";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvpath 2>&1`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "cleanIUCV", $result, $node );
+ # Continue processing even if an error.
+
+ #clean iucv server service start
+ if ( $os =~ m/sles11/i or $os =~ m/rhel6/i ){
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node \"chkconfig --del iucvserd && service iucvserd stop 2>&1";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node "chkconfig --del iucvserd && service iucvserd stop 2>&1"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "cleanIUCV", $result, $node );
+ # Continue processing even if an error.
+ }else{
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node \"systemctl disable iucvserd.service && systemctl stop iucvserd.service 2>&1";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node "systemctl disable iucvserd.service && systemctl stop iucvserd.service 2>&1"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "cleanIUCV", $result, $node );
+ # Continue processing even if an error.
+ }
+}
+
+#-------------------------------------------------------
+
+=head3 setsshforvm
+
+ Description : If IUCV communication failed, try to use ssh to make communication.
+ Arguments : User (root or non-root).
+ VM's node
+ VM's linux system type
+ command [parms..] the comands and parms with the command which need to execute.
+ error message which is got in setup IUCV
+ current VM's status in zvm table
+ callback
+
+ Returns : command result, if success.
+ if an error:
+ and $callback then $callback gets error message and routine returns with 1
+ if no $callback then routine returns with string containing Error: and message
+ Example : my $out = xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+
+=cut
+
+#-------------------------------------------------------
+
+sub setsshforvm {
+ my ($class, $user, $node, $os, $commandwithparm, $msg, $status, $callback) = @_;
+ my $result ='';
+ my $rsp;
+ my $isCallback = 0;
+ my $outmsg = '';
+ my $rc;
+ if (defined $callback) {
+ $isCallback = 1;
+ }
+
+ #clean IUCV server first.
+ $result = xCAT::zvmUtils->cleanIUCV($user, $node, $os);
+ if (xCAT::zvmUtils->checkOutput( $result ) == -1) {
+ return $result;
+ }
+ # check whether the vm can be ping, if so then set ssh to zvm table,
+ # to indicate that it use ssh.
+ my $ping = `ping -W 2 -c 2 -q $node`;
+ if ($? == 0) {
+ my $cmd = "ssh -o ConnectTimeout=5 $user\@$node \"$commandwithparm\"";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node "$commandwithparm"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "setsshforvm", $result, $node );
+ if ($rc == 255) {
+ if ($isCallback){
+ xCAT::zvmUtils->printLn( $callback, "$outmsg");
+ }
+ # Continue processing even if an error.
+ }
+
+ if ($status){
+ $status = "$status;SSH=1";
+ }else{
+ $status = "SSH=1";
+ }
+ xCAT::zvmUtils->setNodeProp( 'zvm', $node, 'status', $status );
+ xCAT::zvmUtils->printSyslog("$node: Set SSH=1 for node $node");
+ if ($isCallback){
+ xCAT::zvmUtils->printLn( $callback, "$node: Set SSH=1 for node $node.");
+ }
+ return $result;
+ }
+
+ # Error occurred on ping
+ if ($callback){
+ push @{$rsp->{data}}, $msg;
+ xCAT::MsgUtils->message( "E", $rsp, $callback );
+ }
+ xCAT::zvmUtils->printSyslog("$node: $msg");
+ return "$msg";
+}
+
+#-------------------------------------------------------
+
+=head3 execcmdonVM
+
+ Description : Execute a command to node.
+ Arguments : User (root or non-root).
+ VM's node
+ command [parms..] the comands and parms with the command which need to execute.
+ callback
+
+ Returns : command result, if success.
+ if an error:
+ and $callback then $callback gets error message
+ routine returns with string containing Error: and message
+
+ Example : my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $commandwithparm, $callback);
+
+=cut
+
+#-------------------------------------------------------
+sub execcmdonVM {
+ my ($class, $user, $node, $commandwithparm, $callback) = @_;
+
+ # get HCP and z/VM userid
+ my @propNames = ( 'hcp', 'userid', 'status' );
+ my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
+ my $status = $propVals->{'status'};
+ if(!(defined($status))){
+ $status = '';
+ }
+ my $hcp = $propVals->{'hcp'};
+ my $userid = $propVals->{'userid'};
+ my $isCallback = 0;
+ if (defined $callback) {
+ $isCallback = 1;
+ }
+
+ my $result = '';
+ my $outmsg = '';
+ my $rsp;
+ my $rc;
+ my $msg = '';
+ my $cmd = '';
+ my $opnclouduserid='OPNCLOUD';
+ my $simplecmd = 'date';
+
+ # Create path string
+ my $dest = "$user\@$node";
+ my $srciucvpath = '/opt/zhcp/bin/IUCV';
+ my $trgtiucvpath = "/usr/bin/iucvserv";
+ my $trgtiucvservicepath_rh6_sl11 = "/etc/init.d/iucvserd";
+ my $trgtiucvservicepath_rh7 = "/lib/systemd/system/iucvserd.service";
+ my $trgtiucvservicepath_sl12 = "/usr/lib/systemd/system/iucvserd.service";
+ my $trgtiucvservicepath_ubuntu16 = "/lib/systemd/system/iucvserd.service";
+ my $authorizedfilepath = "/etc/iucv_authorized_userid";
+ my $xcatuserid = `vmcp q userid | awk '{print \$1}'`;
+ chomp($xcatuserid);
+
+ # Add escape for IUCV and SSH commands.
+ if ($commandwithparm =~ '\\\"'){
+ $commandwithparm =~ s/"/\\"/g;
+ }
+ $commandwithparm =~ s/"/\\"/g;
+
+ # For not xcat deployed node, use SSH to make communication.
+ if (!(defined($userid)) || !(defined($hcp))){
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node \"$commandwithparm\"";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node "$commandwithparm"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "execcmdonVM", $result, $node );
+ if ($rc == 255) {
+ if ($isCallback){
+ xCAT::zvmUtils->printLn( $callback, "$outmsg");
+ }
+ }
+ # Remove IUCV=1 if it has been set
+ if ($status =~ /IUCV=1/){
+ $status =~ s/IUCV=1/SSH=1/g;
+ xCAT::zvmUtils->setNodeProp( 'zvm', $node, 'status', $status );
+ }
+ return $result;
+ }
+
+ $userid =~ tr/a-z/A-Z/;
+ # For normal managed nodes, ask zhcp to query the power state
+ if (($userid ne $xcatuserid) && !($hcp =~ /$node/) && ($hcp ne '')){
+ # Get VM's power stat first, if power stat is off, return error.
+ my $max = 0;
+ while ( !$result && $max < 10 ) {
+ $cmd = "ssh $::SUDOER\@$hcp \"$::SUDO /sbin/vmcp q user $userid 2>/dev/null\" | sed 's/HCPCQU045E.*/off/' | sed 's/$userid.*/on/'";
+ $result = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp q user $userid 2>/dev/null" | sed 's/HCPCQU045E.*/off/' | sed 's/$userid.*/on/'`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $hcp, "execcmdonVM", $result, $node );
+ if ($rc == 255) {
+ if ($isCallback){
+ xCAT::zvmUtils->printLn( $callback, "$outmsg");
+ }
+ return $outmsg;
+ }
+ $max++;
+ }
+ #xCAT::zvmUtils->printSyslog("$node: ssh $::SUDOER\@$hcp \"$::SUDO /sbin/vmcp q user $userid 2>/dev/null\" | sed 's/HCPCQU045E.*/off/' | sed 's/$userid.*/on/' ##$result##");
+ if ("off" =~ $result) {
+ my $msgText = "$node: (Error) VM $userid is powered off";
+ xCAT::zvmUtils->printSyslog("$msgText");
+ if ($isCallback) {
+ xCAT::zvmUtils->printLn( $callback, "$msgText");
+ }
+ return "$msgText";
+ }
+
+ if (!($status =~ /SSH=1/) && !($status =~ /IUCV=1/)){
+ # if zhcp direct entry does set "IUCV ANY", will set to SSH directly.
+ my $hcpUserId = xCAT::zvmCPUtils->getUserId($user, $hcp);
+ @propNames = ( 'status' );
+ $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $hcp, @propNames );
+ my $iucvanystatus = $propVals->{'status'};
+ if (!($iucvanystatus =~ m/IUCVANY/i)){
+ xCAT::zvmUtils->printSyslog("$node: zhcp's IUCVANY status is not set");
+ my $out = `ssh $user\@$hcp "$::SUDO /opt/zhcp/bin/smcli Image_Query_DM -T $hcpUserId"| egrep -i "IUCV ANY"`;
+ if ( $out =~ m/IUCV ANY/i){
+ if ($iucvanystatus){
+ $iucvanystatus = "$status;IUCVANY=1";
+ }else{
+ $iucvanystatus = "IUCVANY=1";
+ }
+ }else{
+ if ($iucvanystatus){
+ $iucvanystatus = "$status;IUCVANY=0";
+ }else{
+ $iucvanystatus = "IUCVANY=0";
+ }
+ }
+ xCAT::zvmUtils->setNodeProp( 'zvm', $hcp, 'status', $iucvanystatus );
+ xCAT::zvmUtils->printSyslog("$node: zhcp's status is $iucvanystatus");
+ }
+ if ($iucvanystatus =~ m/IUCVANY=0/i){
+ xCAT::zvmUtils->printSyslog("$node: zhcp doesn't support to make communication with IUCV, set SSH=1 for $node");
+ if ($status){
+ $status = "$status;SSH=1";
+ }else{
+ $status = "SSH=1";
+ }
+ xCAT::zvmUtils->setNodeProp( 'zvm', $node, 'status', $status );
+ }
+ }
+ }
+
+ # If node userid is xcat or zhcp, only use SSH.
+ if (($status =~ /SSH=1/) || ($userid eq $xcatuserid) || ($hcp =~ /$node/) || ($hcp eq '')){
+ # SSH=1, Use ssh to make communication.
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node \"$commandwithparm\"";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node "$commandwithparm"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "execcmdonVM", $result, $node );
+ if ($rc == 255) {
+ if ($isCallback){
+ xCAT::zvmUtils->printLn( $callback, "$outmsg");
+ }
+ }
+ return $result;
+ }elsif ($status =~ /IUCV=1/){
+ #xCAT::zvmUtils->printSyslog("$node: IUCV command: $commandwithparm");
+ # IUCV=1, Use IUCV to make communication.
+ $result = xCAT::zvmUtils->execcmdthroughIUCV($user, $hcp, $userid, $commandwithparm, $callback);
+ return $result;
+ }
+
+ xCAT::zvmUtils->printSyslog("$node: VM $userid doesn't set communicate type, will set it first." );
+ my $releaseInfo = `ssh -qo ConnectTimeout=2 $user\@$node "$::SUDO ls /dev/null $locAllEtcVerFiles 2>/dev/null | xargs grep ''"`;
+ if (xCAT::zvmUtils->checkOutput( $releaseInfo ) == -1) {
+ return $releaseInfo;
+ }
+ my $os = buildOsVersion( $callback, $releaseInfo, 'all' );
+
+ # For the existed VMs which are deployed with SSH, will try to copy IUCV files to them.
+ # These VMs are not set communication type, try IUCV first and set the type after communication.
+ # if IUCV server doesn't exist on xcat /var/lib/sspmod, first to copy from OPNCLOUD.
+ if ( not (-e "$srciucvpath/iucvserv" and -e "$srciucvpath/iucvserd"
+ and -e "$srciucvpath/iucvserd.service" )) {
+ $result= `mkdir -p $srciucvpath && scp -p $user\@$hcp:$srciucvpath/iucvser* $srciucvpath 2>&1`;
+ $rc = $? >>8 ;
+ xCAT::zvmUtils->printSyslog("$node: IUCV server files doesn't exist on xcat $srciucvpath, copy from OPNCLOUD.return $rc, $result");
+ if ($rc != 0) {
+ $msg = "Failed to copy $user\@$hcp:$srciucvpath/iucvser* to $srciucvpath. $result";
+ return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+ }
+ }
+ # Check whether IUCV server is installed.
+ $result = xCAT::zvmUtils->execcmdthroughIUCV($user, $hcp, $userid, $commandwithparm, $callback);
+ $rc = $? >> 8;
+ xCAT::zvmUtils->printSyslog("$node: try to execute command through IUCV. $result return $?" );
+ if ( $rc != 0 ){
+ #IUCV server doesn't exist on node, copy file to it and restart service
+ if ($result =~ "ERROR connecting socket") {
+ xCAT::zvmUtils->printSyslog("$node: start to set iucv, first to copy iucv server files and start iucv server service" );
+ #copy IUCV server files.
+ $result = `/usr/bin/scp -p $srciucvpath/iucvserv $dest:$trgtiucvpath 2>&1`;
+ $rc = $? >> 8;
+ xCAT::zvmUtils->printSyslog("$node: /usr/bin/scp -p $srciucvpath/iucvserv $dest:$trgtiucvpath 2>&1 return $rc\n $result");
+ if ($rc != 0) {
+ $msg = "Failed to copy $srciucvpath/iucvserv to $dest:$trgtiucvpath. $result";
+ return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+ }
+ if ( $os =~ m/sles11/i or $os =~ m/rhel6/i ) {
+ $result = `/usr/bin/scp -p $srciucvpath/iucvserd $dest:$trgtiucvservicepath_rh6_sl11 2>&1`;
+ }
+ elsif ( $os =~ m/sles12/i ) {
+ $result = `/usr/bin/scp -p $srciucvpath/iucvserd.service $dest:$trgtiucvservicepath_sl12 2>&1`;
+ }
+ elsif ( $os =~ m/rhel7/i){
+ $result = `/usr/bin/scp -p $srciucvpath/iucvserd.service $dest:$trgtiucvservicepath_rh7 2>&1`;
+ } elsif ( $os =~ m/ubuntu16/i){
+ # Note: we should not encounter this line as we don't have ubuntu support before IUCV enablement
+ $result = `/usr/bin/scp -p $srciucvpath/iucvserd.service $dest:$trgtiucvservicepath_ubuntu16 2>&1`;
+ }
+ $rc = $? >> 8;
+ xCAT::zvmUtils->printSyslog("$node: /usr/bin/scp -p iucv service file return $rc $result");
+ if ($rc != 0) {
+ $msg = "Failed to copy iucvservice file. $result";
+ return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+ }
+ $opnclouduserid = xCAT::zvmCPUtils->getUserId($user, $hcp);
+ $opnclouduserid =~ tr/a-z/A-Z/;
+ if ($rc !=0) {
+ $msg = "failed to get OPNCLOUD userid. return $? \n$result";
+ return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+ }
+
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node \"echo -n $opnclouduserid >$authorizedfilepath\" 2>&1";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node "echo -n $opnclouduserid >$authorizedfilepath" 2>&1`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "execcmdonVM", $result, $node );
+ if ($rc != 0) {
+ if ($isCallback){
+ xCAT::zvmUtils->printLn( $callback, "$outmsg");
+ }
+ $msg = "echo -n $hcp >$authorizedfilepath, failed to create authorized userid for $node. return $rc $result";
+ return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+ }
+
+ # Start service of IUCV server
+ if ( $os =~ m/sles11/i or $os =~ m/rhel6/i ){
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node \"chkconfig --add iucvserd && service iucvserd start 2>&1\"";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node "chkconfig --add iucvserd && service iucvserd start 2>&1"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "execcmdonVM", $result, $node );
+ if ($rc != 0) {
+ if ($isCallback){
+ xCAT::zvmUtils->printLn( $callback, "$outmsg");
+ }
+ $msg = "echo -n $hcp >$authorizedfilepath, failed to create authorized userid for $node. return $rc $result";
+ return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+ }
+ }else{
+ $cmd = "ssh -o ConnectTimeout=5 $user\@$node \"systemctl enable iucvserd.service && systemctl start iucvserd.service 2>&1\"";
+ $result = `ssh -o ConnectTimeout=5 $user\@$node "systemctl enable iucvserd.service && systemctl start iucvserd.service 2>&1"`;
+ ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "execcmdonVM", $result, $node );
+ if ($rc != 0) {
+ if ($isCallback){
+ xCAT::zvmUtils->printLn( $callback, "$outmsg");
+ }
+ $msg = "echo -n $hcp >$authorizedfilepath, failed to create authorized userid for $node. return $rc $result";
+ return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+ }
+ }
+ $rc = $? >> 8;
+ xCAT::zvmUtils->printSyslog("$node: start iucvserver service return $rc. $result");
+ # Now that the IUCV server has started successfully, send a simple command
+ if ($rc == 0) {
+ $result = xCAT::zvmUtils->execcmdthroughIUCV($user, $hcp, $userid, $simplecmd, $callback);
+ # The simple command worked! Update the zvm table so we always communicate via IUCV
+ if ($? == 0){
+ xCAT::zvmUtils->printSyslog("$node: successfully initialized IUCV, Set IUCV=1 for $user");
+ if ($callback){
+ xCAT::zvmUtils->printLn( $callback, "$node: successfully initialized IUCV, Set IUCV=1 for $user");
+ }
+ if ($status){
+ $status = "$status;IUCV=1";
+ }else{
+ $status = "IUCV=1";
+ }
+ xCAT::zvmUtils->setNodeProp( 'zvm', $node, 'status', $status );
+ return xCAT::zvmUtils->execcmdthroughIUCV($user, $hcp, $userid, $commandwithparm, $callback);
+ }else{
+ $msg = "$node: Failed to start iucvserver, result is $result";
+ return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+ }
+ } else {
+ $msg = "$node: Failed to start iucvserver, result is $result";
+ return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+ }
+ # If our command failed, just return the error
+ } elsif ($result =~ /Command executed failed/) {
+ return $result;
+ } else {
+ $msg = "$node: IUCV server on VM got another error that is not a socket error, result is $result";
+ return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
+ }
+ } else {
+ $msg = "IUCV has worked well, set IUCV=1 for $user .";
+ if ($status) {
+ $status = "$status;IUCV=1";
+ } else {
+ $status = "IUCV=1";
+ }
+ xCAT::zvmUtils->setNodeProp( 'zvm', $node, 'status', $status );
+ return $result;
+ }
+
+}
diff --git a/xCAT-UI/js/configure/configure.js b/xCAT-UI/js/configure/configure.js
index 33cac8c41..79cff6f25 100644
--- a/xCAT-UI/js/configure/configure.js
+++ b/xCAT-UI/js/configure/configure.js
@@ -1,560 +1,558 @@
-/**
- * Global variables
- */
-var configTabs; // Config tabs
-var configDatatables = new Object(); // Datatables on the config page
-
-/**
- * Set the datatable
- *
- * @param id The ID of the datatable
- * @param obj Datatable object
- */
-function setConfigDatatable(id, obj) {
- configDatatables[id] = obj;
-}
-
-/**
- * Get the datatable with the given ID
- *
- * @param id The ID of the datatable
- * @return Datatable object
- */
-function getConfigDatatable(id) {
- return configDatatables[id];
-}
-
-/**
- * Set the configure tab
- *
- * @param obj Tab object
- */
-function setConfigTab(obj) {
- configTabs = obj;
-}
-
-/**
- * Get the configure tab
- *
- * @param Nothing
- * @return Tab object
- */
-function getConfigTab() {
- return configTabs;
-}
-
-/**
- * Load configure page
- */
-function loadConfigPage() {
- // If the configure page has already been loaded
- if ($('#content').children().length) {
- // Do not reload configure page
- return;
- }
-
- // Create configure tab
- var tab = new Tab();
- setConfigTab(tab);
- tab.init();
- $('#content').append(tab.object());
-
- // Create loader
- var loader = $('
').append(createLoader());
-
- // Add tab to configure xCAT tables
- tab.add('configTablesTab', 'Tables', loader, false);
-
- // Add the update tab
-// tab.add('updateTab', 'Update', '', false);
-
- // Add the Users tab
- tab.add('usersTab', 'Users', '', false);
-
- // Add the discover tab
-// tab.add('discoverTab', 'Discover', '', false);
-
- // Add the self-service tab
-// tab.add('serviceTab', 'Service', '', false);
-
- // Add the files tab
- tab.add('filesTab', 'Files', '', false);
-
- // Get list of tables and their descriptions
- $.ajax({
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'tabdump',
- tgt : '',
- args : '-d',
- msg : ''
- },
-
- success : loadTableNames
- });
-
- // Do not load everything at once
- // Load when tab is shown
- tab.object().bind('tabsshow', function(event, ui) {
- if ($(ui.panel).children().length) {
- return;
- }
-
- if (ui.index == 1) {
- loadUserPage();
- } else if (ui.index == 2) {
- loadServicePage();
- } else if (ui.index == 3) {
- loadFilesPage();
-// loadDiscoverPage();
-// } else if (ui.index == 4) {
-// loadServicePage();
- }
- });
-}
-
-/**
- * Load xCAT database table names and their descriptions
- *
- * @param data Data returned from HTTP request
- */
-function loadTableNames(data) {
- // Get output
- var tables = data.rsp;
-
- // Remove loader
- var tabId = 'configTablesTab';
- $('#' + tabId).find('img').hide();
-
- // Create a groups division
- var tablesDIV = $('');
- $('#' + tabId).append(tablesDIV);
-
- // Create info bar
- var infoBar = createInfoBar('Select a table to view or edit.');
- tablesDIV.append(infoBar);
-
- // Create a list for the tables
- var list = $('
');
- // Loop through each table
- for ( var i = 0; i < tables.length; i++) {
- // Create a link for each table
- var args = tables[i].split(':');
- var link = $('' + args[0] + '');
-
- // Open table on click
- link.bind('click', function(e) {
- // Get table ID that was clicked
- var id = (e.target) ? e.target.id : e.srcElement.id;
-
- // Create loader
- var loader = $('
').append(createLoader());
-
- // Add a new tab for this table
- var configTab = getConfigTab();
- if (!$('#' + id + 'Tab').length) {
- configTab.add(id + 'Tab', id, loader, true);
-
- // Get contents of selected table
- $.ajax({
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'tabdump',
- tgt : '',
- args : id,
- msg : id
- },
-
- success : loadTable
- });
- }
-
- // Select new tab
- configTab.select(id + 'Tab');
- });
-
- var item = $('');
- item.append(link);
-
- // Append the table description
- item.append(': ' + args[1]);
-
- // Append item to list
- list.append(item);
- }
-
- tablesDIV.append(list);
-}
-
-/**
- * Load a given database table
- *
- * @param data Data returned from HTTP request
- */
-function loadTable(data) {
- // Get response
- var rsp = data.rsp;
- // Get table ID
- var id = data.msg;
-
- // Remove loader
- var tabId = id + 'Tab';
- $('#' + tabId).find('img').remove();
-
- // Create info bar
- var infoBar = createInfoBar('Click on a cell to edit. Click outside the table to write to the cell. Once you are satisfied with how the table looks, click on Save.');
- $('#' + tabId).append(infoBar);
-
- // Create action bar
- var actionBar = $('');
- $('#' + tabId).append(actionBar);
-
- // Get table headers
- var args = rsp[0].replace('#', '');
- var headers = args.split(',');
-
- // Create container for original table contents
- var origCont = new Array(); // Original table content
- origCont[0] = rsp[0].split(','); // Headers
-
- // Create container for new table contents
- var newCont = new Object();
- var tmp = new Object();
- tmp[0] = '#' + headers[0]; // Put a # in front of the header
- for ( var i = 1; i < headers.length; i++) {
- tmp[i] = headers[i];
- }
- newCont[0] = tmp;
-
- // Create a new datatable
- var tableId = id + 'Datatable';
- var table = new DataTable(tableId);
-
- // Add column for the remove row button
- headers.unshift('');
- table.init(headers);
- headers.shift();
-
- // Append datatable to tab
- $('#' + tabId).append(table.object());
-
- // Add table rows
- // Start with the 2nd row (1st row is the headers)
- for ( var i = 1; i < rsp.length; i++) {
- // Split into columns
- var cols = rsp[i].split(',');
-
- // Go through each column
- for ( var j = 0; j < cols.length; j++) {
-
- // If the column is not complete
- if (cols[j].count('"') == 1) {
- while (cols[j].count('"') != 2) {
- // Merge this column with the adjacent one
- cols[j] = cols[j] + "," + cols[j + 1];
-
- // Remove merged row
- cols.splice(j + 1, 1);
- }
- }
-
- // Replace quote
- cols[j] = cols[j].replace(new RegExp('"', 'g'), '');
- }
-
- // Add remove button
- cols.unshift('');
-
- // Add row
- table.add(cols);
-
- // Save original table content
- origCont[i] = cols;
- }
-
- // Turn table into datatable
- var dTable = $('#' + id + 'Datatable').dataTable({
- 'iDisplayLength': 50,
- 'bLengthChange': false,
- "bScrollCollapse": true,
- "sScrollY": "400px",
- "sScrollX": "110%",
- "bAutoWidth": true,
- "oLanguage": {
- "oPaginate": {
- "sNext": "",
- "sPrevious": ""
- }
- }
- });
-
- /**
- * Enable editable columns
- */
- // Do not make 1st column editable
- $('#' + tableId + ' td:not(td:nth-child(1))').editable(
- function(value, settings) {
- // Get column index
- var colPos = this.cellIndex;
- // Get row index
- var rowPos = dTable.fnGetPosition(this.parentNode);
-
- // Update datatable
- dTable.fnUpdate(value, rowPos, colPos);
-
- return (value);
- }, {
- onblur : 'submit', // Clicking outside editable area submits changes
- type : 'textarea',
- placeholder: ' ',
- height : '30px' // The height of the text area
- });
-
- // Create action bar
- var actionBar = $('');
-
- var saveLnk = $('Save');
- saveLnk.click(function() {
- // Get table ID and name
- var tableId = $(this).parents('.dataTables_wrapper').attr('id').replace('_wrapper', '');
- var tableName = tableId.replace('Datatable', '');
-
- // Get datatable
- var dTable = $('#' + tableId).dataTable();
- // Get the nodes from the table
- var dRows = dTable.fnGetNodes();
-
- // Go through each row
- for ( var i = 0; i < dRows.length; i++) {
- // If there is row with values
- if (dRows[i]) {
- // Go through each column
- // Ignore the 1st column because it is a button
- var cols = dRows[i].childNodes;
- var vals = new Object();
- for ( var j = 1; j < cols.length; j++) {
- var val = cols.item(j).firstChild.nodeValue;
-
- // Insert quotes
- if (val == ' ') {
- vals[j - 1] = '';
- } else {
- vals[j - 1] = val;
- }
- }
-
- // Save row
- newCont[i + 1] = vals;
- }
- }
-
- // Update xCAT table
- $.ajax({
- type : 'POST',
- url : 'lib/tabRestore.php',
- dataType : 'json',
- data : {
- table : tableName,
- cont : newCont
- },
- success : function(data) {
- // Create info message
- var dialog = $('').append(createInfoBar('Changes saved!'));
-
- // Open dialog
- dialog.dialog({
- modal: true,
- title: 'Info',
- width: 400,
- buttons: {
- "Ok": function(){
- $(this).dialog("close");
- }
- }
- });
- }
- });
- });
-
- var undoLnk = $('Undo');
- undoLnk.click(function() {
- // Get table ID
- var tableId = $(this).parents('.dataTables_wrapper').attr('id').replace('_wrapper', '');
-
- // Get datatable
- var dTable = $('#' + tableId).dataTable();
-
- // Clear entire datatable
- dTable.fnClearTable();
-
- // Add original content back into datatable
- for ( var i = 1; i < origCont.length; i++) {
- dTable.fnAddData(origCont[i], true);
- }
-
- // Enable editable columns (again)
- // Do not make 1st column editable
- $('#' + tableId + ' td:not(td:nth-child(1))').editable(
- function(value, settings) {
- // Get column index
- var colPos = this.cellIndex;
- // Get row index
- var rowPos = dTable.fnGetPosition(this.parentNode);
-
- // Update datatable
- dTable.fnUpdate(value, rowPos, colPos);
-
- return (value);
- }, {
- onblur : 'submit', // Clicking outside editable area submits changes
- type : 'textarea',
- placeholder: ' ',
- height : '30px' // The height of the text area
- });
- });
-
- var addLnk = $('Add row');
- addLnk.click(function() {
- // Create an empty row
- var row = new Array();
-
- /**
- * Remove button
- */
- row.push('');
- for ( var i = 0; i < headers.length; i++) {
- row.push('');
- }
-
- // Get table ID and name
- var tableId = $(this).parents('.dataTables_wrapper').attr('id').replace('_wrapper', '');
-
- // Get datatable
- var dTable = $('#' + tableId).dataTable();
-
- // Add the row to the data table
- dTable.fnAddData(row);
-
- // Enable editable columns (again)
- // Do not make 1st column editable
- $('#' + tableId + ' td:not(td:nth-child(1))').editable(
- function(value, settings) {
- // Get column index
- var colPos = this.cellIndex;
- // Get row index
- var rowPos = dTable.fnGetPosition(this.parentNode);
-
- // Update datatable
- dTable.fnUpdate(value, rowPos, colPos);
-
- return (value);
- }, {
- onblur : 'submit', // Clicking outside editable area submits changes
- type : 'textarea',
- placeholder: ' ',
- height : '30px' // The height of the text area
- });
- });
-
- // Create an action menu
- var actionsMenu = createMenu([saveLnk, undoLnk, addLnk]);
- actionsMenu.superfish();
- actionsMenu.css('display', 'inline-block');
- actionBar.append(actionsMenu);
-
- // Set correct theme for action menu
- actionsMenu.find('li').hover(function() {
- setMenu2Theme($(this));
- }, function() {
- setMenu2Normal($(this));
- });
-
- // Create a division to hold actions menu
- var menuDiv = $('');
- $('#' + id + 'Datatable_wrapper').prepend(menuDiv);
- menuDiv.append(actionBar);
- $('#' + id + 'Datatable_filter').appendTo(menuDiv);
-}
-
-/**
- * Delete a row in the data table
- *
- * @param obj The object that was clicked
- */
-function deleteRow(obj) {
- // Get table ID
- var tableId = $(obj).parents('table').attr('id');
-
- // Get datatable
- var dTable = $('#' + tableId).dataTable();
-
- // Get all nodes within the datatable
- var rows = dTable.fnGetNodes();
- // Get target row
- var tgtRow = $(obj).parent().parent().get(0);
-
- // Find the target row in the datatable
- for ( var i in rows) {
- // If the row matches the target row
- if (rows[i] == tgtRow) {
- // Remove row
- dTable.fnDeleteRow(i, null, true);
- break;
- }
- }
-}
-
-/**
- * Count the number of occurrences of a specific character in a string
- *
- * @param c Character to count
- * @return The number of occurrences
- */
-String.prototype.count = function(c) {
- return (this.length - this.replace(new RegExp(c, 'g'), '').length)/c.length;
-};
-
-/**
- * Update dialog
- *
- * @param data HTTP request data
- */
-function updatePanel(data) {
- var dialogId = data.msg;
- var infoMsg;
-
- // Create info message
- if (jQuery.isArray(data.rsp)) {
- infoMsg = '';
- for (var i in data.rsp) {
- infoMsg += data.rsp[i] + '';
- }
- } else {
- infoMsg = data.rsp;
- }
-
- // Create info bar with close button
- var infoBar = $('').css('margin', '5px 0px');
- var icon = $('').css({
- 'display': 'inline-block',
- 'margin': '10px 5px'
- });
-
- // Create close button to close info bar
- var close = $('').css({
- 'display': 'inline-block',
- 'float': 'right'
- }).click(function() {
- $(this).parent().remove();
- });
-
- var msg = $('
' + infoMsg + '
').css({
- 'display': 'inline-block',
- 'width': '85%'
- });
-
- infoBar.append(icon, msg, close);
- infoBar.prependTo($('#' + dialogId));
+/**
+ * Global variables
+ */
+var configTabs; // Config tabs
+var configDatatables = new Object(); // Datatables on the config page
+
+/**
+ * Set the datatable
+ *
+ * @param id The ID of the datatable
+ * @param obj Datatable object
+ */
+function setConfigDatatable(id, obj) {
+ configDatatables[id] = obj;
+}
+
+/**
+ * Get the datatable with the given ID
+ *
+ * @param id The ID of the datatable
+ * @return Datatable object
+ */
+function getConfigDatatable(id) {
+ return configDatatables[id];
+}
+
+/**
+ * Set the configure tab
+ *
+ * @param obj Tab object
+ */
+function setConfigTab(obj) {
+ configTabs = obj;
+}
+
+/**
+ * Get the configure tab
+ *
+ * @param Nothing
+ * @return Tab object
+ */
+function getConfigTab() {
+ return configTabs;
+}
+
+/**
+ * Load configure page
+ */
+function loadConfigPage() {
+ // If the configure page has already been loaded
+ if ($('#content').children().length) {
+ // Do not reload configure page
+ return;
+ }
+
+ // Create configure tab
+ var tab = new Tab();
+ setConfigTab(tab);
+ tab.init();
+ $('#content').append(tab.object());
+
+ // Create loader
+ var loader = $('
').append(createLoader());
+
+ // Add tab to configure xCAT tables
+ tab.add('configTablesTab', 'Tables', loader, false);
+
+ // Add the self-service tab
+ tab.add('usersTab', 'Users', '', false);
+
+ // Add the self-service tab
+ tab.add('serviceTab', 'Service', '', false);
+
+ // Add the files tab
+ tab.add('filesTab', 'Files', '', false);
+
+ // Get list of tables and their descriptions
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'tabdump',
+ tgt : '',
+ args : '-d',
+ msg : ''
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ loadTableNames(data);
+ }
+ });
+
+ // Do not load everything at once
+ // Load when tab is shown
+ tab.object().bind('tabsshow', function(event, ui) {
+ if ($(ui.panel).children().length) {
+ return;
+ }
+
+ if (ui.index == 1) {
+ loadUserPage();
+ } else if (ui.index == 2) {
+ loadServicePage();
+ } else if (ui.index == 3) {
+ loadFilesPage();
+ }
+ });
+}
+
+/**
+ * Load xCAT database table names and their descriptions
+ *
+ * @param data Data returned from HTTP request
+ */
+function loadTableNames(data) {
+ // Get output
+ var tables = data.rsp;
+
+ // Remove loader
+ var tabId = 'configTablesTab';
+ $('#' + tabId).find('img').hide();
+
+ // Create a groups division
+ var tablesDIV = $('');
+ $('#' + tabId).append(tablesDIV);
+
+ // Create info bar
+ var infoBar = createInfoBar('Select a table to view or edit.');
+ tablesDIV.append(infoBar);
+
+ // Create a list for the tables
+ var list = $('
');
+ // Loop through each table
+ for ( var i = 0; i < tables.length; i++) {
+ // Create a link for each table
+ var args = tables[i].split(':');
+ var link = $('' + args[0] + '');
+
+ // Open table on click
+ link.bind('click', function(e) {
+ // Get table ID that was clicked
+ var id = (e.target) ? e.target.id : e.srcElement.id;
+
+ // Create loader
+ var loader = $('
').append(createLoader());
+
+ // Add a new tab for this table
+ var configTab = getConfigTab();
+ if (!$('#' + id + 'Tab').length) {
+ configTab.add(id + 'Tab', id, loader, true);
+
+ // Get contents of selected table
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'tabdump',
+ tgt : '',
+ args : id,
+ msg : id
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ loadTable(data);
+ }
+ });
+ }
+
+ // Select new tab
+ configTab.select(id + 'Tab');
+ });
+
+ var item = $('');
+ item.append(link);
+
+ // Append the table description
+ item.append(': ' + args[1]);
+
+ // Append item to list
+ list.append(item);
+ }
+
+ tablesDIV.append(list);
+}
+
+/**
+ * Load a given database table
+ *
+ * @param data Data returned from HTTP request
+ */
+function loadTable(data) {
+ // Get response
+ var rsp = data.rsp;
+ // Get table ID
+ var id = data.msg;
+
+ // Remove loader
+ var tabId = id + 'Tab';
+ $('#' + tabId).find('img').remove();
+
+ // Create info bar
+ var infoBar = createInfoBar('Click on a cell to edit. Click outside the table to write to the cell. Once you are satisfied with how the table looks, click on Save.');
+ $('#' + tabId).append(infoBar);
+
+ // Create action bar
+ var actionBar = $('');
+ $('#' + tabId).append(actionBar);
+
+ // Get table headers
+ var args = rsp[0].replace('#', '');
+ var headers = args.split(',');
+
+ // Create container for original table contents
+ var origCont = new Array(); // Original table content
+ origCont[0] = rsp[0].split(','); // Headers
+
+ // Create container for new table contents
+ var newCont = new Object();
+ var tmp = new Object();
+ tmp[0] = '#' + headers[0]; // Put a # in front of the header
+ for ( var i = 1; i < headers.length; i++) {
+ tmp[i] = headers[i];
+ }
+ newCont[0] = tmp;
+
+ // Create a new datatable
+ var tableId = id + 'Datatable';
+ var table = new DataTable(tableId);
+
+ // Add column for the remove row button
+ headers.unshift('');
+ table.init(headers);
+ headers.shift();
+
+ // Append datatable to tab
+ $('#' + tabId).append(table.object());
+
+ // Add table rows
+ // Start with the 2nd row (1st row is the headers)
+ for ( var i = 1; i < rsp.length; i++) {
+ // Split into columns
+ var cols = rsp[i].split(',');
+
+ // Go through each column
+ for ( var j = 0; j < cols.length; j++) {
+
+ // If the column is not complete
+ if (cols[j].count('"') == 1) {
+ while (cols[j].count('"') != 2) {
+ // Merge this column with the adjacent one
+ cols[j] = cols[j] + "," + cols[j + 1];
+
+ // Remove merged row
+ cols.splice(j + 1, 1);
+ }
+ }
+
+ // Replace quote
+ cols[j] = cols[j].replace(new RegExp('"', 'g'), '');
+ }
+
+ // Add remove button
+ cols.unshift('');
+
+ // Add row
+ table.add(cols);
+
+ // Save original table content
+ origCont[i] = cols;
+ }
+
+ // Turn table into datatable
+ var dTable = $('#' + id + 'Datatable').dataTable({
+ 'iDisplayLength': 50,
+ 'bLengthChange': false,
+ "bScrollCollapse": true,
+ "sScrollY": "400px",
+ "sScrollX": "110%",
+ "bAutoWidth": true,
+ "oLanguage": {
+ "oPaginate": {
+ "sNext": "",
+ "sPrevious": ""
+ }
+ }
+ });
+
+ /**
+ * Enable editable columns
+ */
+ // Do not make 1st column editable
+ $('#' + tableId + ' td:not(td:nth-child(1))').editable(
+ function(value, settings) {
+ // Get column index
+ var colPos = this.cellIndex;
+ // Get row index
+ var rowPos = dTable.fnGetPosition(this.parentNode);
+
+ // Update datatable
+ dTable.fnUpdate(value, rowPos, colPos);
+
+ return (value);
+ }, {
+ onblur : 'submit', // Clicking outside editable area submits changes
+ type : 'textarea',
+ placeholder: ' ',
+ height : '30px' // The height of the text area
+ });
+
+ // Create action bar
+ var actionBar = $('');
+
+ var saveLnk = $('Save');
+ saveLnk.click(function() {
+ // Get table ID and name
+ var tableId = $(this).parents('.dataTables_wrapper').attr('id').replace('_wrapper', '');
+ var tableName = tableId.replace('Datatable', '');
+
+ // Get datatable
+ var dTable = $('#' + tableId).dataTable();
+ // Get the nodes from the table
+ var dRows = dTable.fnGetNodes();
+
+ // Go through each row
+ for ( var i = 0; i < dRows.length; i++) {
+ // If there is row with values
+ if (dRows[i]) {
+ // Go through each column
+ // Ignore the 1st column because it is a button
+ var cols = dRows[i].childNodes;
+ var vals = new Object();
+ for ( var j = 1; j < cols.length; j++) {
+ var val = cols.item(j).firstChild.nodeValue;
+
+ // Insert quotes
+ if (val == ' ') {
+ vals[j - 1] = '';
+ } else {
+ vals[j - 1] = val;
+ }
+ }
+
+ // Save row
+ newCont[i + 1] = vals;
+ }
+ }
+
+ // Update xCAT table
+ $.ajax({
+ type : 'POST',
+ url : 'lib/tabRestore.php',
+ dataType : 'json',
+ data : {
+ table : tableName,
+ cont : newCont
+ },
+ success : function(data) {
+ // data = decodeRsp(data); Do not do this here until tabRestore.php is analyzed
+ // Create info message
+ var dialog = $('').append(createInfoBar('Changes saved!'));
+
+ // Open dialog
+ dialog.dialog({
+ modal: true,
+ title: 'Info',
+ width: 400,
+ buttons: {
+ "Ok": function(){
+ $(this).dialog("close");
+ }
+ }
+ });
+ }
+ });
+ });
+
+ var undoLnk = $('Undo');
+ undoLnk.click(function() {
+ // Get table ID
+ var tableId = $(this).parents('.dataTables_wrapper').attr('id').replace('_wrapper', '');
+
+ // Get datatable
+ var dTable = $('#' + tableId).dataTable();
+
+ // Clear entire datatable
+ dTable.fnClearTable();
+
+ // Add original content back into datatable
+ for ( var i = 1; i < origCont.length; i++) {
+ dTable.fnAddData(origCont[i], true);
+ }
+
+ // Enable editable columns (again)
+ // Do not make 1st column editable
+ $('#' + tableId + ' td:not(td:nth-child(1))').editable(
+ function(value, settings) {
+ // Get column index
+ var colPos = this.cellIndex;
+ // Get row index
+ var rowPos = dTable.fnGetPosition(this.parentNode);
+
+ // Update datatable
+ dTable.fnUpdate(value, rowPos, colPos);
+
+ return (value);
+ }, {
+ onblur : 'submit', // Clicking outside editable area submits changes
+ type : 'textarea',
+ placeholder: ' ',
+ height : '30px' // The height of the text area
+ });
+ });
+
+ var addLnk = $('Add row');
+ addLnk.click(function() {
+ // Create an empty row
+ var row = new Array();
+
+ /**
+ * Remove button
+ */
+ row.push('');
+ for ( var i = 0; i < headers.length; i++) {
+ row.push('');
+ }
+
+ // Get table ID and name
+ var tableId = $(this).parents('.dataTables_wrapper').attr('id').replace('_wrapper', '');
+
+ // Get datatable
+ var dTable = $('#' + tableId).dataTable();
+
+ // Add the row to the data table
+ dTable.fnAddData(row);
+
+ // Enable editable columns (again)
+ // Do not make 1st column editable
+ $('#' + tableId + ' td:not(td:nth-child(1))').editable(
+ function(value, settings) {
+ // Get column index
+ var colPos = this.cellIndex;
+ // Get row index
+ var rowPos = dTable.fnGetPosition(this.parentNode);
+
+ // Update datatable
+ dTable.fnUpdate(value, rowPos, colPos);
+
+ return (value);
+ }, {
+ onblur : 'submit', // Clicking outside editable area submits changes
+ type : 'textarea',
+ placeholder: ' ',
+ height : '30px' // The height of the text area
+ });
+ });
+
+ // Create an action menu
+ var actionsMenu = createMenu([saveLnk, undoLnk, addLnk]);
+ actionsMenu.superfish();
+ actionsMenu.css('display', 'inline-block');
+ actionBar.append(actionsMenu);
+
+ // Set correct theme for action menu
+ actionsMenu.find('li').hover(function() {
+ setMenu2Theme($(this));
+ }, function() {
+ setMenu2Normal($(this));
+ });
+
+ // Create a division to hold actions menu
+ var menuDiv = $('');
+ $('#' + id + 'Datatable_wrapper').prepend(menuDiv);
+ menuDiv.append(actionBar);
+ $('#' + id + 'Datatable_filter').appendTo(menuDiv);
+}
+
+/**
+ * Delete a row in the data table
+ *
+ * @param obj The object that was clicked
+ */
+function deleteRow(obj) {
+ // Get table ID
+ var tableId = $(obj).parents('table').attr('id');
+
+ // Get datatable
+ var dTable = $('#' + tableId).dataTable();
+
+ // Get all nodes within the datatable
+ var rows = dTable.fnGetNodes();
+ // Get target row
+ var tgtRow = $(obj).parent().parent().get(0);
+
+ // Find the target row in the datatable
+ for ( var i in rows) {
+ // If the row matches the target row
+ if (rows[i] == tgtRow) {
+ // Remove row
+ dTable.fnDeleteRow(i, null, true);
+ break;
+ }
+ }
+}
+
+/**
+ * Count the number of occurrences of a specific character in a string
+ *
+ * @param c Character to count
+ * @return The number of occurrences
+ */
+String.prototype.count = function(c) {
+ return (this.length - this.replace(new RegExp(c, 'g'), '').length)/c.length;
+};
+
+/**
+ * Update dialog
+ *
+ * @param data HTTP request data
+ */
+function updatePanel(data) {
+ var dialogId = data.msg;
+ var infoMsg;
+
+ // Create info message
+ if (jQuery.isArray(data.rsp)) {
+ infoMsg = '';
+ for (var i in data.rsp) {
+ infoMsg += data.rsp[i] + '';
+ }
+ } else {
+ infoMsg = data.rsp;
+ }
+
+ // Create info bar with close button
+ var infoBar = $('').css('margin', '5px 0px');
+ var icon = $('').css({
+ 'display': 'inline-block',
+ 'margin': '10px 5px'
+ });
+
+ // Create close button to close info bar
+ var close = $('').css({
+ 'display': 'inline-block',
+ 'float': 'right'
+ }).click(function() {
+ $(this).parent().remove();
+ });
+
+ var msg = $('
' + infoMsg + '
').css({
+ 'display': 'inline-block',
+ 'width': '85%'
+ });
+
+ infoBar.append(icon, msg, close);
+ infoBar.prependTo($('#' + dialogId));
}
\ No newline at end of file
diff --git a/xCAT-UI/js/configure/files.js b/xCAT-UI/js/configure/files.js
new file mode 100644
index 000000000..4c79af81f
--- /dev/null
+++ b/xCAT-UI/js/configure/files.js
@@ -0,0 +1,336 @@
+/**
+ * Load the files page
+ */
+function loadFilesPage() {
+ var tabId = 'filesTab';
+ $('#' + tabId).empty();
+
+ // Set padding for page
+ $('#' + tabId).css('padding', '10px 30px');
+
+ // Create info bar
+ var info = $('#' + tabId).find('.ui-state-highlight');
+ // If there is no info bar
+ if (!info.length) {
+ var infoBar = createInfoBar('Below is a listing of the xCAT repository. ' +
+ 'Upload any file or package into the repository using the Upload button. ' +
+ 'Go into any subdirectories by specifying the directory path and clicking on Go.');
+
+ var directoryFS = $('');
+ var dirLegend = $('');
+ directoryFS.append(dirLegend);
+
+ // Division to hold directory actions
+ var actions = $('');
+ directoryFS.append(actions);
+
+ // Create button to create a directory
+ var folderBtn = createButton('New folder');
+ folderBtn.click(function() {
+ var deleteFolderBtn = $('');
+ var createFolderBtn = createButton('Create');
+
+ // Create a new directory
+ var newFolder = $('
');
+ newFolder.prepend(deleteFolderBtn);
+ newFolder.append(createFolderBtn);
+ $('#repo_content ul').append(newFolder);
+
+ // Delete new folder on-click
+ deleteFolderBtn.click(function() {
+ $(this).parents('li').remove();
+ });
+
+ // Create folder on-click
+ createFolderBtn.click(function() {
+ var directory = $('#' + tabId + ' input[name="repo_directory"]');
+ var newFolderPath = $('#' + tabId + ' input[name="new_folder"]').val();
+ if (newFolderPath) {
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : 'createfolder;' + directory.val() + '/' + newFolderPath,
+ msg : ''
+ },
+
+ success:function(data) {
+ data = decodeRsp(data);
+ openDialog('info', data.rsp[0]);
+ }
+ });
+
+ $(this).parents('li').remove();
+ } else {
+ openDialog('warn', 'You must specify the folder name');
+ }
+ });
+ });
+
+ // Create button to upload files
+ var uploadBtn = createButton('Upload');
+ uploadBtn.click(function() {
+ var directory = $('#' + tabId + ' input[name="repo_directory"]');
+ openUploadDialog(directory.val());
+ });
+
+ // Create button to go into a directory path
+ var dirPath = $('');
+ var goBtn = createButton('Go');
+ goBtn.click(function() {
+ var directory = $('#' + tabId + ' input[name="repo_directory"]');
+ loadPath(directory.val());
+ });
+ goBtn.attr('id', 'go_to_path');
+
+ var space = $('');
+ var content = $('');
+ actions.append(folderBtn, uploadBtn, dirPath, goBtn);
+ directoryFS.append(space, content);
+
+ $('#' + tabId).append(infoBar, directoryFS);
+ }
+
+ // Retrieve repository space
+ getRepositorySpace();
+
+ // Retrieve files from /install
+ loadPath('/install');
+}
+
+/**
+ * Get the repository space
+ */
+function getRepositorySpace() {
+ // Grab repository space
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ async: false,
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : 'getrepospace',
+ msg : ''
+ },
+ success: function(data) {
+ data = decodeRsp(data);
+ $('#repo_space').children().remove();
+
+ // Data returned is: size, used, available, used %, mount
+ // Data could be in a different format in CMO, where it puts the directory on the line
+ // "rsp":["\/data\/xcat\/install 28G 6.0G 20G 24% \/install"],"msg":null}
+ var space = data.rsp[0].split(' ');
+ if (space.length == 6) {
+ space.splice(0,1);
+ }
+ var spaceLabel = $('');
+ $('#repo_space').append(spaceLabel);
+ }
+ });
+}
+
+/**
+ * Open a dialog to upload files into the repository
+ *
+ * @param destDirectory The destination directory
+ */
+function openUploadDialog(destDirectory) {
+ // Create info bar
+ var info = createInfoBar('Select a file to upload onto ' + destDirectory + '.');
+ var dialog = $('');
+ dialog.append(info);
+
+ // Upload file
+ var upload = $('');
+ var label = $('');
+ var file = $('');
+ var subBtn = createButton('Upload');
+ upload.append(label, file, subBtn);
+ dialog.append(upload);
+
+ upload.submit(function() {
+ // Create status bar, hide on load
+ var statBarId = 'uploadStatusBar';
+ var statBar = createStatusBar(statBarId);
+ var loader = createLoader('');
+ statBar.find('div').append('Do not close this dialog while the file is being uploaded ');
+ statBar.find('div').append(loader);
+ statBar.prependTo($('#upload_file_dg'));
+
+ var data = new FormData($('#upload_file')[0]);
+ $.ajax({
+ type: 'POST',
+ url : 'lib/uploadfile.php?destination=' + destDirectory,
+ data: data,
+ success: function(data) {
+ $('#uploadStatusBar').find('img').hide();
+ $('#uploadStatusBar').find('div').empty();
+ $('#uploadStatusBar').find('div').append(data);
+
+ // Refresh directory contents
+ $('#go_to_path').click();
+ getRepositorySpace();
+ },
+ cache: false,
+ contentType: false,
+ processData: false
+ });
+
+ return false;
+ });
+
+ // Create dialog
+ dialog.dialog({
+ modal: true,
+ title: 'Upload',
+ width: 500,
+ close: function() {$(this).remove();}
+ });
+}
+
+/**
+ * Load the directory path structure
+ *
+ * @path The directory path
+ */
+function loadPath(path) {
+ // Limit access to only /install
+ if (path.substring(0, 9).indexOf("install") == -1) {
+ openDialog('warn', 'You are not authorized to browse outside the repository');
+ return;
+ }
+
+ var tabId = 'filesTab';
+ var directory = $('#' + tabId + ' input[name="repo_directory"]');
+ directory.val(path);
+
+ // Un-ordered list containing directories and files
+ var contentId = 'repo_content';
+ $('#' + contentId).empty();
+ var itemsList = $('
');
+ $('#' + contentId).append(itemsList);
+
+ // Back button to go up a directory
+ var item = $('
..
');
+ itemsList.append(item);
+ item.dblclick(function() {
+ if (path.lastIndexOf('/') > 1)
+ path = path.substring(0, path.lastIndexOf('/'));
+ loadPath(path);
+ });
+
+ $.ajax({
+ type: 'POST',
+ url : 'lib/getpath.php',
+ dataType : 'json',
+ data: {
+ action: 'browse',
+ path: path,
+ time: new Date().getTime()
+ },
+ beforeSend: function() {
+ // Show loading image
+ },
+ success: function(files) {
+ $.each(files, function(index, file) {
+ if (!file.path || file.path.indexOf("undefined"))
+ file.path = "";
+
+ var fullPath = file.path + "/" + file.name;
+
+ // Create a list showing the directories and files
+ var item;
+ if (file.isFolder) {
+ var deleteFolderBtn = $('');
+
+ item = $('
');
+ item.append(deleteFileBtn, icon);
+
+ // Delete file on click
+ deleteFileBtn.click(function() {
+ deleteFile($(this).parents('li'), directory.val() + fullPath);
+ });
+
+ itemsList.append(item);
+ }
+ });
+ }
+ });
+}
+
+/**
+ * Prompt user to confirm deletion of file
+ *
+ * @param container The element container
+ * @param file The file name to delete
+ */
+function deleteFile(container, file) {
+ // Open dialog to confirm
+ var confirmDialog = $('');
+ var warn = createWarnBar('Are you sure you want to delete ' + file + '?');
+ confirmDialog.append(warn);
+ confirmDialog.dialog({
+ title: "Confirm",
+ modal: true,
+ width: 400,
+ close: function() {$(this).remove();},
+ buttons: {
+ "Ok": function() {
+ var loader = createLoader('').css({'margin': '5px'});
+ $(this).append(loader);
+
+ // Change dialog buttons
+ $(this).dialog('option', 'buttons', {
+ 'Close':function() {
+ $(this).dialog('destroy').remove();
+ }
+ });
+
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ async: false,
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : 'deletefile;' + file,
+ msg : ''
+ },
+ success: function(data) {
+ data = decodeRsp(data);
+ $('#confirm_delete').children().remove();
+ var info = createInfoBar(data.rsp[0]);
+ $('#confirm_delete').append(info);
+ getRepositorySpace();
+ }
+ });
+
+ // Delete folder from the list
+ container.remove();
+ },
+ "Cancel": function() {
+ $(this).dialog('destroy').remove();
+ }
+ }
+ });
+}
\ No newline at end of file
diff --git a/xCAT-UI/js/configure/service.js b/xCAT-UI/js/configure/service.js
index 515b86296..036de8dce 100644
--- a/xCAT-UI/js/configure/service.js
+++ b/xCAT-UI/js/configure/service.js
@@ -1,1280 +1,1314 @@
-/**
- * Global variables
- */
-var topPriority = 0;
-
-/**
- * Load the service portal's provision page
- *
- * @param tabId Tab ID where page will reside
- */
-function loadServicePage(tabId) {
- // Create info bar
- var infoBar = createInfoBar('Select a platform to configure, then click Ok.');
-
- // Create self-service portal page
- var tabId = 'serviceTab';
- var servicePg = $('');
- $('#' + tabId).append(infoBar, servicePg);
-
- // Create radio buttons for platforms
- var hwList = $('Platforms available:');
- var esx = $('
ESX
');
- var kvm = $('
KVM
');
- var zvm = $('
z\/VM
');
-
- hwList.append(esx);
- hwList.append(kvm);
- hwList.append(zvm);
- servicePg.append(hwList);
-
- /**
- * Ok
- */
- var okBtn = createButton('Ok');
- okBtn.bind('click', function(event) {
- var configTabs = getConfigTab();
-
- // Get hardware that was selected
- var hw = $(this).parent().find('input[name="hw"]:checked').val();
- var newTabId = hw + 'ProvisionTab';
-
- if ($('#' + newTabId).size() > 0){
- configTabs.select(newTabId);
- } else {
- var title = '';
-
- // Create an instance of the plugin
- var plugin = null;
- switch (hw) {
- case "kvm":
- plugin = new kvmPlugin();
- title = 'KVM';
- break;
- case "esx":
- plugin = new esxPlugin();
- title = 'ESX';
- break;
- case "zvm":
- plugin = new zvmPlugin();
- title = 'z/VM';
-
- // Get zVM host names
- if (!$.cookie('xcat_zvms')){
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webportal',
- tgt : '',
- args : 'lszvm',
- msg : ''
- },
-
- success : function(data) {
- setzVMCookies(data);
- }
- });
- }
-
- break;
- }
-
- // Select tab
- configTabs.add(newTabId, title, '', true);
- configTabs.select(newTabId);
- plugin.loadConfigPage(newTabId);
- }
- });
-
- servicePg.append(okBtn);
-}
-
-/**
- * Round a floating point to a given precision
- *
- * @param value Floating point
- * @param precision Decimal precision
- * @returns Floating point number
- */
-function toFixed(value, precision) {
- var power = Math.pow(10, precision || 0);
- return String(Math.round(value * power) / power);
-}
-
-/**
- * Query the images that exists
- *
- * @param panelId Panel ID
- */
-function queryImages(panelId) {
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'tabdump',
- tgt : '',
- args : 'osimage',
- msg : panelId
- },
-
- success : configImagePanel
- });
-}
-
-/**
- * Panel to configure OS images
- *
- * @param data Data from HTTP request
- */
-function configImagePanel(data) {
- var panelId = data.msg;
- var rsp = data.rsp;
-
- // Wipe panel clean
- $('#' + panelId).empty();
-
- // Add info bar
- $('#' + panelId).append(createInfoBar('Create, edit, and delete operating system images for the self-service portal.'));
-
- // Create table
- var tableId = panelId + 'Datatable';
- var table = new DataTable(tableId);
- table.init(['', 'Name', 'Selectable', 'OS Version', 'OS Arch', 'OS Name', 'Type', 'Profile', 'Method', 'Description']);
-
- // Insert images into table
- var imagePos = 0;
- var profilePos = 0;
- var osversPos = 0;
- var osarchPos = 0;
- var osnamePos = 0;
- var imagetypePos = 0;
- var provMethodPos = 0;
- var comments = 0;
- var desc, selectable, tmp;
- // Get column index for each attribute
- var colNameArray = rsp[0].substr(1).split(',');
- for (var i in colNameArray){
- switch (colNameArray[i]){
- case 'imagename': {
- imagePos = i;
- }
- break;
-
- case 'profile':{
- profilePos = i;
- }
- break;
-
- case 'osvers':{
- osversPos = i;
- }
- break;
-
- case 'osarch':{
- osarchPos = i;
- }
- break;
-
- case 'osname':{
- osnamePos = i;
- }
- break;
-
- case 'imagetype':{
- imagetypePos = i;
- }
- break;
-
- case 'comments':{
- comments = i;
- }
- break;
-
- case 'provmethod':{
- provMethodPos = i;
- }
- break;
-
- default :
- break;
- }
- }
-
- // Go through each index
- for (var i = 1; i < rsp.length; i++) {
- // Get image name
- var cols = rsp[i].split(',');
- var name = cols[imagePos].replace(new RegExp('"', 'g'), '');
- var profile = cols[profilePos].replace(new RegExp('"', 'g'), '');
- var provMethod = cols[provMethodPos].replace(new RegExp('"', 'g'), '');
- var osVer = cols[osversPos].replace(new RegExp('"', 'g'), '');
- var osArch = cols[osarchPos].replace(new RegExp('"', 'g'), '');
- var osName = cols[osnamePos].replace(new RegExp('"', 'g'), '');
- var imageType = cols[imagetypePos].replace(new RegExp('"', 'g'), '');
- var osComments = cols[comments].replace(new RegExp('"', 'g'), '');
-
- // Only save install boot and s390x architectures
- if (osArch == "s390x") {
- // Set default description and selectable
- selectable = "no";
- desc = "No description";
-
- if (osComments) {
- tmp = osComments.split('|');
- for (var j = 0; j < tmp.length; j++) {
- // Save description
- if (tmp[j].indexOf('description:') > -1) {
- desc = tmp[j].replace('description:', '');
- desc = jQuery.trim(desc);
- }
-
- // Is the image selectable?
- if (tmp[j].indexOf('selectable:') > -1) {
- selectable = tmp[j].replace('selectable:', '');
- selectable = jQuery.trim(selectable);
- }
- }
- }
-
- // Columns are: name, selectable, OS version, OS arch, OS name, type, profile, method, and description
- var cols = new Array(name, selectable, osVer, osArch, osName, imageType, profile, provMethod, desc);
-
- // Add remove button where id = user name
- cols.unshift('');
-
- // Add row
- table.add(cols);
- }
- }
-
- // Append datatable to tab
- $('#' + panelId).append(table.object());
-
- // Turn into datatable
- $('#' + tableId).dataTable({
- 'iDisplayLength': 50,
- 'bLengthChange': false,
- "bScrollCollapse": true,
- "sScrollY": "400px",
- "sScrollX": "110%",
- "bAutoWidth": true,
- "oLanguage": {
- "oPaginate": {
- "sNext": "",
- "sPrevious": ""
- }
- }
- });
-
- // Create action bar
- var actionBar = $('').css("width", "400px");
-
- // Create a profile
- var createLnk = $('Create');
- createLnk.click(function() {
- imageDialog();
- });
-
- // Edit a profile
- var editLnk = $('Edit');
- editLnk.click(function() {
- var images = $('#' + tableId + ' input[type=checkbox]:checked');
- for (var i in images) {
- var image = images.eq(i).attr('name');
- if (image) {
- // Columns are: name, selectable, OS version, OS arch, OS name, type, profile, method, and description
- var cols = images.eq(i).parents('tr').find('td');
- var selectable = cols.eq(2).text();
- var osVersion = cols.eq(3).text();
- var osArch = cols.eq(4).text();
- var osName = cols.eq(5).text();
- var type = cols.eq(6).text();
- var profile = cols.eq(7).text();
- var method = cols.eq(8).text();
- var description = cols.eq(9).text();
-
- editImageDialog(image, selectable, osVersion, osArch, osName, type, profile, method, description);
- }
- }
- });
-
- // Delete a profile
- var deleteLnk = $('Delete');
- deleteLnk.click(function() {
- var images = getNodesChecked(tableId);
- if (images) {
- deleteImageDialog(images);
- }
- });
-
- // Refresh profiles table
- var refreshLnk = $('Refresh');
- refreshLnk.click(function() {
- queryImages(panelId);
- });
-
- // Create an action menu
- var actionsMenu = createMenu([refreshLnk, createLnk, editLnk, deleteLnk]);
- actionsMenu.superfish();
- actionsMenu.css('display', 'inline-block');
- actionBar.append(actionsMenu);
-
- // Set correct theme for action menu
- actionsMenu.find('li').hover(function() {
- setMenu2Theme($(this));
- }, function() {
- setMenu2Normal($(this));
- });
-
- // Create a division to hold actions menu
- var menuDiv = $('');
- $('#' + tableId + '_wrapper').prepend(menuDiv);
- menuDiv.append(actionBar);
- $('#' + tableId + '_filter').appendTo(menuDiv);
-
- // Resize accordion
- $('#' + tableId).parents('.ui-accordion').accordion('resize');
-}
-
-/**
- * Open image dialog
- */
-function imageDialog() {
- // Create form to add profile
- var dialogId = 'createImage';
- var imageForm = $('');
-
- // Create info bar
- var info = createInfoBar('Provide the following attributes for the image. The image name will be generated based on the attributes you will give.');
- imageForm.append(info);
-
- var imageName = $('');
- var selectable = $('');
- var imageType = $('');
- var architecture = $('');
- var osName = $('');
- var osVersion = $('');
- var profile = $('');
- var provisionMethod = $('');
- var provisionSelect = $('');
- provisionMethod.append(provisionSelect);
- var comments = $('');
- imageForm.append(imageName, selectable, imageType, architecture, osName, osVersion, profile, provisionMethod, comments);
-
- // Generate tooltips
- imageForm.find('div input[title],textarea[title],select[title]').tooltip({
- position: "center right",
- offset: [-2, 10],
- effect: "fade",
- opacity: 0.8,
- delay: 0,
- predelay: 800,
- events: {
- def: "mouseover,mouseout",
- input: "mouseover,mouseout",
- widget: "focus mouseover,blur mouseout",
- tooltip: "mouseover,mouseout"
- },
-
- // Change z index to show tooltip in front
- onBeforeShow: function() {
- this.getTip().css('z-index', $.topZIndex());
- }
- });
-
- // Open dialog to add image
- imageForm.dialog({
- title:'Create image',
- modal: true,
- close: function(){
- $(this).remove();
- },
- width: 400,
- buttons: {
- "Ok": function() {
- // Remove any warning messages
- $(this).find('.ui-state-error').remove();
-
- // Get image attributes
- var imageType = $(this).find('input[name="imagetype"]');
- var selectable = $(this).find('input[name="selectable"]');
- var architecture = $(this).find('input[name="osarch"]');
- var osName = $(this).find('input[name="osname"]');
- var osVersion = $(this).find('input[name="osvers"]');
- var profile = $(this).find('input[name="profile"]');
- var provisionMethod = $(this).find('select[name="provmethod"]');
- var comments = $(this).find('input[name="comments"]');
-
- // Check that image attributes are provided before continuing
- var ready = 1;
- var inputs = new Array(imageType, architecture, osName, osVersion, profile, provisionMethod);
- for (var i in inputs) {
- if (!inputs[i].val()) {
- inputs[i].css('border-color', 'red');
- ready = 0;
- } else
- inputs[i].css('border-color', '');
- }
-
- // If inputs are not complete, show warning message
- if (!ready) {
- var warn = createWarnBar('Please provide a value for each missing field.');
- warn.prependTo($(this));
- } else {
- // Override image name
- $(this).find('input[name="imagename"]').val(osVersion.val() + '-' + architecture.val() + '-' + provisionMethod.val() + '-' + profile.val());
- var imageName = $(this).find('input[name="imagename"]');
-
- // Change dialog buttons
- $(this).dialog('option', 'buttons', {
- 'Close': function() {$(this).dialog("close");}
- });
-
- // Set default description
- if (!comments.val())
- comments.val('No description');
-
- // Create arguments to send via AJAX
- var args = 'updateosimage;' + imageName.val() + ';' +
- imageType.val() + ';' +
- architecture.val() + ';' +
- osName.val() + ';' +
- osVersion.val() + ';' +
- profile.val() + ';' +
- provisionMethod.val() + ';';
-
- if (selectable.attr('checked'))
- args += '"description:' + comments.val() + '|selectable:yes"';
- else
- args += '"description:' + comments.val() + '|selectable:no"';
-
- // Add image to xCAT
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : args,
- msg : dialogId
- },
-
- success : updatePanel
- });
- }
- },
- "Cancel": function() {
- $(this).dialog( "close" );
- }
- }
- });
-}
-
-/**
- * Edit image dialog
- *
- * @param iName Image name
- * @param iSelectable Is image selectable from service page
- * @param iOsVersion OS version
- * @param iProfile Profile name
- * @param iMethod Provisioning method
- * @param iComments Image description
- */
-function editImageDialog(iName, iSelectable, iOsVersion, iOsArch, iOsName, iType, iProfile, iMethod, iComments) {
- var inst = 0;
- var dialogId = 'editImage' + inst;
- while ($('#' + dialogId).length) {
- // If one already exists, generate another one
- inst = inst + 1;
- dialogId = 'editImage' + inst;
- }
-
- // Create form to add profile
- var imageForm = $('');
-
- // Create info bar
- var info = createInfoBar('Provide the following attributes for the image. The image name will be generated based on the attributes you will give.');
- imageForm.append(info);
-
- var imageName = $('');
- var selectable = $('');
- var imageType = $('');
- var architecture = $('');
- var osName = $('');
- var osVersion = $('');
- var profile = $('');
- var provisionMethod = $('');
- var provisionSelect = $('');
- provisionMethod.append(provisionSelect);
- var comments = $('');
- imageForm.append(imageName, selectable, imageType, architecture, osName, osVersion, profile, provisionMethod, comments);
-
- // Fill in image attributes
- imageForm.find('input[name="imagename"]').val(iName);
- imageForm.find('input[name="osvers"]').val(iOsVersion);
- imageForm.find('input[name="osarch"]').val(iOsArch);
- imageForm.find('input[name="osname"]').val(iOsName);
- imageForm.find('input[name="imagetype"]').val(iType);
- imageForm.find('input[name="profile"]').val(iProfile);
- imageForm.find('select[name="provmethod"]').val(iMethod);
- imageForm.find('input[name="comments"]').val(iComments);
- if (iSelectable == "yes")
- imageForm.find('input[name="selectable"]').attr('checked', 'checked');
-
- // Generate tooltips
- imageForm.find('div input[title],textarea[title],select[title]').tooltip({
- position: "center right",
- offset: [-2, 10],
- effect: "toggle",
- opacity: 0.8,
- delay: 0,
- predelay: 800,
- events: {
- def: "mouseover,mouseout",
- input: "mouseover,mouseout",
- widget: "focus mouseover,blur mouseout",
- tooltip: "mouseover,mouseout"
- },
-
- // Change z index to show tooltip in front
- onBeforeShow: function() {
- this.getTip().css('z-index', $.topZIndex());
- }
- });
-
- // Open dialog to add image
- imageForm.dialog({
- title:'Edit image',
- modal: true,
- close: function(){
- $(this).remove();
- },
- width: 400,
- buttons: {
- "Ok": function() {
- // Remove any warning messages
- $(this).find('.ui-state-error').remove();
-
- // Get image attributes
- var imageType = $(this).find('input[name="imagetype"]');
- var selectable = $(this).find('input[name="selectable"]');
- var architecture = $(this).find('input[name="osarch"]');
- var osName = $(this).find('input[name="osname"]');
- var osVersion = $(this).find('input[name="osvers"]');
- var profile = $(this).find('input[name="profile"]');
- var provisionMethod = $(this).find('select[name="provmethod"]');
- var comments = $(this).find('input[name="comments"]');
-
- // Check that image attributes are provided before continuing
- var ready = 1;
- var inputs = new Array(imageType, architecture, osName, osVersion, profile, provisionMethod);
- for (var i in inputs) {
- if (!inputs[i].val()) {
- inputs[i].css('border-color', 'red');
- ready = 0;
- } else
- inputs[i].css('border-color', '');
- }
-
- // If inputs are not complete, show warning message
- if (!ready) {
- var warn = createWarnBar('Please provide a value for each missing field.');
- warn.prependTo($(this));
- } else {
- // Override image name
- $(this).find('input[name="imagename"]').val(osVersion.val() + '-' + architecture.val() + '-' + provisionMethod.val() + '-' + profile.val());
- var imageName = $(this).find('input[name="imagename"]');
-
- // Change dialog buttons
- $(this).dialog('option', 'buttons', {
- 'Close': function() {$(this).dialog("close");}
- });
-
- // Set default description
- if (!comments.val())
- comments.val('No description');
-
- // Create arguments to send via AJAX
- var args = 'updateosimage;' + imageName.val() + ';' +
- imageType.val() + ';' +
- architecture.val() + ';' +
- osName.val() + ';' +
- osVersion.val() + ';' +
- profile.val() + ';' +
- provisionMethod.val() + ';';
-
- if (selectable.attr('checked'))
- args += '"description:' + comments.val() + '|selectable:yes"';
- else
- args += '"description:' + comments.val() + '|selectable:no"';
-
- // Add image to xCAT
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : args,
- msg : dialogId
- },
-
- success : updatePanel
- });
- }
- },
- "Cancel": function() {
- $(this).dialog( "close" );
- }
- }
- });
-}
-
-/**
- * Open dialog to confirm image delete
- *
- * @param images Images to delete
- */
-function deleteImageDialog(images) {
- // Create form to delete disk to pool
- var dialogId = 'deleteImage';
- var deleteForm = $('');
-
- // Create info bar
- var info = createInfoBar('Are you sure you want to delete ' + images.replace(new RegExp(',', 'g'), ', ') + '?');
- deleteForm.append(info);
-
- // Open dialog to delete user
- deleteForm.dialog({
- title:'Delete image',
- modal: true,
- width: 400,
- close: function(){
- $(this).remove();
- },
- buttons: {
- "Ok": function(){
- // Remove any warning messages
- $(this).find('.ui-state-error').remove();
-
- // Change dialog buttons
- $(this).dialog('option', 'buttons', {
- 'Close': function() {$(this).dialog("close");}
- });
-
- // Delete user
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : 'rmosimage;' + images,
- msg : dialogId
- },
- success : updatePanel
- });
- },
- "Cancel": function() {
- $(this).dialog( "close" );
- }
- }
- });
-}
-
-/**
- * Query the groups that exists
- *
- * @param panelId Panel ID
- */
-function queryGroups(panelId) {
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'tabdump',
- tgt : '',
- args : 'hosts',
- msg : panelId
- },
-
- success : configGroupPanel
- });
-}
-
-/**
- * Panel to configure groups
- *
- * @param data Data from HTTP request
- */
-function configGroupPanel(data) {
- var panelId = data.msg;
- var rsp = data.rsp;
-
- // Wipe panel clean
- $('#' + panelId).empty();
-
- // Add info bar
- $('#' + panelId).append(createInfoBar('Create, edit, and delete groups for the self-service portal.'));
-
- // Create table
- var tableId = panelId + 'Datatable';
- var table = new DataTable(tableId);
- table.init(['', 'Name', 'Selectable', 'IP', 'Hostname', 'Description']);
-
- // Insert groups into table
- var nodePos = 0;
- var ipPos = 0;
- var hostnamePos = 0;
- var commentsPos = 0;
- var desc, selectable, tmp;
- // Get column index for each attribute
- var colNameArray = rsp[0].substr(1).split(',');
- for (var i in colNameArray){
- switch (colNameArray[i]){
- case 'node':
- nodePos = i;
- break;
-
- case 'ip':
- ipPos = i;
- break;
-
- case 'hostnames':
- hostnamePos = i;
- break;
-
- case 'comments':
- commentsPos = i;
- break;
-
- default :
- break;
- }
- }
-
- // Go through each index
- for (var i = 1; i < rsp.length; i++) {
- // Get image name
- var cols = rsp[i].split(',');
- var name = cols[nodePos].replace(new RegExp('"', 'g'), '');
- var ip = cols[ipPos].replace(new RegExp('"', 'g'), '');
- var hostname = cols[hostnamePos].replace(new RegExp('"', 'g'), '');
- var comments = cols[commentsPos].replace(new RegExp('"', 'g'), '');
-
- // Set default description and selectable
- selectable = "no";
- network = "";
- desc = "No description";
-
- if (comments) {
- tmp = comments.split('|');
- for (var j = 0; j < tmp.length; j++) {
- // Save description
- if (tmp[j].indexOf('description:') > -1) {
- desc = tmp[j].replace('description:', '');
- desc = jQuery.trim(desc);
- }
-
- // Is the group selectable?
- if (tmp[j].indexOf('selectable:') > -1) {
- selectable = tmp[j].replace('selectable:', '');
- selectable = jQuery.trim(selectable);
- }
- }
- }
-
- // Columns are: name, selectable, network, and description
- var cols = new Array(name, selectable, ip, hostname, desc);
-
- // Add remove button where id = user name
- cols.unshift('');
-
- // Add row
- table.add(cols);
- }
-
- // Append datatable to tab
- $('#' + panelId).append(table.object());
-
- // Turn into datatable
- $('#' + tableId).dataTable({
- 'iDisplayLength': 50,
- 'bLengthChange': false,
- "bScrollCollapse": true,
- "sScrollY": "400px",
- "sScrollX": "110%",
- "bAutoWidth": true,
- "oLanguage": {
- "oPaginate": {
- "sNext": "",
- "sPrevious": ""
- }
- }
- });
-
- // Create action bar
- var actionBar = $('').css("width", "400px");
-
- // Create a group
- var createLnk = $('Create');
- createLnk.click(function() {
- groupDialog();
- });
-
- // Edit a group
- var editLnk = $('Edit');
- editLnk.click(function() {
- var groups = $('#' + tableId + ' input[type=checkbox]:checked');
- for (var i in groups) {
- var group = groups.eq(i).attr('name');
- if (group) {
- // Column order is: name, selectable, network, and description
- var cols = groups.eq(i).parents('tr').find('td');
- var selectable = cols.eq(2).text();
- var ip = cols.eq(3).text();
- var hostnames = cols.eq(4).text();
- var description = cols.eq(5).text();
-
- editGroupDialog(group, selectable, ip, hostnames, description);
- }
- }
- });
-
- // Delete a profile
- var deleteLnk = $('Delete');
- deleteLnk.click(function() {
- var groups = getNodesChecked(tableId);
- if (groups) {
- deleteGroupDialog(groups);
- }
- });
-
- // Refresh profiles table
- var refreshLnk = $('Refresh');
- refreshLnk.click(function() {
- queryGroups(panelId);
- });
-
- // Create an action menu
- var actionsMenu = createMenu([refreshLnk, createLnk, editLnk, deleteLnk]);
- actionsMenu.superfish();
- actionsMenu.css('display', 'inline-block');
- actionBar.append(actionsMenu);
-
- // Set correct theme for action menu
- actionsMenu.find('li').hover(function() {
- setMenu2Theme($(this));
- }, function() {
- setMenu2Normal($(this));
- });
-
- // Create a division to hold actions menu
- var menuDiv = $('');
- $('#' + tableId + '_wrapper').prepend(menuDiv);
- menuDiv.append(actionBar);
- $('#' + tableId + '_filter').appendTo(menuDiv);
-
- // Resize accordion
- $('#' + tableId).parents('.ui-accordion').accordion('resize');
-}
-
-/**
- * Open group dialog
- */
-function groupDialog() {
- // Create form to add profile
- var dialogId = 'createGroup';
- var groupForm = $('');
-
- // Create info bar
- var info = createInfoBar('Provide the following attributes for the group.');
- groupForm.append(info);
-
- var group = $('');
- var selectable = $('');
- var ip = $('');
- var hostnames = $('');
- var comments = $('');
- var ipPool = $('');
-
- groupForm.append(group, selectable, ip, hostnames, comments, ipPool);
-
- // Generate tooltips
- groupForm.find('div input[title],textarea[title],select[title]').tooltip({
- position: "center right",
- offset: [-2, 10],
- effect: "fade",
- opacity: 0.8,
- delay: 0,
- predelay: 800,
- events: {
- def: "mouseover,mouseout",
- input: "mouseover,mouseout",
- widget: "focus mouseover,blur mouseout",
- tooltip: "mouseover,mouseout"
- },
-
- // Change z index to show tooltip in front
- onBeforeShow: function() {
- this.getTip().css('z-index', $.topZIndex());
- }
- });
-
- // Open dialog to add image
- groupForm.dialog({
- title:'Create group',
- modal: true,
- close: function(){
- $(this).remove();
- },
- width: 600,
- buttons: {
- "Ok": function() {
- // Remove any warning messages
- $(this).find('.ui-state-error').remove();
-
- // Get group attributes
- var group = $(this).find('input[name="group"]');
- var selectable = $(this).find('input[name="selectable"]');
- var ip = $(this).find('input[name="ip"]');
- var hostnames = $(this).find('input[name="hostnames"]');
- var comments = $(this).find('input[name="comments"]');
- var ipPool = $(this).find('textarea[name=ip_pool]').val();
-
- // Check that group attributes are provided before continuing
- var ready = 1;
- var inputs = new Array(group);
- for (var i in inputs) {
- if (!inputs[i].val()) {
- inputs[i].css('border-color', 'red');
- ready = 0;
- } else
- inputs[i].css('border-color', '');
- }
-
- // If inputs are not complete, show warning message
- if (!ready) {
- var warn = createWarnBar('Please provide a value for each missing field.');
- warn.prependTo($(this));
- } else {
- // Change dialog buttons
- $(this).dialog('option', 'buttons', {
- 'Close': function() {$(this).dialog("close");}
- });
-
- // A newline at the end of IP pool is needed
- ipPool = ipPool.replace(/^\s+|\s+$/g, '');
- ipPool += '\n';
-
- // Set default description
- if (!comments.val())
- comments.val('No description');
-
- // Create arguments to send via AJAX
- var args = "updategroup;" + group.val() + ";'" + ip.val() + "';'" + hostnames.val() + "';";
-
- if (selectable.attr("checked"))
- args += "'description:" + comments.val() + "|selectable:yes";
- else
- args += "'description:" + comments.val() + "|selectable:no";
-
- // Add image to xCAT
- $.ajax({
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : args,
- msg : dialogId
- },
-
- success : updatePanel
- });
-
- // Write IP pool file to /var/tmp
- $.ajax({
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'write',
- tgt : '/var/tmp/' + group.val() + '.pool',
- args : '',
- cont : ipPool,
- msg : dialogId + ';' + group.val()
- },
-
- success : function(data) {
- var args = data.msg.split(';');
-
- // Create profile in xCAT
- $.ajax({
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : 'mkippool;' + args[1],
- msg : args[0]
- },
-
- success: updatePanel
- });
- }
- });
- }
- },
- "Cancel": function() {
- $(this).dialog( "close" );
- }
- }
- });
-}
-
-/**
- * Edit group dialog
- *
- * @param iGroup Group name
- * @param iSelectable Is group selectable from the service page
- * @param iIp Group IP regex
- * @param iHostnames Group hostnames regex
- * @param iComments Group description
- */
-function editGroupDialog(iGroup, iSelectable, iIp, iHostnames, iComments) {
- // Create form to add profile
- var dialogId = 'createGroup-' + iGroup;
- var groupForm = $('');
-
- // Create info bar
- var info = createInfoBar('Provide the following attributes for the group.');
- groupForm.append(info);
-
- var group = $('');
- var selectable = $('');
- var ip = $('');
- var hostnames = $('');
- var comments = $('');
- var ipPool = $('');
-
- groupForm.append(group, selectable, ip, hostnames, comments, ipPool);
-
- // Query IP pool based on group name
- $.ajax({
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : 'lsippool;' + iGroup,
- msg : dialogId
- },
-
- success : function(data) {
- // Populate textarea with IP pool entries
- $('#' + data.msg).find('textarea[name="ip_pool"]').val(data.rsp[0]);
- }
- });
-
- // Fill in group attributes
- groupForm.find('input[name="group"]').val(iGroup);
- groupForm.find('input[name="ip"]').val(iIp);
- groupForm.find('input[name="hostnames"]').val(iHostnames);
- groupForm.find('input[name="comments"]').val(iComments);
- if (iSelectable == "yes")
- groupForm.find('input[name="selectable"]').attr('checked', 'checked');
-
- // Generate tooltips
- groupForm.find('div input[title],textarea[title],select[title]').tooltip({
- position: "center right",
- offset: [-2, 10],
- effect: "toggle",
- opacity: 0.8,
- delay: 0,
- predelay: 800,
- events: {
- def: "mouseover,mouseout",
- input: "mouseover,mouseout",
- widget: "focus mouseover,blur mouseout",
- tooltip: "mouseover,mouseout"
- },
-
- // Change z index to show tooltip in front
- onBeforeShow: function() {
- this.getTip().css('z-index', $.topZIndex());
- }
- });
-
- // Open dialog to add image
- groupForm.dialog({
- title:'Edit group',
- modal: true,
- close: function(){
- $(this).remove();
- },
- width: 600,
- buttons: {
- "Ok": function() {
- // Remove any warning messages
- $(this).find('.ui-state-error').remove();
-
- // Get group attributes
- var group = $(this).find('input[name="group"]');
- var selectable = $(this).find('input[name="selectable"]');
- var ip = $(this).find('input[name="ip"]');
- var hostnames = $(this).find('input[name="hostnames"]');
- var comments = $(this).find('input[name="comments"]');
- var ipPool = $(this).find('textarea[name=ip_pool]').val();
-
- // Check that group attributes are provided before continuing
- var ready = 1;
- var inputs = new Array(group);
- for (var i in inputs) {
- if (!inputs[i].val()) {
- inputs[i].css('border-color', 'red');
- ready = 0;
- } else
- inputs[i].css('border-color', '');
- }
-
- // If inputs are not complete, show warning message
- if (!ready) {
- var warn = createWarnBar('Please provide a value for each missing field.');
- warn.prependTo($(this));
- } else {
- // Change dialog buttons
- $(this).dialog('option', 'buttons', {
- 'Close': function() {$(this).dialog("close");}
- });
-
- // A newline at the end of IP pool is needed
- ipPool = ipPool.replace(/^\s+|\s+$/g, '');
- ipPool += '\n';
-
- // Set default description
- if (!comments.val())
- comments.val('No description');
-
- // Create arguments to send via AJAX
- var args = "updategroup;" + group.val() + ";'" + ip.val() + "';'" + hostnames.val() + "';";
-
- if (selectable.attr("checked"))
- args += "'description:" + comments.val() + "|selectable:yes";
- else
- args += "'description:" + comments.val() + "|selectable:no";
-
- // Add image to xCAT
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : args,
- msg : dialogId
- },
-
- success : updatePanel
- });
-
- // Write IP pool file to /var/tmp
- $.ajax({
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'write',
- tgt : '/var/tmp/' + group.val() + '.pool',
- args : '',
- cont : ipPool,
- msg : dialogId + ';' + group.val()
- },
-
- success : function(data) {
- var args = data.msg.split(';');
-
- // Create profile in xCAT
- $.ajax({
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : 'mkippool;' + args[1],
- msg : args[0]
- },
-
- success: updatePanel
- });
- }
- });
- }
- },
- "Cancel": function() {
- $(this).dialog( "close" );
- }
- }
- });
-}
-
-/**
- * Open dialog to confirm group delete
- *
- * @param groups Groups to delete
- */
-function deleteGroupDialog(groups) {
- // Create form to delete disk to pool
- var dialogId = 'deleteImage';
- var deleteForm = $('');
-
- // Create info bar
- var info = createInfoBar('Are you sure you want to delete ' + groups.replace(new RegExp(',', 'g'), ', ') + '?');
- deleteForm.append(info);
-
- // Open dialog to delete user
- deleteForm.dialog({
- title:'Delete group',
- modal: true,
- width: 400,
- close: function(){
- $(this).remove();
- },
- buttons: {
- "Ok": function(){
- // Remove any warning messages
- $(this).find('.ui-state-error').remove();
-
- // Change dialog buttons
- $(this).dialog('option', 'buttons', {
- 'Close': function() {$(this).dialog("close");}
- });
-
- // Delete user
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : 'rmgroup;' + groups,
- msg : dialogId
- },
- success : updatePanel
- });
- },
- "Cancel": function() {
- $(this).dialog( "close" );
- }
- }
- });
+/**
+ * Global variables
+ */
+var topPriority = 0;
+
+/**
+ * Load the service portal's provision page
+ *
+ * @param tabId Tab ID where page will reside
+ */
+function loadServicePage(tabId) {
+ // Create info bar
+ var infoBar = createInfoBar('Select a platform to configure, then click Ok.');
+
+ // Create self-service portal page
+ var tabId = 'serviceTab';
+ var servicePg = $('');
+ $('#' + tabId).append(infoBar, servicePg);
+
+ // Create radio buttons for platforms
+ var hwList = $('Platforms available:');
+ var esx = $('
ESX
');
+ var kvm = $('
KVM
');
+ var zvm = $('
z\/VM
');
+
+ hwList.append(esx);
+ hwList.append(kvm);
+ hwList.append(zvm);
+ servicePg.append(hwList);
+
+ /**
+ * Ok
+ */
+ var okBtn = createButton('Ok');
+ okBtn.bind('click', function(event) {
+ var configTabs = getConfigTab();
+
+ // Get hardware that was selected
+ var hw = $(this).parent().find('input[name="hw"]:checked').val();
+ var newTabId = hw + 'ProvisionTab';
+
+ if ($('#' + newTabId).size() > 0){
+ configTabs.select(newTabId);
+ } else {
+ var title = '';
+
+ // Create an instance of the plugin
+ var plugin = null;
+ switch (hw) {
+ case "kvm":
+ plugin = new kvmPlugin();
+ title = 'KVM';
+ break;
+ case "esx":
+ plugin = new esxPlugin();
+ title = 'ESX';
+ break;
+ case "zvm":
+ plugin = new zvmPlugin();
+ title = 'z/VM';
+
+ // Get zVM host names
+ if (!$.cookie('xcat_zvms')){
+ $.ajax( {
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webportal',
+ tgt : '',
+ args : 'lszvm',
+ msg : ''
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ setzVMCookies(data);
+ }
+ });
+ }
+
+ break;
+ }
+
+ // Select tab
+ configTabs.add(newTabId, title, '', true);
+ configTabs.select(newTabId);
+ plugin.loadConfigPage(newTabId);
+ }
+ });
+
+ servicePg.append(okBtn);
+}
+
+/**
+ * Round a floating point to a given precision
+ *
+ * @param value Floating point
+ * @param precision Decimal precision
+ * @returns Floating point number
+ */
+function toFixed(value, precision) {
+ var power = Math.pow(10, precision || 0);
+ return String(Math.round(value * power) / power);
+}
+
+/**
+ * Query the images that exists
+ *
+ * @param panelId Panel ID
+ */
+function queryImages(panelId) {
+ $.ajax( {
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'tabdump',
+ tgt : '',
+ args : 'osimage',
+ msg : panelId
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ configImagePanel(data);
+ }
+ });
+}
+
+/**
+ * Panel to configure OS images
+ *
+ * @param data Data from HTTP request
+ */
+function configImagePanel(data) {
+ var panelId = data.msg;
+ var rsp = data.rsp;
+
+ // Wipe panel clean
+ $('#' + panelId).empty();
+
+ // Add info bar
+ $('#' + panelId).append(createInfoBar('Create, edit, and delete operating system images for the self-service portal.'));
+
+ // Create table
+ var tableId = panelId + 'Datatable';
+ var table = new DataTable(tableId);
+ table.init(['', 'Name', 'Selectable', 'OS Version', 'OS Arch', 'OS Name', 'Type', 'Profile', 'Method', 'Description']);
+
+ // Insert images into table
+ var imagePos = 0;
+ var profilePos = 0;
+ var osversPos = 0;
+ var osarchPos = 0;
+ var osnamePos = 0;
+ var imagetypePos = 0;
+ var provMethodPos = 0;
+ var comments = 0;
+ var desc, selectable, tmp;
+ // Get column index for each attribute
+ var colNameArray = rsp[0].substr(1).split(',');
+ for (var i in colNameArray){
+ switch (colNameArray[i]){
+ case 'imagename': {
+ imagePos = i;
+ }
+ break;
+
+ case 'profile':{
+ profilePos = i;
+ }
+ break;
+
+ case 'osvers':{
+ osversPos = i;
+ }
+ break;
+
+ case 'osarch':{
+ osarchPos = i;
+ }
+ break;
+
+ case 'osname':{
+ osnamePos = i;
+ }
+ break;
+
+ case 'imagetype':{
+ imagetypePos = i;
+ }
+ break;
+
+ case 'comments':{
+ comments = i;
+ }
+ break;
+
+ case 'provmethod':{
+ provMethodPos = i;
+ }
+ break;
+
+ default :
+ break;
+ }
+ }
+
+ // Go through each index
+ for (var i = 1; i < rsp.length; i++) {
+ // Get image name
+ var cols = rsp[i].split(',');
+ var name = cols[imagePos].replace(new RegExp('"', 'g'), '');
+ var profile = cols[profilePos].replace(new RegExp('"', 'g'), '');
+ var provMethod = cols[provMethodPos].replace(new RegExp('"', 'g'), '');
+ var osVer = cols[osversPos].replace(new RegExp('"', 'g'), '');
+ var osArch = cols[osarchPos].replace(new RegExp('"', 'g'), '');
+ var osName = cols[osnamePos].replace(new RegExp('"', 'g'), '');
+ var imageType = cols[imagetypePos].replace(new RegExp('"', 'g'), '');
+ var osComments = cols[comments].replace(new RegExp('"', 'g'), '');
+
+ // Only save install boot and s390x architectures
+ if (osArch == "s390x") {
+ // Set default description and selectable
+ selectable = "no";
+ desc = "No description";
+
+ if (osComments) {
+ tmp = osComments.split('|');
+ for (var j = 0; j < tmp.length; j++) {
+ // Save description
+ if (tmp[j].indexOf('description:') > -1) {
+ desc = tmp[j].replace('description:', '');
+ desc = jQuery.trim(desc);
+ }
+
+ // Is the image selectable?
+ if (tmp[j].indexOf('selectable:') > -1) {
+ selectable = tmp[j].replace('selectable:', '');
+ selectable = jQuery.trim(selectable);
+ }
+ }
+ }
+
+ // Columns are: name, selectable, OS version, OS arch, OS name, type, profile, method, and description
+ var cols = new Array(name, selectable, osVer, osArch, osName, imageType, profile, provMethod, desc);
+
+ // Add remove button where id = user name
+ cols.unshift('');
+
+ // Add row
+ table.add(cols);
+ }
+ }
+
+ // Append datatable to tab
+ $('#' + panelId).append(table.object());
+
+ // Turn into datatable
+ $('#' + tableId).dataTable({
+ 'iDisplayLength': 50,
+ 'bLengthChange': false,
+ "bScrollCollapse": true,
+ "sScrollY": "400px",
+ "sScrollX": "110%",
+ "bAutoWidth": true,
+ "oLanguage": {
+ "oPaginate": {
+ "sNext": "",
+ "sPrevious": ""
+ }
+ }
+ });
+
+ // Create action bar
+ var actionBar = $('').css("width", "400px");
+
+ // Create a profile
+ var createLnk = $('Create');
+ createLnk.click(function() {
+ imageDialog();
+ });
+
+ // Edit a profile
+ var editLnk = $('Edit');
+ editLnk.click(function() {
+ var images = $('#' + tableId + ' input[type=checkbox]:checked');
+ for (var i in images) {
+ var image = images.eq(i).attr('name');
+ if (image) {
+ // Columns are: name, selectable, OS version, OS arch, OS name, type, profile, method, and description
+ var cols = images.eq(i).parents('tr').find('td');
+ var selectable = cols.eq(2).text();
+ var osVersion = cols.eq(3).text();
+ var osArch = cols.eq(4).text();
+ var osName = cols.eq(5).text();
+ var type = cols.eq(6).text();
+ var profile = cols.eq(7).text();
+ var method = cols.eq(8).text();
+ var description = cols.eq(9).text();
+
+ editImageDialog(image, selectable, osVersion, osArch, osName, type, profile, method, description);
+ }
+ }
+ });
+
+ // Delete a profile
+ var deleteLnk = $('Delete');
+ deleteLnk.click(function() {
+ var images = getNodesChecked(tableId);
+ if (images) {
+ deleteImageDialog(images);
+ }
+ });
+
+ // Refresh profiles table
+ var refreshLnk = $('Refresh');
+ refreshLnk.click(function() {
+ queryImages(panelId);
+ });
+
+ // Create an action menu
+ var actionsMenu = createMenu([refreshLnk, createLnk, editLnk, deleteLnk]);
+ actionsMenu.superfish();
+ actionsMenu.css('display', 'inline-block');
+ actionBar.append(actionsMenu);
+
+ // Set correct theme for action menu
+ actionsMenu.find('li').hover(function() {
+ setMenu2Theme($(this));
+ }, function() {
+ setMenu2Normal($(this));
+ });
+
+ // Create a division to hold actions menu
+ var menuDiv = $('');
+ $('#' + tableId + '_wrapper').prepend(menuDiv);
+ menuDiv.append(actionBar);
+ $('#' + tableId + '_filter').appendTo(menuDiv);
+
+ // Resize accordion
+ $('#' + tableId).parents('.ui-accordion').accordion('resize');
+}
+
+/**
+ * Open image dialog
+ */
+function imageDialog() {
+ // Create form to add profile
+ var dialogId = 'createImage';
+ var imageForm = $('');
+
+ // Create info bar
+ var info = createInfoBar('Provide the following attributes for the image. The image name will be generated based on the attributes you will give.');
+ imageForm.append(info);
+
+ var imageName = $('');
+ var selectable = $('');
+ var imageType = $('');
+ var architecture = $('');
+ var osName = $('');
+ var osVersion = $('');
+ var profile = $('');
+ var provisionMethod = $('');
+ var provisionSelect = $('');
+ provisionMethod.append(provisionSelect);
+ var comments = $('');
+ imageForm.append(imageName, selectable, imageType, architecture, osName, osVersion, profile, provisionMethod, comments);
+
+ // Generate tooltips
+ imageForm.find('div input[title],textarea[title],select[title]').tooltip({
+ position: "center right",
+ offset: [-2, 10],
+ effect: "fade",
+ opacity: 0.8,
+ delay: 0,
+ predelay: 800,
+ events: {
+ def: "mouseover,mouseout",
+ input: "mouseover,mouseout",
+ widget: "focus mouseover,blur mouseout",
+ tooltip: "mouseover,mouseout"
+ },
+
+ // Change z index to show tooltip in front
+ onBeforeShow: function() {
+ this.getTip().css('z-index', $.topZIndex());
+ }
+ });
+
+ // Open dialog to add image
+ imageForm.dialog({
+ title:'Create image',
+ modal: true,
+ close: function(){
+ $(this).remove();
+ },
+ width: 400,
+ buttons: {
+ "Ok": function() {
+ // Remove any warning messages
+ $(this).find('.ui-state-error').remove();
+
+ // Get image attributes
+ var imageType = $(this).find('input[name="imagetype"]');
+ var selectable = $(this).find('input[name="selectable"]');
+ var architecture = $(this).find('input[name="osarch"]');
+ var osName = $(this).find('input[name="osname"]');
+ var osVersion = $(this).find('input[name="osvers"]');
+ var profile = $(this).find('input[name="profile"]');
+ var provisionMethod = $(this).find('select[name="provmethod"]');
+ var comments = $(this).find('input[name="comments"]');
+
+ // Check that image attributes are provided before continuing
+ var ready = 1;
+ var inputs = new Array(imageType, architecture, osName, osVersion, profile, provisionMethod);
+ for (var i in inputs) {
+ if (!inputs[i].val()) {
+ inputs[i].css('border-color', 'red');
+ ready = 0;
+ } else
+ inputs[i].css('border-color', '');
+ }
+
+ // If inputs are not complete, show warning message
+ if (!ready) {
+ var warn = createWarnBar('Please provide a value for each missing field.');
+ warn.prependTo($(this));
+ } else {
+ // Override image name
+ $(this).find('input[name="imagename"]').val(osVersion.val() + '-' + architecture.val() + '-' + provisionMethod.val() + '-' + profile.val());
+ var imageName = $(this).find('input[name="imagename"]');
+
+ // Change dialog buttons
+ $(this).dialog('option', 'buttons', {
+ 'Close': function() {$(this).dialog("close");}
+ });
+
+ // Set default description
+ if (!comments.val())
+ comments.val('No description');
+
+ // Create arguments to send via AJAX
+ var args = 'updateosimage;' + imageName.val() + ';' +
+ imageType.val() + ';' +
+ architecture.val() + ';' +
+ osName.val() + ';' +
+ osVersion.val() + ';' +
+ profile.val() + ';' +
+ provisionMethod.val() + ';';
+
+ if (selectable.attr('checked'))
+ args += '"description:' + comments.val() + '|selectable:yes"';
+ else
+ args += '"description:' + comments.val() + '|selectable:no"';
+
+ // Add image to xCAT
+ $.ajax( {
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : args,
+ msg : dialogId
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ updatePanel(data);
+ }
+ });
+ }
+ },
+ "Cancel": function() {
+ $(this).dialog( "close" );
+ }
+ }
+ });
+}
+
+/**
+ * Edit image dialog
+ *
+ * @param iName Image name
+ * @param iSelectable Is image selectable from service page
+ * @param iOsVersion OS version
+ * @param iProfile Profile name
+ * @param iMethod Provisioning method
+ * @param iComments Image description
+ */
+function editImageDialog(iName, iSelectable, iOsVersion, iOsArch, iOsName, iType, iProfile, iMethod, iComments) {
+ var inst = 0;
+ var dialogId = 'editImage' + inst;
+ while ($('#' + dialogId).length) {
+ // If one already exists, generate another one
+ inst = inst + 1;
+ dialogId = 'editImage' + inst;
+ }
+
+ // Create form to add profile
+ var imageForm = $('');
+
+ // Create info bar
+ var info = createInfoBar('Provide the following attributes for the image. The image name will be generated based on the attributes you will give.');
+ imageForm.append(info);
+
+ var imageName = $('');
+ var selectable = $('');
+ var imageType = $('');
+ var architecture = $('');
+ var osName = $('');
+ var osVersion = $('');
+ var profile = $('');
+ var provisionMethod = $('');
+ var provisionSelect = $('');
+ provisionMethod.append(provisionSelect);
+ var comments = $('');
+ imageForm.append(imageName, selectable, imageType, architecture, osName, osVersion, profile, provisionMethod, comments);
+
+ // Fill in image attributes
+ imageForm.find('input[name="imagename"]').val(iName);
+ imageForm.find('input[name="osvers"]').val(iOsVersion);
+ imageForm.find('input[name="osarch"]').val(iOsArch);
+ imageForm.find('input[name="osname"]').val(iOsName);
+ imageForm.find('input[name="imagetype"]').val(iType);
+ imageForm.find('input[name="profile"]').val(iProfile);
+ imageForm.find('select[name="provmethod"]').val(iMethod);
+ imageForm.find('input[name="comments"]').val(iComments);
+ if (iSelectable == "yes")
+ imageForm.find('input[name="selectable"]').attr('checked', 'checked');
+
+ // Generate tooltips
+ imageForm.find('div input[title],textarea[title],select[title]').tooltip({
+ position: "center right",
+ offset: [-2, 10],
+ effect: "toggle",
+ opacity: 0.8,
+ delay: 0,
+ predelay: 800,
+ events: {
+ def: "mouseover,mouseout",
+ input: "mouseover,mouseout",
+ widget: "focus mouseover,blur mouseout",
+ tooltip: "mouseover,mouseout"
+ },
+
+ // Change z index to show tooltip in front
+ onBeforeShow: function() {
+ this.getTip().css('z-index', $.topZIndex());
+ }
+ });
+
+ // Open dialog to add image
+ imageForm.dialog({
+ title:'Edit image',
+ modal: true,
+ close: function(){
+ $(this).remove();
+ },
+ width: 400,
+ buttons: {
+ "Ok": function() {
+ // Remove any warning messages
+ $(this).find('.ui-state-error').remove();
+
+ // Get image attributes
+ var imageType = $(this).find('input[name="imagetype"]');
+ var selectable = $(this).find('input[name="selectable"]');
+ var architecture = $(this).find('input[name="osarch"]');
+ var osName = $(this).find('input[name="osname"]');
+ var osVersion = $(this).find('input[name="osvers"]');
+ var profile = $(this).find('input[name="profile"]');
+ var provisionMethod = $(this).find('select[name="provmethod"]');
+ var comments = $(this).find('input[name="comments"]');
+
+ // Check that image attributes are provided before continuing
+ var ready = 1;
+ var inputs = new Array(imageType, architecture, osName, osVersion, profile, provisionMethod);
+ for (var i in inputs) {
+ if (!inputs[i].val()) {
+ inputs[i].css('border-color', 'red');
+ ready = 0;
+ } else
+ inputs[i].css('border-color', '');
+ }
+
+ // If inputs are not complete, show warning message
+ if (!ready) {
+ var warn = createWarnBar('Please provide a value for each missing field.');
+ warn.prependTo($(this));
+ } else {
+ // Override image name
+ $(this).find('input[name="imagename"]').val(osVersion.val() + '-' + architecture.val() + '-' + provisionMethod.val() + '-' + profile.val());
+ var imageName = $(this).find('input[name="imagename"]');
+
+ // Change dialog buttons
+ $(this).dialog('option', 'buttons', {
+ 'Close': function() {$(this).dialog("close");}
+ });
+
+ // Set default description
+ if (!comments.val())
+ comments.val('No description');
+
+ // Create arguments to send via AJAX
+ var args = 'updateosimage;' + imageName.val() + ';' +
+ imageType.val() + ';' +
+ architecture.val() + ';' +
+ osName.val() + ';' +
+ osVersion.val() + ';' +
+ profile.val() + ';' +
+ provisionMethod.val() + ';';
+
+ if (selectable.attr('checked'))
+ args += '"description:' + comments.val() + '|selectable:yes"';
+ else
+ args += '"description:' + comments.val() + '|selectable:no"';
+
+ // Add image to xCAT
+ $.ajax( {
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : args,
+ msg : dialogId
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ updatePanel(data);
+ }
+ });
+ }
+ },
+ "Cancel": function() {
+ $(this).dialog( "close" );
+ }
+ }
+ });
+}
+
+/**
+ * Open dialog to confirm image delete
+ *
+ * @param images Images to delete
+ */
+function deleteImageDialog(images) {
+ // Create form to delete disk to pool
+ var dialogId = 'deleteImage';
+ var deleteForm = $('');
+
+ // Create info bar
+ var info = createInfoBar('Are you sure you want to delete ' + images.replace(new RegExp(',', 'g'), ', ') + '?');
+ deleteForm.append(info);
+
+ // Open dialog to delete user
+ deleteForm.dialog({
+ title:'Delete image',
+ modal: true,
+ width: 400,
+ close: function(){
+ $(this).remove();
+ },
+ buttons: {
+ "Ok": function(){
+ // Remove any warning messages
+ $(this).find('.ui-state-error').remove();
+
+ // Change dialog buttons
+ $(this).dialog('option', 'buttons', {
+ 'Close': function() {$(this).dialog("close");}
+ });
+
+ // Delete user
+ $.ajax( {
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : 'rmosimage;' + images,
+ msg : dialogId
+ },
+ success : function(data) {
+ data = decodeRsp(data);
+ updatePanel(data);
+ }
+ });
+ },
+ "Cancel": function() {
+ $(this).dialog( "close" );
+ }
+ }
+ });
+}
+
+/**
+ * Query the groups that exists
+ *
+ * @param panelId Panel ID
+ */
+function queryGroups(panelId) {
+ $.ajax( {
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'tabdump',
+ tgt : '',
+ args : 'hosts',
+ msg : panelId
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ configGroupPanel(data);
+ }
+ });
+}
+
+/**
+ * Panel to configure groups
+ *
+ * @param data Data from HTTP request
+ */
+function configGroupPanel(data) {
+ var panelId = data.msg;
+ var rsp = data.rsp;
+
+ // Wipe panel clean
+ $('#' + panelId).empty();
+
+ // Add info bar
+ $('#' + panelId).append(createInfoBar('Create, edit, and delete groups for the self-service portal.'));
+
+ // Create table
+ var tableId = panelId + 'Datatable';
+ var table = new DataTable(tableId);
+ table.init(['', 'Name', 'Selectable', 'IP', 'Hostname', 'Description']);
+
+ // Insert groups into table
+ var nodePos = 0;
+ var ipPos = 0;
+ var hostnamePos = 0;
+ var commentsPos = 0;
+ var desc, selectable, tmp;
+ // Get column index for each attribute
+ var colNameArray = rsp[0].substr(1).split(',');
+ for (var i in colNameArray){
+ switch (colNameArray[i]){
+ case 'node':
+ nodePos = i;
+ break;
+
+ case 'ip':
+ ipPos = i;
+ break;
+
+ case 'hostnames':
+ hostnamePos = i;
+ break;
+
+ case 'comments':
+ commentsPos = i;
+ break;
+
+ default :
+ break;
+ }
+ }
+
+ // Go through each index
+ for (var i = 1; i < rsp.length; i++) {
+ // Get image name
+ var cols = rsp[i].split(',');
+ var name = cols[nodePos].replace(new RegExp('"', 'g'), '');
+ var ip = cols[ipPos].replace(new RegExp('"', 'g'), '');
+ var hostname = cols[hostnamePos].replace(new RegExp('"', 'g'), '');
+ var comments = cols[commentsPos].replace(new RegExp('"', 'g'), '');
+
+ // Set default description and selectable
+ selectable = "no";
+ network = "";
+ desc = "No description";
+
+ if (comments) {
+ tmp = comments.split('|');
+ for (var j = 0; j < tmp.length; j++) {
+ // Save description
+ if (tmp[j].indexOf('description:') > -1) {
+ desc = tmp[j].replace('description:', '');
+ desc = jQuery.trim(desc);
+ }
+
+ // Is the group selectable?
+ if (tmp[j].indexOf('selectable:') > -1) {
+ selectable = tmp[j].replace('selectable:', '');
+ selectable = jQuery.trim(selectable);
+ }
+ }
+ }
+
+ // Columns are: name, selectable, network, and description
+ var cols = new Array(name, selectable, ip, hostname, desc);
+
+ // Add remove button where id = user name
+ cols.unshift('');
+
+ // Add row
+ table.add(cols);
+ }
+
+ // Append datatable to tab
+ $('#' + panelId).append(table.object());
+
+ // Turn into datatable
+ $('#' + tableId).dataTable({
+ 'iDisplayLength': 50,
+ 'bLengthChange': false,
+ "bScrollCollapse": true,
+ "sScrollY": "400px",
+ "sScrollX": "110%",
+ "bAutoWidth": true,
+ "oLanguage": {
+ "oPaginate": {
+ "sNext": "",
+ "sPrevious": ""
+ }
+ }
+ });
+
+ // Create action bar
+ var actionBar = $('').css("width", "400px");
+
+ // Create a group
+ var createLnk = $('Create');
+ createLnk.click(function() {
+ groupDialog();
+ });
+
+ // Edit a group
+ var editLnk = $('Edit');
+ editLnk.click(function() {
+ var groups = $('#' + tableId + ' input[type=checkbox]:checked');
+ for (var i in groups) {
+ var group = groups.eq(i).attr('name');
+ if (group) {
+ // Column order is: name, selectable, network, and description
+ var cols = groups.eq(i).parents('tr').find('td');
+ var selectable = cols.eq(2).text();
+ var ip = cols.eq(3).text();
+ var hostnames = cols.eq(4).text();
+ var description = cols.eq(5).text();
+
+ editGroupDialog(group, selectable, ip, hostnames, description);
+ }
+ }
+ });
+
+ // Delete a profile
+ var deleteLnk = $('Delete');
+ deleteLnk.click(function() {
+ var groups = getNodesChecked(tableId);
+ if (groups) {
+ deleteGroupDialog(groups);
+ }
+ });
+
+ // Refresh profiles table
+ var refreshLnk = $('Refresh');
+ refreshLnk.click(function() {
+ queryGroups(panelId);
+ });
+
+ // Create an action menu
+ var actionsMenu = createMenu([refreshLnk, createLnk, editLnk, deleteLnk]);
+ actionsMenu.superfish();
+ actionsMenu.css('display', 'inline-block');
+ actionBar.append(actionsMenu);
+
+ // Set correct theme for action menu
+ actionsMenu.find('li').hover(function() {
+ setMenu2Theme($(this));
+ }, function() {
+ setMenu2Normal($(this));
+ });
+
+ // Create a division to hold actions menu
+ var menuDiv = $('');
+ $('#' + tableId + '_wrapper').prepend(menuDiv);
+ menuDiv.append(actionBar);
+ $('#' + tableId + '_filter').appendTo(menuDiv);
+
+ // Resize accordion
+ $('#' + tableId).parents('.ui-accordion').accordion('resize');
+}
+
+/**
+ * Open group dialog
+ */
+function groupDialog() {
+ // Create form to add profile
+ var dialogId = 'createGroup';
+ var groupForm = $('');
+
+ // Create info bar
+ var info = createInfoBar('Provide the following attributes for the group.');
+ groupForm.append(info);
+
+ var group = $('');
+ var selectable = $('');
+ var ip = $('');
+ var hostnames = $('');
+ var comments = $('');
+ var ipPool = $('');
+
+ groupForm.append(group, selectable, ip, hostnames, comments, ipPool);
+
+ // Generate tooltips
+ groupForm.find('div input[title],textarea[title],select[title]').tooltip({
+ position: "center right",
+ offset: [-2, 10],
+ effect: "fade",
+ opacity: 0.8,
+ delay: 0,
+ predelay: 800,
+ events: {
+ def: "mouseover,mouseout",
+ input: "mouseover,mouseout",
+ widget: "focus mouseover,blur mouseout",
+ tooltip: "mouseover,mouseout"
+ },
+
+ // Change z index to show tooltip in front
+ onBeforeShow: function() {
+ this.getTip().css('z-index', $.topZIndex());
+ }
+ });
+
+ // Open dialog to add image
+ groupForm.dialog({
+ title:'Create group',
+ modal: true,
+ close: function(){
+ $(this).remove();
+ },
+ width: 600,
+ buttons: {
+ "Ok": function() {
+ // Remove any warning messages
+ $(this).find('.ui-state-error').remove();
+
+ // Get group attributes
+ var group = $(this).find('input[name="group"]');
+ var selectable = $(this).find('input[name="selectable"]');
+ var ip = $(this).find('input[name="ip"]');
+ var hostnames = $(this).find('input[name="hostnames"]');
+ var comments = $(this).find('input[name="comments"]');
+ var ipPool = $(this).find('textarea[name=ip_pool]').val();
+
+ // Check that group attributes are provided before continuing
+ var ready = 1;
+ var inputs = new Array(group);
+ for (var i in inputs) {
+ if (!inputs[i].val()) {
+ inputs[i].css('border-color', 'red');
+ ready = 0;
+ } else
+ inputs[i].css('border-color', '');
+ }
+
+ // If inputs are not complete, show warning message
+ if (!ready) {
+ var warn = createWarnBar('Please provide a value for each missing field.');
+ warn.prependTo($(this));
+ } else {
+ // Change dialog buttons
+ $(this).dialog('option', 'buttons', {
+ 'Close': function() {$(this).dialog("close");}
+ });
+
+ // A newline at the end of IP pool is needed
+ ipPool = ipPool.replace(/^\s+|\s+$/g, '');
+ ipPool += '\n';
+
+ // Set default description
+ if (!comments.val())
+ comments.val('No description');
+
+ // Create arguments to send via AJAX
+ var args = "updategroup;" + group.val() + ";'" + ip.val() + "';'" + hostnames.val() + "';";
+
+ if (selectable.attr("checked"))
+ args += "'description:" + comments.val() + "|selectable:yes";
+ else
+ args += "'description:" + comments.val() + "|selectable:no";
+
+ // Add image to xCAT
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : args,
+ msg : dialogId
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ updatePanel(data);
+ }
+ });
+
+ // Write IP pool file to /var/tmp
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'write',
+ tgt : '/var/tmp/' + group.val() + '.pool',
+ args : '',
+ cont : ipPool,
+ msg : dialogId + ';' + group.val()
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ var args = data.msg.split(';');
+
+ // Create profile in xCAT
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : 'mkippool;' + args[1],
+ msg : args[0]
+ },
+
+ success: function(data) {
+ data = decodeRsp(data);
+ updatePanel(data);
+ }
+ });
+ }
+ });
+ }
+ },
+ "Cancel": function() {
+ $(this).dialog( "close" );
+ }
+ }
+ });
+}
+
+/**
+ * Edit group dialog
+ *
+ * @param iGroup Group name
+ * @param iSelectable Is group selectable from the service page
+ * @param iIp Group IP regex
+ * @param iHostnames Group hostnames regex
+ * @param iComments Group description
+ */
+function editGroupDialog(iGroup, iSelectable, iIp, iHostnames, iComments) {
+ // Create form to add profile
+ var dialogId = 'createGroup-' + iGroup;
+ var groupForm = $('');
+
+ // Create info bar
+ var info = createInfoBar('Provide the following attributes for the group.');
+ groupForm.append(info);
+
+ var group = $('');
+ var selectable = $('');
+ var ip = $('');
+ var hostnames = $('');
+ var comments = $('');
+ var ipPool = $('');
+
+ groupForm.append(group, selectable, ip, hostnames, comments, ipPool);
+
+ // Query IP pool based on group name
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : 'lsippool;' + iGroup,
+ msg : dialogId
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ // Populate textarea with IP pool entries
+ $('#' + data.msg).find('textarea[name="ip_pool"]').val(data.rsp[0]);
+ }
+ });
+
+ // Fill in group attributes
+ groupForm.find('input[name="group"]').val(iGroup);
+ groupForm.find('input[name="ip"]').val(iIp);
+ groupForm.find('input[name="hostnames"]').val(iHostnames);
+ groupForm.find('input[name="comments"]').val(iComments);
+ if (iSelectable == "yes")
+ groupForm.find('input[name="selectable"]').attr('checked', 'checked');
+
+ // Generate tooltips
+ groupForm.find('div input[title],textarea[title],select[title]').tooltip({
+ position: "center right",
+ offset: [-2, 10],
+ effect: "toggle",
+ opacity: 0.8,
+ delay: 0,
+ predelay: 800,
+ events: {
+ def: "mouseover,mouseout",
+ input: "mouseover,mouseout",
+ widget: "focus mouseover,blur mouseout",
+ tooltip: "mouseover,mouseout"
+ },
+
+ // Change z index to show tooltip in front
+ onBeforeShow: function() {
+ this.getTip().css('z-index', $.topZIndex());
+ }
+ });
+
+ // Open dialog to add image
+ groupForm.dialog({
+ title:'Edit group',
+ modal: true,
+ close: function(){
+ $(this).remove();
+ },
+ width: 600,
+ buttons: {
+ "Ok": function() {
+ // Remove any warning messages
+ $(this).find('.ui-state-error').remove();
+
+ // Get group attributes
+ var group = $(this).find('input[name="group"]');
+ var selectable = $(this).find('input[name="selectable"]');
+ var ip = $(this).find('input[name="ip"]');
+ var hostnames = $(this).find('input[name="hostnames"]');
+ var comments = $(this).find('input[name="comments"]');
+ var ipPool = $(this).find('textarea[name=ip_pool]').val();
+
+ // Check that group attributes are provided before continuing
+ var ready = 1;
+ var inputs = new Array(group);
+ for (var i in inputs) {
+ if (!inputs[i].val()) {
+ inputs[i].css('border-color', 'red');
+ ready = 0;
+ } else
+ inputs[i].css('border-color', '');
+ }
+
+ // If inputs are not complete, show warning message
+ if (!ready) {
+ var warn = createWarnBar('Please provide a value for each missing field.');
+ warn.prependTo($(this));
+ } else {
+ // Change dialog buttons
+ $(this).dialog('option', 'buttons', {
+ 'Close': function() {$(this).dialog("close");}
+ });
+
+ // A newline at the end of IP pool is needed
+ ipPool = ipPool.replace(/^\s+|\s+$/g, '');
+ ipPool += '\n';
+
+ // Set default description
+ if (!comments.val())
+ comments.val('No description');
+
+ // Create arguments to send via AJAX
+ var args = "updategroup;" + group.val() + ";'" + ip.val() + "';'" + hostnames.val() + "';";
+
+ if (selectable.attr("checked"))
+ args += "'description:" + comments.val() + "|selectable:yes";
+ else
+ args += "'description:" + comments.val() + "|selectable:no";
+
+ // Add image to xCAT
+ $.ajax( {
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : args,
+ msg : dialogId
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ updatePanel(data);
+ }
+ });
+
+ // Write IP pool file to /var/tmp
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'write',
+ tgt : '/var/tmp/' + group.val() + '.pool',
+ args : '',
+ cont : ipPool,
+ msg : dialogId + ';' + group.val()
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ var args = data.msg.split(';');
+
+ // Create profile in xCAT
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : 'mkippool;' + args[1],
+ msg : args[0]
+ },
+
+ success: function(data) {
+ data = decodeRsp(data);
+ updatePanel(data);
+ }
+ });
+ }
+ });
+ }
+ },
+ "Cancel": function() {
+ $(this).dialog( "close" );
+ }
+ }
+ });
+}
+
+/**
+ * Open dialog to confirm group delete
+ *
+ * @param groups Groups to delete
+ */
+function deleteGroupDialog(groups) {
+ // Create form to delete disk to pool
+ var dialogId = 'deleteImage';
+ var deleteForm = $('');
+
+ // Create info bar
+ var info = createInfoBar('Are you sure you want to delete ' + groups.replace(new RegExp(',', 'g'), ', ') + '?');
+ deleteForm.append(info);
+
+ // Open dialog to delete user
+ deleteForm.dialog({
+ title:'Delete group',
+ modal: true,
+ width: 400,
+ close: function(){
+ $(this).remove();
+ },
+ buttons: {
+ "Ok": function(){
+ // Remove any warning messages
+ $(this).find('.ui-state-error').remove();
+
+ // Change dialog buttons
+ $(this).dialog('option', 'buttons', {
+ 'Close': function() {$(this).dialog("close");}
+ });
+
+ // Delete user
+ $.ajax( {
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : 'rmgroup;' + groups,
+ msg : dialogId
+ },
+ success : function(data) {
+ data = decodeRsp(data);
+ updatePanel(data);
+ }
+ });
+ },
+ "Cancel": function() {
+ $(this).dialog( "close" );
+ }
+ }
+ });
}
\ No newline at end of file
diff --git a/xCAT-UI/js/configure/update.js b/xCAT-UI/js/configure/update.js
index 65d339292..1d8684891 100644
--- a/xCAT-UI/js/configure/update.js
+++ b/xCAT-UI/js/configure/update.js
@@ -1,310 +1,322 @@
-/**
- * Load update page
- */
-function loadUpdatePage() {
- var repositoryDiv = $('');
- var rpmDiv = $('');
- var statusDiv = createStatusBar("update");
- statusDiv.hide();
-
- $('#updateTab').append(statusDiv);
- $('#updateTab').append(repositoryDiv);
- $('#updateTab').append(rpmDiv);
-
- var infoBar = createInfoBar('Select the repository to use and the RPMs to update, then click Update.');
- repositoryDiv.append(infoBar);
-
- repositoryDiv.append("");
- $.ajax( {
- url : 'lib/systemcmd.php',
- dataType : 'json',
- data : {
- cmd : 'ostype'
- },
-
- success : showRepository
- });
-
- rpmDiv.append("");
- $.ajax( {
- url : 'lib/systemcmd.php',
- dataType : 'json',
- data : {
- cmd : 'rpm -q xCAT-client perl-xCAT xCAT-server xCAT xCAT-rmc xCAT-UI'
- },
-
- success : showRpmInfo
- });
-}
-
-/**
- * Show the RPM repository (it can use the user's last choice and input)
- *
- * @param data Data returned from HTTP request
- */
-function showRepository(data) {
- var develRepository = "";
- var stableRepository = "";
- var show = "";
-
- // Get the corresponding repository by OS Type
- if (data.rsp == "aix") {
- // No repository exists for AIX on Sourceforge!
- develRepository = "http://xcat.sourceforge.net/aix/devel/xcat-core/";
- stableRepository = "http://xcat.sourceforge.net/aix/xcat-core/";
- } else {
- develRepository = "http://sourceforge.net/projects/xcat/files/yum/devel/xcat-core/";
- stableRepository = "http://sourceforge.net/projects/xcat/files/yum/stable/xcat-core/";
- }
-
- var repoList = $('');
-
- // Display the Devel Repository, remember user's last selection
- show = show + "
";
- show = show + "Development: " + develRepository + "
";
- repoList.append(show);
-
- // Display the Stable Repository, remember user's last selection
- show = "
";
- show = show + "Stable: " + stableRepository + "
";
- repoList.append(show);
-
- // Display the Input Repository, remember user's last selection
- if (($.cookie('xcat_repository')) && ($.cookie('xcat_repository') != 1)
- && ($.cookie('xcat_repository') != 2)) {
- show = "
Other: ";
- show += "";
- } else {
- show = "
Other: ";
- show += "";
- }
- repoList.append(show);
-
- $('#repository fieldset').append(repoList);
-}
-
-/**
- * Show all xCAT RPMs
- *
- * @param data Data returned from HTTP request
- */
-function showRpmInfo(data) {
- var rpms = null;
- var show = "";
- var rpmNames = new Array("xCAT-client", "perl-xCAT", "xCAT-server", "xCAT", "xCAT-rmc",
- "xCAT-UI");
- var temp = 0;
- if (null == data.rsp) {
- $('#rpm fieldset').append("Error getting RPMs!");
- return;
- }
-
- rpms = data.rsp.split(/\n/);
-
- // No rpm installed, return
- if (1 > rpms.length) {
- $('#rpm fieldset').append("No RPMs installed!");
- return;
- }
-
- // Clear the old data
- $('#rpm fieldset').children().remove();
- $('#rpm fieldset').append("");
- show = "
";
- show += "
";
- show += "
";
- show += "
Package Name
Version
";
- show += "
";
- for (temp = 0; temp < rpms.length; temp++) {
- // Empty line continue
- if (!rpms[temp]) {
- continue;
- }
-
- // The RPM is not installed, continue
- if (rpms[temp].indexOf("not") != -1) {
- continue;
- }
-
- // Show the version in table
- show += "
";
- show += " ";
- $('#rpm fieldset').append(show);
-
- // Add the update button
- var updateButton = createButton('Update');
- $('#rpm fieldset').append(updateButton);
- updateButton.bind('click', function() {
- updateRpm();
- });
-}
-
-/**
- * Select all checkboxes
- */
-function updateSelectAll() {
- var check_status = $('#selectall').attr('checked');
- $('input:checkbox').attr('checked', check_status);
-}
-
-/**
- * Update selected xCAT RPMs
- */
-function updateRpm() {
- // Remove any warning messages
- $('#updateTab').find('.ui-state-error').remove();
-
- var rpmPath = $('input[type=radio]:checked').val();
- var rpmPathType = "0";
- var rpms = "";
- var temp = "";
-
- if (undefined == rpmPath) {
- rpmPath = "";
- }
-
- // Select other and we should use the value in the input
- if ("" == rpmPath) {
- // Store repo in a cookie
- rpmPath = $('#repositoryaddr').val();
- rpmPathType = rpmPath;
- } else {
- if (-1 == rpmPath.toLowerCase().indexOf("devel")) {
- rpmPathType = "2";
- } else {
- rpmPathType = "1";
- }
- }
-
- $("input[type=checkbox]:checked").each(function() {
- temp = $(this).val();
- if ("" == temp) {
- return true;
- }
-
- var pattern = new RegExp("^" + temp + ",|," + temp + ",");
- if (pattern.test(rpms)) {
- return true;
- }
-
- rpms = rpms + temp + ",";
- });
-
- if (0 < rpms.length) {
- rpms = rpms.slice(0, -1);
- }
-
- // Check RPM and repository
- var errMsg = '';
- if (!rpms) {
- errMsg = "Please select an RPM! ";
- }
-
- if (!rpmPath) {
- errMsg += "Please select or specify a repository!";
- }
-
- if (!rpms || !rpmPath) {
- // Show warning message
- var warn = createWarnBar(errMsg);
- warn.prependTo($('#updateTab'));
- return;
- }
-
- // Remember users' choice and input
- $.cookie('xcat_repository', rpmPathType, {
- path : '/xcat',
- secure : true,
- expires : 10
- });
-
- $('#update').show();
- $('#update div').empty();
- $('#update div').append("
Updating " + rpms + " from " + rpmPath + "
");
- $('#update div').append("");
- $('#rpm button').attr('disabled', 'true');
-
- // Send the update command to server
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : 'update;' + rpms + ";" + rpmPath,
- msg : ''
- },
-
- success : showUpdateResult
- });
-}
-
-/**
- * Show the results of the RPM update
- *
- * @param data Data returned from HTTP request
- */
-function showUpdateResult(data) {
- var temp = 0;
- $('#loadingpic').remove();
-
- var resArray = data.rsp[0].split(/\n/);
- if (0 < resArray.length) {
- // Show last lines
- if (('' == resArray[resArray.length - 1]) && (resArray.length > 1)) {
- $('#update div').append('
' + resArray[resArray.length - 2] + '
');
- } else {
- $('#update div').append('
' + resArray[resArray.length - 1] + '
');
- }
-
- // Create link to show details
- $('#update div').append(' Show details');
- $('#update div a').css( {
- 'color' : '#0000FF',
- 'cursor' : 'pointer'
- }).bind('click', function() {
- // Toggle details and change text
- $('#resDetail').toggle();
- if ($('#update div a').text() == 'Show details') {
- $('#update div a').text('Hide details');
- } else {
- $('#update div a').text('Show details');
- }
- });
-
- var resDetail = $('');
- resDetail.hide();
- $('#update div').append(resDetail);
- for (temp = 0; temp < resArray.length; temp++) {
- resDetail.append(resArray[temp] + ' ');
- }
- }
-
- // Update the rpm info
- $.ajax( {
- url : 'lib/systemcmd.php',
- dataType : 'json',
- data : {
- cmd : 'rpm -q xCAT-client perl-xCAT xCAT-server xCAT xCAT-rmc xCAT-UI'
- },
-
- success : showRpmInfo
- });
-
- $('#rpm button').attr('disabled', '');
+/**
+ * Load update page
+ */
+function loadUpdatePage() {
+ var repositoryDiv = $('');
+ var rpmDiv = $('');
+ var statusDiv = createStatusBar("update");
+ statusDiv.hide();
+
+ $('#updateTab').append(statusDiv);
+ $('#updateTab').append(repositoryDiv);
+ $('#updateTab').append(rpmDiv);
+
+ var infoBar = createInfoBar('Select the repository to use and the RPMs to update, then click Update.');
+ repositoryDiv.append(infoBar);
+
+ repositoryDiv.append("");
+ $.ajax( {
+ url : 'lib/systemcmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'ostype'
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ showRepository(data);
+ }
+ });
+
+ rpmDiv.append("");
+ $.ajax( {
+ url : 'lib/systemcmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'rpm -q xCAT-client perl-xCAT xCAT-server xCAT xCAT-rmc xCAT-UI'
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ showRpmInfo(data);
+ }
+ });
+}
+
+/**
+ * Show the RPM repository (it can use the user's last choice and input)
+ *
+ * @param data Data returned from HTTP request
+ */
+function showRepository(data) {
+ var develRepository = "";
+ var stableRepository = "";
+ var show = "";
+
+ // Get the corresponding repository by OS Type
+ if (data.rsp == "aix") {
+ // No repository exists for AIX on Sourceforge!
+ develRepository = "http://xcat.sourceforge.net/aix/devel/xcat-core/";
+ stableRepository = "http://xcat.sourceforge.net/aix/xcat-core/";
+ } else {
+ develRepository = "http://sourceforge.net/projects/xcat/files/yum/devel/xcat-core/";
+ stableRepository = "http://sourceforge.net/projects/xcat/files/yum/stable/xcat-core/";
+ }
+
+ var repoList = $('');
+
+ // Display the Devel Repository, remember user's last selection
+ show = show + "
";
+ show = show + "Development: " + develRepository + "
";
+ repoList.append(show);
+
+ // Display the Stable Repository, remember user's last selection
+ show = "
";
+ show = show + "Stable: " + stableRepository + "
";
+ repoList.append(show);
+
+ // Display the Input Repository, remember user's last selection
+ if (($.cookie('xcat_repository')) && ($.cookie('xcat_repository') != 1)
+ && ($.cookie('xcat_repository') != 2)) {
+ show = "
Other: ";
+ show += "";
+ } else {
+ show = "
Other: ";
+ show += "";
+ }
+ repoList.append(show);
+
+ $('#repository fieldset').append(repoList);
+}
+
+/**
+ * Show all xCAT RPMs
+ *
+ * @param data Data returned from HTTP request
+ */
+function showRpmInfo(data) {
+ var rpms = null;
+ var show = "";
+ var rpmNames = new Array("xCAT-client", "perl-xCAT", "xCAT-server", "xCAT", "xCAT-rmc",
+ "xCAT-UI");
+ var temp = 0;
+ if (null == data.rsp) {
+ $('#rpm fieldset').append("Error getting RPMs!");
+ return;
+ }
+
+ rpms = data.rsp.split(/\n/);
+
+ // No rpm installed, return
+ if (1 > rpms.length) {
+ $('#rpm fieldset').append("No RPMs installed!");
+ return;
+ }
+
+ // Clear the old data
+ $('#rpm fieldset').children().remove();
+ $('#rpm fieldset').append("");
+ show = "
";
+ show += "
";
+ show += "
";
+ show += "
Package Name
Version
";
+ show += "
";
+ for (temp = 0; temp < rpms.length; temp++) {
+ // Empty line continue
+ if (!rpms[temp]) {
+ continue;
+ }
+
+ // The RPM is not installed, continue
+ if (rpms[temp].indexOf("not") != -1) {
+ continue;
+ }
+
+ // Show the version in table
+ show += "
'));
- imgFS.append(imgAttr);
-
- // Select group name
- var group = $('').append('');
- var groupSelect = $('');
- group.append(groupSelect);
- var groupNames = $.cookie('xcat_groups');
- if (groupNames) {
- var tmp = groupNames.split(',');
- groupSelect.append(''); // Append empty group name
- for (var i in tmp)
- groupSelect.append('');
- }
- nodeAttr.append(group);
-
- // Select node from table
- var nodes = $('');
- var nodesTable = $('
Select a group to view its nodes
');
- nodes.append(nodesTable);
- nodeAttr.append(nodes);
-
- // Select architecture
- var arch = $('').append('');
- var archName = $.cookie('xcat_osarchs');
- if (archName) {
- var archSelect = $('');
- arch.append(archSelect);
-
- var tmp = archName.split(',');
- for (var i in tmp)
- archSelect.append('');
- } else {
- arch.append('');
- }
- imgAttr.append(arch);
-
- imgAttr.append('');
- imgAttr.append('');
- imgAttr.append('');
- imgAttr.append('');
- imgAttr.append('');
- imgAttr.append('');
-
- // When a group is selected, show the nodes belonging to that group
- groupSelect.bind('change', function() {
- var nodesTableId = '#' + tabId + ' #nodesTable';
- $(nodesTableId).append(createLoader());
- createNodesTable($(this).val(), nodesTableId);
- });
-
- return;
-}
-
-/**
- * Provision node
- *
- * @param tabId Provision tab ID
- */
-function provisionNode(tabId) {
- var errorMessage = "";
- var args = new Array();
- var node = "";
-
- // Delete any existing warnings
- $('#' + tabId + ' .ui-state-error').remove();
-
- // Go through each input
- $('#' + tabId + ' input[type!="checkbox"]').each(function() {
- if (!$(this).val()) {
- errorMessage = 'Please provide a value for each missing field!';
- return false;
- } else {
- args.push($(this).val());
- }
- });
-
- // Do not continue if error was found
- if (errorMessage) {
- $('#' + tabId).prepend(createWarnBar(errorMessage));
- return;
- }
-
- // If jumped from nodes page, get node name
- if (tabId == 'quick') {
- node = args.shift();
- } else {
- // Select platform, get node names from table checkbox
- args.unshift($('#' + tabId + ' input[name=arch]').val());
- node = getCheckedByObj($('#' + tabId + ' #nodesTable'));
- }
-
- // Do not continue if a node is not given
- if (!node) {
- $('#' + tabId).prepend(createWarnBar('Please select a node!'));
- return;
- }
-
- var software = getCheckedByObj($('#' + tabId + ' #advanced'));
- var imageName = $('#' + tabId + ' select[name=image]').val();
- var provision = args.join(',');
-
- var url = 'lib/cmd.php?cmd=webrun&tgt=&args=provision;' +
- node + ';' + imageName + ';' + provision + ';' + software + '&msg=&opts=flush';
- $('#' + tabId).prepend(createIFrame(url));
-}
-
-/**
- * Create advance option
- *
- * @param image Image name
- * @param outId Output area ID
- */
-function createAdvancedOptions(image, outId) {
- $.ajax({
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'lsdef',
- tgt : '',
- args : '-t;osimage;' + image + ';-i;osname,provmethod',
- msg : outId
- },
-
- success : function(data) {
- var outId = data.msg;
- var osName = '';
- var provMethod = '';
- var tmpStr = '';
- var position = 0;
-
- for (var i = 0; i < data.rsp.length; i++) {
- tmpStr = data.rsp[i];
- if (tmpStr.indexOf('osname') != -1) {
- position = tmpStr.indexOf('=');
- osName = tmpStr.substr(position + 1);
- }
-
- if (tmpStr.indexOf('provmethod') != -1) {
- position = tmpStr.indexOf('=');
- provMethod = tmpStr.substr(position + 1);
- }
- }
-
- $('#' + outId + ' #advanced').remove();
- if (osName.toLowerCase() == 'aix')
- return;
-
- if (provMethod == 'install') {
- // Create advanced fieldset
- var advancedFS = $('').append($(''));
- $('#' + outId + ' div.form fieldset:eq(1)').after(advancedFS);
-
- advancedFS.append('
Install Ganglia monitoring
');
- }
- }
- });
-}
-
-/**
- * Create nodes table
- *
- * @param group Group name
- * @param outId Output section ID
- */
-function createNodesTable(group, outId) {
- // Get group nodes
- $.ajax({
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'nodels',
- tgt : group,
- args : '',
- msg : outId
- },
-
- success : function(data) {
- var outId = $(data.msg);
- var nodes = data.rsp;
-
- // Create table to hold nodes
- var nTable = $('
');
- var tHead = $('
Node
');
- nTable.append(tHead);
- var tBody = $('');
- nTable.append(tBody);
-
- for (var i in nodes) {
- var node = nodes[i][0];
-
- // Go to next node if there is nothing here
- if (!node)
- continue;
- // Insert node into table
- tBody.append('
' + node + '
');
- }
-
- outId.empty().append(nTable);
-
- if (nodes.length > 10)
- outId.css('height', '300px');
- else
- outId.css('height', 'auto');
- }
- });
-}
-
-/**
- * Get select element names
- *
- * @param obj Object to get selected element names
- * @return Nodes name seperate by a comma
- */
-function getCheckedByObj(obj) {
- var str = '';
-
- // Get nodes that were checked
- obj.find('input:checked').each(function() {
- if ($(this).attr('name')) {
- str += $(this).attr('name') + ',';
- }
- });
-
- if (str) {
- str = str.substr(0, str.length - 1);
- }
-
- return str;
-}
-
-/**
- * Select all checkboxes in the table
- *
- * @param event Event on element
- * @param obj Object triggering event
- */
-function selectAll4Table(event, obj) {
- // Get datatable ID
- // This will ascend from
- var tableObj = obj.parents('table').find('tbody');
- var status = obj.attr('checked');
- tableObj.find(' :checkbox').attr('checked', status);
- event.stopPropagation();
+/**
+ * Create nodes datatable for a given group
+ *
+ * @param group Group name
+ * @param outId Division ID to append datatable
+ * @return Nodes datatable
+ */
+function createNodesDatatable(group, outId) {
+ // Get group nodes
+ $.ajax( {
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'lsdef',
+ tgt : '',
+ args : group,
+ msg : outId
+ },
+
+ /**
+ * Create nodes datatable
+ *
+ * @param data Data returned from HTTP request
+ */
+ success : function(data) {
+ data = decodeRsp(data);
+ // Data returned
+ var rsp = data.rsp;
+
+ // Get output ID
+ var outId = data.msg;
+ // Get datatable ID
+ var dTableId = outId.replace('DIV', '');
+
+ // Node attributes hash
+ var attrs = new Object();
+ // Node attributes
+ var headers = new Object();
+
+ // Clear nodes datatable division
+ $('#' + outId).empty();
+
+ // Create nodes datatable
+ var node = null;
+ var args;
+ for ( var i in rsp) {
+ // Get node
+ var pos = rsp[i].indexOf('Object name:');
+ if (pos > -1) {
+ var temp = rsp[i].split(': ');
+ node = jQuery.trim(temp[1]);
+
+ // Create a hash for the node attributes
+ attrs[node] = new Object();
+ i++;
+ }
+
+ // Get key and value
+ args = rsp[i].split('=');
+ var key = jQuery.trim(args[0]);
+ var val = jQuery.trim(args[1]);
+
+ // Create hash table
+ attrs[node][key] = val;
+ headers[key] = 1;
+ }
+
+ // Sort headers
+ var sorted = new Array();
+ for ( var key in headers) {
+ // Do not put in status or comments
+ if (key.indexOf("status") < 0 && key.indexOf("usercomment") < 0) {
+ sorted.push(key);
+ }
+ }
+ sorted.sort();
+
+ // Add column for check box and node
+ sorted.unshift('', 'node');
+
+ // Create nodes datatable
+ var dTable = new DataTable(dTableId);
+ dTable.init(sorted);
+
+ // Go through each node
+ for ( var node in attrs) {
+ // Create a row
+ var row = new Array();
+ // Create a check box
+ var checkBx = '';
+ row.push(checkBx, node);
+
+ // Go through each header
+ for ( var i = 2; i < sorted.length; i++) {
+ // Add node attributes to the row
+ var key = sorted[i];
+ var val = attrs[node][key];
+ if (val) {
+ row.push(val);
+ } else {
+ row.push('');
+ }
+ }
+
+ // Add row to table
+ dTable.add(row);
+ }
+
+ $('#' + outId).append(dTable.object());
+ $('#' + dTableId).dataTable({
+ 'iDisplayLength': 50,
+ 'bLengthChange': false,
+ "bScrollCollapse": true,
+ "sScrollY": "400px",
+ "sScrollX": "110%",
+ "bAutoWidth": true,
+ "oLanguage": {
+ "oPaginate": {
+ "sNext": "",
+ "sPrevious": ""
+ }
+ }
+ });
+
+ // Fix table styling
+ $('#' + dTableId + '_wrapper .dataTables_filter label').css('width', '250px');
+ } // End of function(data)
+ });
+}
+
+/**
+ * Create provision existing node division
+ *
+ * @param plugin Plugin name to create division for
+ * @param inst Provision tab instance
+ * @return Provision existing node division
+ */
+function createProvisionExisting(plugin, inst) {
+ // Create provision existing division and hide it
+ var provExisting = $('').hide();
+
+ // Create group input
+ var group = $('');
+ var groupLabel = $('');
+ group.append(groupLabel);
+
+ // Turn on auto complete for group
+ var dTableDivId = plugin + 'NodesDatatableDIV' + inst; // Division ID where nodes datatable will be appended
+ var groupNames = $.cookie('xcat_groups');
+ if (groupNames) {
+ // Split group names into an array
+ var tmp = groupNames.split(',');
+
+ // Create drop down for groups
+ var groupSelect = $('');
+ groupSelect.append('');
+ for ( var i in tmp) {
+ // Add group into drop down
+ var opt = $('');
+ groupSelect.append(opt);
+ }
+ group.append(groupSelect);
+
+ // Create node datatable
+ groupSelect.change(function() {
+ // Get group selected
+ var thisGroup = $(this).val();
+ // If a valid group is selected
+ if (thisGroup) {
+ createNodesDatatable(thisGroup, dTableDivId);
+ } // End of if (thisGroup)
+ });
+ } else {
+ // If no groups are cookied
+ var groupInput = $('');
+ group.append(groupInput);
+ }
+ provExisting.append(group);
+
+ // Create node input
+ var node = $('');
+ var nodeLabel = $('');
+ var nodeDatatable = $('
Select a group to view its nodes
');
+ node.append(nodeLabel);
+ node.append(nodeDatatable);
+ provExisting.append(node);
+
+ // Create boot method drop down
+ var method = $('');
+ var methodLabel = $('');
+ var methodSelect = $('');
+ methodSelect.append(''
+ + ''
+ + ''
+ + ''
+ + ''
+ );
+ method.append(methodLabel);
+ method.append(methodSelect);
+ provExisting.append(method);
+
+ // Create boot type drop down
+ var type = $('');
+ var typeLabel = $('');
+ var typeSelect = $('');
+ typeSelect.append(''
+ + ''
+ + ''
+ );
+ type.append(typeLabel);
+ type.append(typeSelect);
+ provExisting.append(type);
+
+ // Create operating system input
+ var os = $('');
+ var osLabel = $('');
+ var osInput = $('');
+ osInput.one('focus', function() {
+ var tmp = $.cookie('xcat_osvers');
+ if (tmp) {
+ // Turn on auto complete
+ $(this).autocomplete({
+ source: tmp.split(',')
+ });
+ }
+ });
+ os.append(osLabel);
+ os.append(osInput);
+ provExisting.append(os);
+
+ // Create architecture input
+ var arch = $('');
+ var archLabel = $('');
+ var archInput = $('');
+ archInput.one('focus', function() {
+ var tmp = $.cookie('xcat_osarchs');
+ if (tmp) {
+ // Turn on auto complete
+ $(this).autocomplete({
+ source: tmp.split(',')
+ });
+ }
+ });
+ arch.append(archLabel);
+ arch.append(archInput);
+ provExisting.append(arch);
+
+ // Create profile input
+ var profile = $('');
+ var profileLabel = $('');
+ var profileInput = $('');
+ profileInput.one('focus', function() {
+ var tmp = $.cookie('xcat_profiles');
+ if (tmp) {
+ // Turn on auto complete
+ $(this).autocomplete({
+ source: tmp.split(',')
+ });
+ }
+ });
+ profile.append(profileLabel);
+ profile.append(profileInput);
+ provExisting.append(profile);
+
+ /**
+ * Provision existing
+ */
+ var provisionBtn = createButton('Provision');
+ provisionBtn.bind('click', function(event) {
+ // TODO Insert provision code here
+ openDialog('info', 'Not yet supported');
+ });
+ provExisting.append(provisionBtn);
+
+ return provExisting;
+}
+
+/**
+ * Create provision new node division
+ *
+ * @param inst Provision tab instance
+ * @return Provision new node division
+ */
+function createProvisionNew(plugin, inst) {
+ // Create provision new node division
+ var provNew = $('');
+
+ // Create node input
+ var nodeName = $('');
+ provNew.append(nodeName);
+
+ // Create group input
+ var group = $('');
+ var groupLabel = $('');
+ var groupInput = $('');
+ groupInput.one('focus', function() {
+ var groupNames = $.cookie('xcat_groups');
+ if (groupNames) {
+ // Turn on auto complete
+ $(this).autocomplete({
+ source: groupNames.split(',')
+ });
+ }
+ });
+ group.append(groupLabel);
+ group.append(groupInput);
+ provNew.append(group);
+
+ // Create boot method drop down
+ var method = $('');
+ var methodLabel = $('');
+ var methodSelect = $('');
+ methodSelect.append(''
+ + ''
+ + ''
+ + ''
+ + ''
+ );
+ method.append(methodLabel);
+ method.append(methodSelect);
+ provNew.append(method);
+
+ // Create boot type drop down
+ var type = $('');
+ var typeLabel = $('');
+ var typeSelect = $('');
+ typeSelect.append(''
+ + ''
+ + ''
+ );
+ type.append(typeLabel);
+ type.append(typeSelect);
+ provNew.append(type);
+
+ // Create operating system input
+ var os = $('');
+ var osLabel = $('');
+ var osInput = $('');
+ osInput.one('focus', function() {
+ var tmp = $.cookie('xcat_osvers');
+ if (tmp) {
+ // Turn on auto complete
+ $(this).autocomplete({
+ source: tmp.split(',')
+ });
+ }
+ });
+ os.append(osLabel);
+ os.append(osInput);
+ provNew.append(os);
+
+ // Create architecture input
+ var arch = $('');
+ var archLabel = $('');
+ var archInput = $('');
+ archInput.one('focus', function() {
+ var tmp = $.cookie('xcat_osarchs');
+ if (tmp) {
+ // Turn on auto complete
+ $(this).autocomplete({
+ source: tmp.split(',')
+ });
+ }
+ });
+ arch.append(archLabel);
+ arch.append(archInput);
+ provNew.append(arch);
+
+ // Create profile input
+ var profile = $('');
+ var profileLabel = $('');
+ var profileInput = $('');
+ profileInput.one('focus', function() {
+ var tmp = $.cookie('xcat_profiles');
+ if (tmp) {
+ // Turn on auto complete
+ $(this).autocomplete({
+ source: tmp.split(',')
+ });
+ }
+ });
+ profile.append(profileLabel);
+ profile.append(profileInput);
+ provNew.append(profile);
+
+ /**
+ * Provision new node
+ */
+ var provisionBtn = createButton('Provision');
+ provisionBtn.bind('click', function(event) {
+ // TODO Insert provision code here
+ openDialog('info', 'Not yet supported');
+ });
+ provNew.append(provisionBtn);
+
+ return provNew;
+}
+
+/**
+ * Create section to provision node
+ *
+ * @param plugin Plugin name
+ * @param container Container to hold provision section
+ */
+function appendProvisionSection(plugin, container) {
+ // Get provision tab ID
+ var tabId = container.parents('.tab').attr('id');
+
+ if (plugin == 'quick')
+ appendProvision4Url(container); // For provisioning based on argmunents found in URL
+ else
+ appendProvision4NoUrl(plugin, container);
+
+ // Add provision button
+ var provisionBtn = createButton('Provision');
+ provisionBtn.bind('click', function(){
+ provisionNode(tabId);
+ });
+ container.append(provisionBtn);
+
+ // Bind image select to change event
+ container.find('select[name=image]').bind('change', function() {
+ createAdvancedOptions($(this).val(), tabId);
+ });
+
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'lsdef',
+ tgt : '',
+ args : '-t;osimage',
+ msg : tabId
+ },
+
+ success : function(data){
+ data = decodeRsp(data);
+ var tabId = data.msg;
+ var i = 0;
+ var imageName = 0;
+ var position = 0;
+ if (!data.rsp.length) {
+ $('#' + tabId).prepend(createWarnBar('Please run copycds and genimage in provision page before continuing!'));
+ return;
+ }
+
+ for (i in data.rsp) {
+ imageName = data.rsp[i];
+ position = imageName.indexOf(' ');
+ imageName = imageName.substr(0, position);
+
+ $('#' + tabId + ' select[name=image]').append($(''));
+ }
+
+ // Trigger select change event
+ $('#' + tabId + ' select[name=image]').trigger('change');
+ // Show provision button
+ $('#' + tabId + ' button').show();
+ }
+ });
+}
+
+/**
+ * Create provision node section using URL
+ *
+ * @param container Container to hold provision section
+ * @returns Nothing
+ */
+function appendProvision4Url(container){
+ // Create node fieldset
+ var nodeFS = $('');
+ var nodeLegend = $('');
+ nodeFS.append(nodeLegend);
+ container.append(nodeFS);
+
+ var nodeAttr = $('');
+ nodeFS.append($('
'));
+ imgFS.append(imgAttr);
+
+ // Select group name
+ var group = $('').append('');
+ var groupSelect = $('');
+ group.append(groupSelect);
+ var groupNames = $.cookie('xcat_groups');
+ if (groupNames) {
+ var tmp = groupNames.split(',');
+ groupSelect.append(''); // Append empty group name
+ for (var i in tmp)
+ groupSelect.append('');
+ }
+ nodeAttr.append(group);
+
+ // Select node from table
+ var nodes = $('');
+ var nodesTable = $('
Select a group to view its nodes
');
+ nodes.append(nodesTable);
+ nodeAttr.append(nodes);
+
+ // Select architecture
+ var arch = $('').append('');
+ var archName = $.cookie('xcat_osarchs');
+ if (archName) {
+ var archSelect = $('');
+ arch.append(archSelect);
+
+ var tmp = archName.split(',');
+ for (var i in tmp)
+ archSelect.append('');
+ } else {
+ arch.append('');
+ }
+ imgAttr.append(arch);
+
+ imgAttr.append('');
+ imgAttr.append('');
+ imgAttr.append('');
+ imgAttr.append('');
+ imgAttr.append('');
+ imgAttr.append('');
+
+ // When a group is selected, show the nodes belonging to that group
+ groupSelect.bind('change', function() {
+ var nodesTableId = '#' + tabId + ' #nodesTable';
+ $(nodesTableId).append(createLoader());
+ createNodesTable($(this).val(), nodesTableId);
+ });
+
+ return;
+}
+
+/**
+ * Provision node
+ *
+ * @param tabId Provision tab ID
+ */
+function provisionNode(tabId) {
+ var errorMessage = "";
+ var args = new Array();
+ var node = "";
+
+ // Delete any existing warnings
+ $('#' + tabId + ' .ui-state-error').remove();
+
+ // Go through each input
+ $('#' + tabId + ' input[type!="checkbox"]').each(function() {
+ if (!$(this).val()) {
+ errorMessage = 'Please provide a value for each missing field!';
+ return false;
+ } else {
+ args.push($(this).val());
+ }
+ });
+
+ // Do not continue if error was found
+ if (errorMessage) {
+ $('#' + tabId).prepend(createWarnBar(errorMessage));
+ return;
+ }
+
+ // If jumped from nodes page, get node name
+ if (tabId == 'quick') {
+ node = args.shift();
+ } else {
+ // Select platform, get node names from table checkbox
+ args.unshift($('#' + tabId + ' input[name=arch]').val());
+ node = getCheckedByObj($('#' + tabId + ' #nodesTable'));
+ }
+
+ // Do not continue if a node is not given
+ if (!node) {
+ $('#' + tabId).prepend(createWarnBar('Please select a node!'));
+ return;
+ }
+
+ var software = getCheckedByObj($('#' + tabId + ' #advanced'));
+ var imageName = $('#' + tabId + ' select[name=image]').val();
+ var provision = args.join(',');
+
+ var url = 'lib/cmd.php?cmd=webrun&tgt=&args=provision;' +
+ node + ';' + imageName + ';' + provision + ';' + software + '&msg=&opts=flush';
+ $('#' + tabId).prepend(createIFrame(url));
+}
+
+/**
+ * Create advance option
+ *
+ * @param image Image name
+ * @param outId Output area ID
+ */
+function createAdvancedOptions(image, outId) {
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'lsdef',
+ tgt : '',
+ args : '-t;osimage;' + image + ';-i;osname,provmethod',
+ msg : outId
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ var outId = data.msg;
+ var osName = '';
+ var provMethod = '';
+ var tmpStr = '';
+ var position = 0;
+
+ for (var i = 0; i < data.rsp.length; i++) {
+ tmpStr = data.rsp[i];
+ if (tmpStr.indexOf('osname') != -1) {
+ position = tmpStr.indexOf('=');
+ osName = tmpStr.substr(position + 1);
+ }
+
+ if (tmpStr.indexOf('provmethod') != -1) {
+ position = tmpStr.indexOf('=');
+ provMethod = tmpStr.substr(position + 1);
+ }
+ }
+
+ $('#' + outId + ' #advanced').remove();
+ if (osName.toLowerCase() == 'aix')
+ return;
+
+ if (provMethod == 'install') {
+ // Create advanced fieldset
+ var advancedFS = $('').append($(''));
+ $('#' + outId + ' div.form fieldset:eq(1)').after(advancedFS);
+
+ advancedFS.append('
Install Ganglia monitoring
');
+ }
+ }
+ });
+}
+
+/**
+ * Create nodes table
+ *
+ * @param group Group name
+ * @param outId Output section ID
+ */
+function createNodesTable(group, outId) {
+ // Get group nodes
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'nodels',
+ tgt : group,
+ args : '',
+ msg : outId
+ },
+
+ success : function(data) {
+ data = decodeRsp(data);
+ var outId = $(data.msg);
+ var nodes = data.rsp;
+
+ // Create table to hold nodes
+ var nTable = $('
');
+ var tHead = $('
Node
');
+ nTable.append(tHead);
+ var tBody = $('');
+ nTable.append(tBody);
+
+ for (var i in nodes) {
+ var node = nodes[i][0];
+
+ // Go to next node if there is nothing here
+ if (!node)
+ continue;
+ // Insert node into table
+ tBody.append('
' + node + '
');
+ }
+
+ outId.empty().append(nTable);
+
+ if (nodes.length > 10)
+ outId.css('height', '300px');
+ else
+ outId.css('height', 'auto');
+ }
+ });
+}
+
+/**
+ * Get select element names
+ *
+ * @param obj Object to get selected element names
+ * @return Nodes name seperate by a comma
+ */
+function getCheckedByObj(obj) {
+ var str = '';
+
+ // Get nodes that were checked
+ obj.find('input:checked').each(function() {
+ if ($(this).attr('name')) {
+ str += $(this).attr('name') + ',';
+ }
+ });
+
+ if (str) {
+ str = str.substr(0, str.length - 1);
+ }
+
+ return str;
+}
+
+/**
+ * Select all checkboxes in the table
+ *
+ * @param event Event on element
+ * @param obj Object triggering event
+ */
+function selectAll4Table(event, obj) {
+ // Get datatable ID
+ // This will ascend from
+ var tableObj = obj.parents('table').find('tbody');
+ var status = obj.attr('checked');
+ tableObj.find(' :checkbox').attr('checked', status);
+ event.stopPropagation();
}
\ No newline at end of file
diff --git a/xCAT-UI/js/custom/zvm.js b/xCAT-UI/js/custom/zvm.js
index 9d6525481..40ba4e946 100644
--- a/xCAT-UI/js/custom/zvm.js
+++ b/xCAT-UI/js/custom/zvm.js
@@ -1,2785 +1,2815 @@
-/**
- * Execute when the DOM is fully loaded
- */
-$(document).ready(function() {
- // Load utility scripts
- includeJs("js/custom/zvmUtils.js");
-});
-
-/**
- * Constructor
- */
-var zvmPlugin = function() {
-
-};
-
-/**
- * Configure self-service configure page
- */
-zvmPlugin.prototype.loadConfigPage = function(tabId) {
- var configAccordion = $('');
-
- // Create accordion panel for profiles
- var profileSection = $('');
- var profileLnk = $('
').click(function () {
- // Do not load panel again if it is already loaded
- if ($('#zvmConfigProfile').find('.dataTables_wrapper').length)
- return;
- else
- $('#zvmConfigProfile').append(createLoader(''));
-
- queryProfiles('zvmConfigProfile');
- });
-
- // Create accordion panel for images
- var imgSection = $('');
- var imgLnk = $('
').click(function () {
- // Do not load panel again if it is already loaded
- if ($('#zvmConfigImages').find('.dataTables_wrapper').length)
- return;
- else
- $('#zvmConfigImages').append(createLoader(''));
-
- queryImages('zvmConfigImages');
- });
-
- // Create accordion panel for groups
- var groupsSection = $('');
- var groupsLnk = $('
').click(function () {
+ // Do not load panel again if it is already loaded
+ if ($('#zvmConfigProfile').find('.dataTables_wrapper').length)
+ return;
+ else
+ $('#zvmConfigProfile').append(createLoader(''));
+
+ queryProfiles('zvmConfigProfile');
+ });
+
+ // Create accordion panel for images
+ var imgSection = $('');
+ var imgLnk = $('
').click(function () {
+ // Do not load panel again if it is already loaded
+ if ($('#zvmConfigImages').find('.dataTables_wrapper').length)
+ return;
+ else
+ $('#zvmConfigImages').append(createLoader(''));
+
+ queryImages('zvmConfigImages');
+ });
+
+ // Create accordion panel for groups
+ var groupsSection = $('');
+ var groupsLnk = $('