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 = $('Directory'); + 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 = $('
      • ' + file.name + '
      • '); + item.prepend(deleteFolderBtn); + itemsList.append(item); + item.dblclick(function() { + loadPath(directory.val() + fullPath); + }); + + // Delete file on click + deleteFolderBtn.click(function() { + deleteFile($(this).parents('li'), directory.val() + fullPath); + }); + } else { + var icon = $(''); + var deleteFileBtn = $(''); + + item = $('
      • ' + file.name + '
      • '); + 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 = $('
        '); - logOpt.hide(); - optsList.append(logOpt); - - // Create clear log checkbox - var clearChkBox = $('
      • '); - optsList.append(clearChkBox); - clearChkBox.append('Clear log'); - - retrieveChkBox.bind('click', function(event) { - tgtLog.toggle(); - }); - - setChkBox.find('input').bind('click', function(event) { - logOpt.toggle(); - }); - - // Generate tooltips - logForm.find('div input[title]').tooltip({ - position : "center right", - offset : [ -2, 10 ], - effect : "fade", - opacity : 0.7, - predelay: 800, - events : { - def : "mouseover,mouseout", - input : "mouseover,mouseout", - widget : "focus mouseover,blur mouseout", - tooltip : "mouseover,mouseout" - } - }); - - /** - * Run node - */ - var runBtn = createButton('Run'); - runBtn.bind('click', function(event) { - // Remove any warning messages - $(this).parent().parent().find('.ui-state-error').remove(); - - var ready = true; - var errMsg = ''; - - // Verify required inputs are provided - var inputs = $('#' + newTabId + ' input'); - for ( var i = 0; i < inputs.length; i++) { - if (!inputs.eq(i).val() - && inputs.eq(i).attr('name') != 'tgtLog' - && inputs.eq(i).attr('name') != 'logOpt') { - inputs.eq(i).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - inputs.eq(i).css('border', 'solid #BDBDBD 1px'); - } - } - - // Write error message - if (!ready) { - errMsg = errMsg + 'Please provide a value for each missing field.
        '; - } - - var tgts = $('#' + newTabId + ' input[name=tgtNode]').val(); - var srcLog = $('#' + newTabId + ' input[name=srcLog]').val(); - - var chkBoxes = $("#" + newTabId + " input[type='checkbox']:checked"); - var optStr = '-s;' + srcLog + ';'; - var opt; - for ( var i = 0; i < chkBoxes.length; i++) { - opt = chkBoxes.eq(i).attr('name'); - optStr += '-' + opt; - - // If it is the retrieve log - if (opt == 't') { - // Append log destination - optStr += ';' + $('#' + newTabId + ' input[name=tgtLog]').val(); - } - - // If it is set options - if (opt == 'o') { - // Append options - optStr += ';' + $('#' + newTabId + ' textarea[name=logOpt]').val(); - } - - // Append ; to end of string - if (i < (chkBoxes.length - 1)) { - optStr += ';'; - } - } - - // If a value is given for every input - if (ready) { - // Do not disable all inputs - //var inputs = $('#' + newTabId + ' input'); - //inputs.attr('disabled', 'disabled'); - - /** - * (1) Retrieve, clear, or set options for event logs - */ - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'reventlog', - tgt : tgts, - args : optStr, - msg : 'out=' + statBarId + ';cmd=reventlog;tgt=' + tgts - }, - - success : updateStatusBar - }); - - // Create loader - $('#' + statBarId).find('div').append(createLoader()); - $('#' + statBarId).show(); - - // Do not disable run button - //$(this).attr('disabled', 'true'); - } else { - // Show warning message - var warn = createWarnBar(errMsg); - warn.prependTo($(this).parent().parent()); - } - }); - logForm.append(runBtn); - - // Add clone tab - tab.add(newTabId, 'Logs', logForm, true); - } - - tab.select(newTabId); -}; +/** + * 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 = $('

        Profiles

        ').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 = $('

        Templates

        ').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 = $('

        Groups

        ').click(function () { + // Do not load panel again if it is already loaded + if ($('#zvmConfigGroups').find('.dataTables_wrapper').length) + return; + else + $('#zvmConfigGroups').append(createLoader('')); + + queryGroups('zvmConfigGroups'); + }); + + configAccordion.append(profileLnk, profileSection, imgLnk, imgSection, groupsLnk, groupsSection); + $('#' + tabId).append(configAccordion); + configAccordion.accordion(); + + profileLnk.trigger('click'); +}; + +/** + * Clone node (service page) + * + * @param node Node to clone + */ +zvmPlugin.prototype.serviceClone = function(node) { + var owner = $.cookie('xcat_username'); + var group = getUserNodeAttr(node, 'groups'); + + // Submit request to clone VM + // webportal clonezlinux [src node] [group] [owner] + var iframe = createIFrame('lib/srv_cmd.php?cmd=webportal&tgt=&args=clonezlinux;' + node + ';' + group + ';' + owner + '&msg=&opts=flush'); + iframe.prependTo($('#manageTab')); +}; + +/** + * Load provision page (service page) + * + * @param tabId Tab ID where page will reside + */ +zvmPlugin.prototype.loadServiceProvisionPage = function(tabId) { + // Create provision form + var provForm = $('
        '); + + // Create info bar + var infoBar = createInfoBar('Provision a Linux virtual machine on IBM z Systems by selecting the appropriate choices below. Once you are ready, click on Provision to provision the virtual machine.'); + provForm.append(infoBar); + + // Append to provision tab + $('#' + tabId).append(provForm); + + // Create provision table + var provTable = $(''); + var provBody = $(''); + var provFooter = $(''); + provTable.append(provHeader, provBody, provFooter); + provForm.append(provTable); + + provHeader.children('th').css({ + 'font': 'bold 12px verdana, arial, helvetica, sans-serif' + }); + + // Create row to contain selections + var provRow = $(''); + provBody.append(provRow); + // Create columns for zVM, group, template, and image + var zvmCol = $(''); + provRow.append(zvmCol); + var groupCol = $(''); + provRow.append(groupCol); + var tmplCol = $(''); + provRow.append(tmplCol); + var imgCol = $(''); + provRow.append(imgCol); + + provRow.children('td').css({ + 'min-width': '200px' + }); + + /** + * Provision VM + */ + var provisionBtn = createButton('Provision'); + provisionBtn.bind('click', function(event) { + // Remove any warning messages + $(this).parent().find('.ui-state-error').remove(); + + var hcp = $('#select-table tbody tr:eq(0) td:eq(0) input[name="hcp"]:checked').val(); + var group = $('#select-table tbody tr:eq(0) td:eq(1) input[name="group"]:checked').val(); + var tmpl = $('#select-table tbody tr:eq(0) td:eq(2) input[name="image"]:checked').val(); + var img = $('#select-table tbody tr:eq(0) td:eq(3) input[name="master"]:checked').val(); + var owner = $.cookie('xcat_username'); + + if (img && !group) { + // Show warning message + var warn = createWarnBar('You need to select a group'); + warn.prependTo($(this).parent()); + } else if (!img && (!hcp || !group || !tmpl)) { + // Show warning message + var warn = createWarnBar('You need to select a zHCP, group, and image'); + warn.prependTo($(this).parent()); + } else { + if (img) { + // Begin by clonning VM + + // Submit request to clone VM + // webportal clonezlinux [src node] [group] [owner] + var iframe = createIFrame('lib/srv_cmd.php?cmd=webportal&tgt=&args=clonezlinux;' + img + ';' + group + ';' + owner + '&msg=&opts=flush'); + iframe.prependTo($('#zvmProvisionTab')); + } else { + // Begin by creating VM + createzVM(tabId, group, hcp, tmpl, owner); + } + } + }); + provForm.append(provisionBtn); + + // Load zVMs, groups, template, and image into their respective columns + loadSrvGroups(groupCol); + loadOSImages(tmplCol); + loadGoldenImages(imgCol); + + // Get zVM host names + if (!$.cookie('xcat_zvms')){ + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webportal', + tgt : '', + args : 'lszvm', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setzVMCookies(data); + loadzVMs(zvmCol); + } + }); + } else { + loadzVMs(zvmCol); + } +}; + +/** + * Show node inventory (service page) + * + * @param data Data from HTTP request + */ +zvmPlugin.prototype.loadServiceInventory = function(data) { + var args = data.msg.split(','); + + // Get tab ID + var tabId = args[0].replace('out=', ''); + // Get node + var node = args[1].replace('node=', ''); + + // Remove loader + $('#' + tabId).find('img').remove(); + + // Do not continue if error is found + if (data.rsp[0].indexOf('Error') > -1) { + var warn = createWarnBar(data.rsp[0]); + $('#' + tabId).append(warn); + return; + } + + // Get node inventory + var inv = data.rsp[0].split(node + ':'); + + // Create array of unique property keys for this node (VM) + // The keys must match all possible keys that zvm.pm rinv could return. Can add new ones to the end. + var keys = new Array('userId', 'host', 'os', 'arch', 'uptime', 'cpuusedtime', 'hcp', 'priv', 'memory', 'maxmemory', 'proc', 'disk', 'zfcp', 'nic', 'hypervisornode'); + + // These two arrays show what keys and what order the data is displayed in the GUI + var guikeysGeneral = new Array('userId', 'host', 'hypervisornode', 'os', 'arch', 'uptime'); + var guikeysHardware = new Array('priv', 'memory', 'maxmemory', 'proc', 'disk', 'zfcp', 'nic'); + + // Create hash table for property names (VM) + var attrNames = new Object(); + attrNames['userId'] = 'z/VM UserID:'; + attrNames['host'] = 'z/VM Host:'; + attrNames['os'] = 'Operating System:'; + attrNames['arch'] = 'Architecture:'; + attrNames['uptime'] = 'Uptime:'; + attrNames['cpuusedtime'] = 'CPU Used Time:'; + attrNames['hcp'] = 'HCP:'; + attrNames['priv'] = 'Privileges:'; + attrNames['memory'] = 'Total Memory:'; + attrNames['maxmemory'] = 'Max Memory:'; + attrNames['proc'] = 'Processors:'; + attrNames['disk'] = 'Disks:'; + attrNames['zfcp'] = 'zFCP:'; + attrNames['nic'] = 'NICs:'; + attrNames['hypervisornode'] = 'xCAT Hypervisor Node:'; + + // Create hash table for node attributes + var attrs = getAttrs(keys, attrNames, inv); + + // Create division to hold inventory + var invDivId = node + 'Inventory'; + var invDiv = $('
        '); + + var infoBar = createInfoBar('Below is the inventory for the virtual machine you selected.'); + invDiv.append(infoBar); + + /** + * General info section + */ + var fieldSet = $('
        '); + var legend = $('General'); + fieldSet.append(legend); + var oList = $('
          '); + var item, label, args; + + // Loop through each general property + for ( var k = 0; k < guikeysGeneral.length; k++) { + // Create a list item for each property + item = $('
        1. '); + + // Create a label - Property name. Change old "z/VM Host label" + if (guikeysGeneral[k] == 'host') { + label = ''; + } else { + label = $(''); + } + item.append(label); + + // Insert the data stored in attr hash using the key + for ( var l = 0; l < attrs[guikeysGeneral[k]].length; l++) { + // Create a input - Property value(s) + // Handle each property uniquely + item.append(attrs[guikeysGeneral[k]][l]); + } + + oList.append(item); + } + // Append to inventory form + fieldSet.append(oList); + invDiv.append(fieldSet); + + /** + * Monitoring section + */ + fieldSet = $('
          '); + legend = $('Monitoring [Refresh]'); + fieldSet.append(legend); +// var info = createInfoBar('No data available'); +// fieldSet.append(info.css('width', '300px')); + + getMonitorMetrics(node); + + // Refresh monitoring charts on-click + legend.find('a').click(function() { + getMonitorMetrics(node); + }); + + // Append to inventory form + invDiv.append(fieldSet); + + /** + * Hardware info section + */ + var hwList, hwItem; + fieldSet = $('
          '); + legend = $('Hardware'); + fieldSet.append(legend); + oList = $('
            '); + + // Loop through each property + var label; + for (k = 0; k < guikeysHardware.length; k++) { + // Create a list item + item = $('
          1. '); + + // Create a list to hold the property value(s) + hwList = $('
              '); + hwItem = $('
            • '); + + /** + * Privilege section + */ + if (guikeysHardware[k] == 'priv') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Loop through each line + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + // Create a new list item for each line + hwItem = $('
            • '); + + // Determine privilege + args = attrs[guikeysHardware[k]][l].split(' '); + if (args[0] == 'Directory:') { + label = $(''); + hwItem.append(label); + hwItem.append(args[1]); + } else if (args[0] == 'Currently:') { + label = $(''); + hwItem.append(label); + hwItem.append(args[1]); + } + + hwList.append(hwItem); + } + + item.append(hwList); + } + + /** + * Memory section + */ + else if (guikeysHardware[k] == 'memory') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Loop through each value line + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + // Create a new list item for each line + hwItem = $('
            • '); + hwItem.append(attrs[guikeysHardware[k]][l]); + hwList.append(hwItem); + } + + item.append(hwList); + } + + /** + * Processor section + */ + else if (guikeysHardware[k] == 'proc') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold processor data + var procTable = $('
              zVM Group Template Image
              '); + var procBody = $(''); + + // Table columns - Type, Address, ID, Base, Dedicated, and Affinity + var procTabRow = $(' Type Address ID Base Dedicated Affinity '); + procTable.append(procTabRow); + var procType, procAddr, procId, procAff; + + // Loop through each processor + var n, temp; + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + if (attrs[guikeysHardware[k]][l]) { + args = attrs[guikeysHardware[k]][l].split(' '); + + // Get processor type, address, ID, and affinity + n = 3; + temp = args[args.length - n]; + while (!jQuery.trim(temp)) { + n = n + 1; + temp = args[args.length - n]; + } + procType = $('' + temp + ''); + procAddr = $('' + args[1] + ''); + procId = $('' + args[5] + ''); + procAff = $('' + args[args.length - 1] + ''); + + // Base processor + if (args[6] == '(BASE)') { + baseProc = $('' + true + ''); + } else { + baseProc = $('' + false + ''); + } + + // Dedicated processor + if (args[args.length - 3] == 'DEDICATED') { + dedicatedProc = $('' + true + ''); + } else { + dedicatedProc = $('' + false + ''); + } + + // Create a new row for each processor + procTabRow = $(''); + procTabRow.append(procType); + procTabRow.append(procAddr); + procTabRow.append(procId); + procTabRow.append(baseProc); + procTabRow.append(dedicatedProc); + procTabRow.append(procAff); + procBody.append(procTabRow); + } + } + + procTable.append(procBody); + item.append(procTable); + } + + /** + * Disk section + */ + else if (guikeysHardware[k] == 'disk') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold disk (DASD) data + var dasdTable = $('
              '); + var dasdBody = $(''); + + // Table columns - Virtual Device, Type, VolID, Type of Access, and Size + var dasdTabRow = $(' Virtual Device # Type VolID Type of Access Size '); + dasdTable.append(dasdTabRow); + var dasdVDev, dasdType, dasdVolId, dasdAccess, dasdSize; + + // Loop through each DASD + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + if (attrs[guikeysHardware[k]][l]) { + args = attrs[guikeysHardware[k]][l].split(' '); + + // Get DASD virtual device, type, volume ID, access, and size + dasdVDev = $('' + args[1] + ''); + dasdType = $('' + args[2] + ''); + dasdVolId = $('' + args[3] + ''); + dasdAccess = $('' + args[4] + ''); + dasdSize = $('' + args[args.length - 9] + ' ' + args[args.length - 8] + ''); + + // Create a new row for each DASD + dasdTabRow = $(''); + dasdTabRow.append(dasdVDev); + dasdTabRow.append(dasdType); + dasdTabRow.append(dasdVolId); + dasdTabRow.append(dasdAccess); + dasdTabRow.append(dasdSize); + dasdBody.append(dasdTabRow); + } + } + + dasdTable.append(dasdBody); + item.append(dasdTable); + } + + /** + * zFCP section + */ + else if (guikeysHardware[k] == 'zfcp') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold NIC data + var zfcpTable = $('
              '); + var zfcpBody = $(''); + + // Table columns - Virtual device, Adapter Type, Port Name, # of Devices, MAC Address, and LAN Name + var zfcpTabRow = $(' Virtual Device # Port Name Unit Number Size'); + zfcpTable.append(zfcpTabRow); + var zfcpVDev, zfcpPortName, zfcpLun, zfcpSize; + + // Loop through each zFCP device + if (attrs[guikeysHardware[k]]) { + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + if (attrs[guikeysHardware[k]][l]) { + args = attrs[guikeysHardware[k]][l].split(' '); + + // Get zFCP virtual device, port name (WWPN), unit number (LUN), and size + zfcpVDev = $('' + args[1].replace('0.0.', '') + ''); + zfcpPortName = $('' + args[4] + ''); + zfcpLun = $('' + args[7] + ''); + zfcpSize = $('' + args[args.length - 2] + ' ' + args[args.length - 1] + ''); + + // Create a new row for each zFCP device + zfcpTabRow = $(''); + zfcpTabRow.append(zfcpVDev); + zfcpTabRow.append(zfcpPortName); + zfcpTabRow.append(zfcpLun); + zfcpTabRow.append(zfcpSize); + + zfcpBody.append(zfcpTabRow); + } + } + } + + zfcpTable.append(zfcpBody); + item.append(zfcpTable); + } + + /** + * NIC section + */ + else if (guikeysHardware[k] == 'nic') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold NIC data + var nicTable = $('
              '); + var nicBody = $(''); + + // Table columns - Virtual device, Adapter Type, Port Name, # of Devices, MAC Address, and LAN Name + var nicTabRow = $('Virtual Device # Adapter Type Port Name # of Devices LAN Name'); + nicTable.append(nicTabRow); + var nicVDev, nicType, nicPortName, nicNumOfDevs, nicLanName; + + // Loop through each NIC (Data contained in 2 lines) + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + if (attrs[guikeysHardware[k]][l].indexOf('Adapter') != -1) { + args = attrs[guikeysHardware[k]][l].split(' '); + + // Get NIC virtual device, type, port name, and number of devices + nicVDev = $('' + args[1] + ''); + nicType = $('' + args[3] + ''); + nicPortName = $('' + args[10] + ''); + nicNumOfDevs = $('' + args[args.length - 1] + ''); + + args = attrs[guikeysHardware[k]][l + 1].split(' '); + nicLanName = $('' + args[args.length - 2] + ' ' + args[args.length - 1] + ''); + + // Create a new row for each DASD + nicTabRow = $(''); + nicTabRow.append(nicVDev); + nicTabRow.append(nicType); + nicTabRow.append(nicPortName); + nicTabRow.append(nicNumOfDevs); + nicTabRow.append(nicLanName); + + nicBody.append(nicTabRow); + } + } + + nicTable.append(nicBody); + item.append(nicTable); + } + + // Ignore any fields not in key + else { + continue; + } + + oList.append(item); + } + + // Append inventory to division + fieldSet.append(oList); + invDiv.append(fieldSet); + invDiv.find('th').css({ + 'padding': '5px 10px', + 'font-weight': 'bold' + }); + + // Append to tab + $('#' + tabId).append(invDiv); +}; + +/** + * Load clone page + * + * @param node Source node to clone + */ +zvmPlugin.prototype.loadClonePage = function(node, nodeOS, nodeArch) { + // Get nodes tab + if (typeof console == "object"){ + console.log("Entering loadClonePage....."); + } + var tab = getNodesTab(); + var newTabId = node + 'CloneTab'; + + // If there is no existing clone tab + if (!$('#' + newTabId).length) { + // Get table headers + var tableId = $('#' + node).parents('table').attr('id'); + var headers = $('#' + tableId).parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr:eq(0) th'); + var cols = new Array(); + for ( var i = 0; i < headers.length; i++) { + var col = headers.eq(i).text(); + cols.push(col); + } + + // Get hardware control point column + var hcpCol = $.inArray('hcp', cols); + + // Get hardware control point + var nodeRow = $('#' + node).parent().parent(); + var datatable = $('#' + getNodesTableId()).dataTable(); + var rowPos = datatable.fnGetPosition(nodeRow.get(0)); + var aData = datatable.fnGetData(rowPos); + var hcp = aData[hcpCol]; + + // Create status bar and hide it + var statBarId = node + 'CloneStatusBar'; + var statBar = createStatusBar(statBarId).hide(); + + // Create info bar + var infoBar = createInfoBar('Clone a zVM node.'); + + // Create clone form + var cloneForm = $('
              '); + cloneForm.append(statBar); + cloneForm.append(infoBar); + + // Create VM fieldset + var vmFS = $('
              '); + var vmLegend = $('Virtual Machine'); + vmFS.append(vmLegend); + cloneForm.append(vmFS); + + var vmAttr = $('
              '); + vmFS.append($('
              ')); + vmFS.append(vmAttr); + + // Create hardware fieldset + var storageFS = $('
              '); + var storageLegend = $('Storage'); + storageFS.append(storageLegend); + cloneForm.append(storageFS); + + var storageAttr = $('
              '); + storageFS.append($('
              ')); + storageFS.append(storageAttr); + + vmAttr.append('
              '); + vmAttr.append('
              '); + vmAttr.append('
              '); + vmAttr.append('
              '); + + // 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); + vmAttr.append(group); + + // Create an advanced link to set IP address and hostname + var advancedLnk = $(''); + vmAttr.append(advancedLnk); + var advanced = $('
              ').hide(); + vmAttr.append(advanced); + + var ip = $('
              '); + advanced.append(ip); + var hostname = $('
              '); + advanced.append(hostname); + + // Show IP address and hostname inputs on-click + advancedLnk.click(function() { + advanced.toggle(); + }); + + if (typeof console == "object"){ + console.log(" loadClonePage hcp data:<"+hcp+">"); + } + // Get list of disk pools + var temp = hcp.split('.'); + var diskPools = $.cookie('xcat_' + temp[0] + 'diskpools'); + + // Create disk pool input + var poolDiv = $('
              '); + var poolLabel = $(''); + var poolInput = $('').autocomplete({ + source: diskPools.split(',') + }); + poolDiv.append(poolLabel); + poolDiv.append(poolInput); + storageAttr.append(poolDiv); + + storageAttr.append('
              '); + + // Generate tooltips + cloneForm.find('div input[title]').tooltip({ + position : "center right", + offset : [ -2, 10 ], + effect : "fade", + opacity : 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + /** + * Clone node + */ + var cloneBtn = createButton('Clone'); + cloneBtn.bind('click', function(event) { + // Remove any warning messages + $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); + + var ready = true; + var errMsg = ''; + + // Check node name, userId, hardware control point, group, and password + var inputs = $('#' + newTabId + ' input'); + for ( var i = 0; i < inputs.length; i++) { + if (!inputs.eq(i).val() + && inputs.eq(i).attr('name') != 'diskPw' + && inputs.eq(i).attr('name') != 'diskPool' + && inputs.eq(i).attr('name') != 'ip' + && inputs.eq(i).attr('name') != 'hostname') { + inputs.eq(i).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + inputs.eq(i).css('border', 'solid #BDBDBD 1px'); + } + } + + // Write error message + if (!ready) { + errMsg = errMsg + 'Please provide a value for each missing field.
              '; + } + + // Get target node + var nodeRange = $('#' + newTabId + ' input[name=tgtNode]').val(); + // Get target user ID + var userIdRange = $('#' + newTabId + ' input[name=tgtUserId]').val(); + // Get IP address range + var ipRange = $('#' + newTabId + ' input[name=ip]').val(); + // Get hostname range + var hostnameRange = $('#' + newTabId + ' input[name=hostname]').val(); + + // Check node range and user ID range + if (nodeRange.indexOf('-') > -1 || userIdRange.indexOf('-') > -1 || ipRange.indexOf('-') > -1 || hostnameRange.indexOf('-') > -1) { + if (nodeRange.indexOf('-') < 0 || userIdRange.indexOf('-') < 0) { + errMsg = errMsg + 'A user ID range and node range needs to be given.
              '; + ready = false; + } else { + var tmp = nodeRange.split('-'); + + // Get node base name + var nodeBase = tmp[0].match(/[a-zA-Z]+/); + // Get starting index + var nodeStart = parseInt(tmp[0].match(/\d+/)); + // Get ending index + var nodeEnd = parseInt(tmp[1].match(/\d+/)); + + tmp = userIdRange.split('-'); + + // Get user ID base name + var userIdBase = tmp[0].match(/[a-zA-Z]+/); + // Get starting index + var userIdStart = parseInt(tmp[0].match(/\d+/)); + // Get ending index + var userIdEnd = parseInt(tmp[1].match(/\d+/)); + + var ipStart = "", ipEnd = ""; + if (ipRange) { + tmp = ipRange.split('-'); + + // Get starting IP address + ipStart = tmp[0].substring(tmp[0].lastIndexOf(".") + 1); + // Get ending IP address + ipEnd = tmp[1].substring(tmp[1].lastIndexOf(".") + 1); + } + + var hostnameStart = "", hostnameEnd = ""; + if (hostnameRange) { + tmp = hostnameRange.split('-'); + + // Get starting hostname + hostnameStart = parseInt(tmp[0].substring(0, tmp[0].indexOf(".")).match(/\d+/)); + // Get ending hostname + hostnameEnd = parseInt(tmp[1].substring(0, tmp[1].indexOf(".")).match(/\d+/)); + } + + // If starting and ending index do not match + if (!(nodeStart == userIdStart) || !(nodeEnd == userIdEnd)) { + // Not ready to provision + errMsg = errMsg + 'The node range and user ID range does not match.
              '; + ready = false; + } + + // If an IP address range is given and the starting and ending index do not match + if (ipRange && (!(nodeStart == ipStart) || !(nodeEnd == ipEnd))) { + errMsg = errMsg + 'The node range and IP address range does not match. '; + ready = false; + } + + // If a hostname range is given and the starting and ending index do not match + if (hostnameRange && (!(nodeStart == hostnameStart) || !(nodeEnd == hostnameEnd))) { + errMsg = errMsg + 'The node range and hostname range does not match. '; + ready = false; + } + } + } + + // Get source node, hardware control point, group, disk pool, and disk password + var srcNode = $('#' + newTabId + ' input[name=srcNode]').val(); + var hcp = $('#' + newTabId + ' input[name=newHcp]').val(); + var group = $('#' + newTabId + ' input[name=newGroup]').val(); + var diskPool = $('#' + newTabId + ' input[name=diskPool]').val(); + var diskPw = $('#' + newTabId + ' input[name=diskPw]').val(); + + // If a value is given for every input + if (ready) { + // Disable all inputs + var inputs = $('#' + newTabId + ' input'); + inputs.attr('disabled', 'disabled'); + + // If a node range is given + if (nodeRange.indexOf('-') > -1) { + var tmp = nodeRange.split('-'); + + // Get node base name + var nodeBase = tmp[0].match(/[a-zA-Z]+/); + // Get starting index + var nodeStart = parseInt(tmp[0].match(/\d+/)); + // Get ending index + var nodeEnd = parseInt(tmp[1].match(/\d+/)); + + tmp = userIdRange.split('-'); + + // Get user ID base name + var userIdBase = tmp[0].match(/[a-zA-Z]+/); + + var ipBase = ""; + if (ipRange) { + tmp = ipRange.split('-'); + + // Get network base + ipBase = tmp[0].substring(0, tmp[0].lastIndexOf(".") + 1); + } + + var domain = ""; + if (hostnameRange) { + tmp = hostnameRange.split('-'); + + // Get domain name + domain = tmp[0].substring(tmp[0].indexOf(".")); + } + + // Loop through each node in the node range + for ( var i = nodeStart; i <= nodeEnd; i++) { + var node = nodeBase + i.toString(); + var userId = userIdBase + i.toString(); + var inst = i + '/' + nodeEnd; + + var args = node + + ';zvm.hcp=' + hcp + + ';zvm.userid=' + userId + + ';nodehm.mgt=zvm' + + ';nodetype.os=' + nodeOS + + ';nodetype.arch=' + nodeArch + + ';groups=' + group; + + if (ipRange) { + var ip = ipBase + i.toString(); + args += ';hosts.ip=' + ip; + } + + if (hostnameRange) { + var hostname = node + domain; + args += ';hosts.hostnames=' + hostname; + } + + /** + * (1) Define node + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeadd', + tgt : '', + args : args, + msg : 'cmd=nodeadd;inst=' + inst + + ';out=' + statBarId + + ';node=' + node + }, + + success : function(data) { + data = decodeRsp(data); + updateZCloneStatus(data); + } + }); + } + } else { + var args = nodeRange + + ';zvm.hcp=' + hcp + + ';zvm.userid=' + userIdRange + + ';nodehm.mgt=zvm' + + ';nodetype.os=' + nodeOS + + ';nodetype.arch=' + nodeArch + + ';groups=' + group; + + if (ipRange) + args += ';hosts.ip=' + ipRange; + + if (hostnameRange) + args += ';hosts.hostnames=' + hostnameRange; + + /** + * (1) Define node + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeadd', + tgt : '', + args : args, + msg : 'cmd=nodeadd;inst=1/1;out=' + statBarId + + ';node=' + nodeRange + }, + + success : function(data) { + data = decodeRsp(data); + updateZCloneStatus(data); + } + }); + } + + // Create loader + $('#' + statBarId).find('div').append(createLoader()); + $('#' + statBarId).show(); + + // Disable clone button + $(this).attr('disabled', 'true'); + } else { + // Show warning message + var warn = createWarnBar(errMsg); + warn.prependTo($(this).parent().parent()); + } + }); + cloneForm.append(cloneBtn); + + // Add clone tab + tab.add(newTabId, 'Clone', cloneForm, true); + } + + tab.select(newTabId); +}; + +/** + * Load node inventory + * + * @param data Data from HTTP request + */ +zvmPlugin.prototype.loadInventory = function(data) { + var args = data.msg.split(','); + + // Get tab ID + var tabId = args[0].replace('out=', ''); + // Get node + var node = args[1].replace('node=', ''); + // Clear any existing cookie + $.cookie('xcat_' + node + 'processes', null, {path: '/xcat', secure:true }); + + // Remove loader + $('#' + tabId).find('img').remove(); + + // Check for error + var error = false; + if (data.rsp.length && data.rsp[0].indexOf('Error') > -1) { + error = true; + + var warn = createWarnBar(data.rsp[0]); + $('#' + tabId).append(warn); + } + + // Determine the node type + if (data.rsp.length && data.rsp[0].indexOf('Hypervisor OS:') > -1) { + loadHypervisorInventory(data); + return; + } + + // Create status bar + var statBarId = node + 'StatusBar'; + var statBar = createStatusBar(statBarId); + + // Add loader to status bar and hide it + var loader = createLoader(node + 'StatusBarLoader').hide(); + statBar.find('div').append(loader); + statBar.hide(); + + // Create division to hold user entry + var ueDivId = node + 'UserEntry'; + var ueDiv = $('
              '); + + // Create division to hold inventory + var invDivId = node + 'Inventory'; + var invDiv = $('
              '); + + /** + * Show user entry + */ + var toggleLinkId = node + 'ToggleLink'; + var toggleLink = $('Show directory entry'); + toggleLink.one('click', function(event) { + // Toggle inventory division + $('#' + invDivId).toggle(); + + // Create loader + var loader = createLoader(node + 'TabLoader'); + loader = $('
              ').append(loader); + ueDiv.append(loader); + + // Get user entry + var msg = 'out=' + ueDivId + ';node=' + node; + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : node, + args : '', + msg : msg + }, + + success : function(data) { + data = decodeRsp(data); + loadUserEntry(data); + } + }); + + // Change text + $(this).text('Show inventory'); + + // Disable toggle link + $(this).unbind(event); + }); + + // Align toggle link to the right + var toggleLnkDiv = $('
              ').css({ + 'text-align' : 'right' + }); + toggleLnkDiv.append(toggleLink); + + // Append to tab + $('#' + tabId).append(statBar); + $('#' + tabId).append(toggleLnkDiv); + $('#' + tabId).append(ueDiv); + $('#' + tabId).append(invDiv); + + // Do not load inventory if no inventory is returned + if (data.rsp.length && data.rsp[0].indexOf('z/VM UserID:') > -1) { + // Do nothing + } else { + return; + } + + // Create array of unique property keys for this node (VM) + // The keys must match all possible keys that zvm.pm rinv could return. Can add new ones to the end. + var keys = new Array('userId', 'host', 'os', 'arch', 'uptime', 'cpuusedtime', 'hcp', 'priv', 'memory', 'maxmemory', 'proc', 'disk', 'zfcp', 'nic', 'hypervisornode'); + + // These two arrays show what keys and what order the data is displayed in the GUI + var guikeysGeneral = new Array('userId', 'host', 'hypervisornode', 'os', 'arch', 'uptime', 'cpuusedtime'); + var guikeysHardware = new Array('priv', 'memory', 'maxmemory', 'proc', 'disk', 'zfcp', 'nic'); + + + // Create hash table for property names (VM) + var attrNames = new Object(); + attrNames['userId'] = 'z/VM UserID:'; + attrNames['host'] = 'z/VM Host:'; + attrNames['os'] = 'Operating System:'; + attrNames['arch'] = 'Architecture:'; + attrNames['uptime'] = 'Uptime:'; + attrNames['cpuusedtime'] = 'CPU Used Time:'; + attrNames['hcp'] = 'HCP:'; + attrNames['priv'] = 'Privileges:'; + attrNames['memory'] = 'Total Memory:'; + attrNames['maxmemory'] = 'Max Memory:'; + attrNames['proc'] = 'Processors:'; + attrNames['disk'] = 'Disks:'; + attrNames['zfcp'] = 'zFCP:'; + attrNames['nic'] = 'NICs:'; + attrNames['hypervisornode'] = 'xCAT Hypervisor Node:'; + + // Create hash table for node attributes + var inv = data.rsp[0].split(node + ':'); + var attrs; + if (!error) { + attrs = getAttrs(keys, attrNames, inv); + } + + // Do not continue if error + if (error) { + return; + } + + // Find the hcp node from the host name + // Start off an ajax request to save the zhcp node name + // in a cookie for possible later use by addNic dialog + var hcpHostname = attrs['hcp']; + if (!$.cookie('xcat_' + node+'_hcpnodename')){ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodels', + tgt : 'mgt==zvm', + args : 'hosts.hostnames', + msg : node+';'+hcpHostname + }, + + success : function(data) { + data = decodeRsp(data); + setNodeZhcpNodename(data); + } + }); + } + + /** + * General info section + */ + var fieldSet = $('
              '); + var legend = $('General'); + fieldSet.append(legend); + var oList = $('
                '); + var item, label, args; + + // Loop through each property + for (var k = 0; k < guikeysGeneral.length; k++) { + // Create a list item for each property + item = $('
              1. '); + + // Create a label - Property name. Change old "z/VM Host label" + if (guikeysGeneral[k] == 'host') { + label = ''; + } else { + label = $(''); + } + item.append(label); + + for (var l = 0; l < attrs[guikeysGeneral[k]].length; l++) { + // Create a input - Property value(s) + // Handle each property uniquely + item.append(attrs[guikeysGeneral[k]][l]); + } + + oList.append(item); + } + // Append to inventory form + fieldSet.append(oList); + invDiv.append(fieldSet); + + /** + * Hardware info section + */ + var hwList, hwItem; + fieldSet = $('
                '); + legend = $('Hardware'); + fieldSet.append(legend); + oList = $('
                  '); + + // Loop through each property + var label; + for (k = 0; k < guikeysHardware.length; k++) { + // Create a list item + item = $('
                1. '); + + // Create a list to hold the property value(s) + hwList = $('
                    '); + hwItem = $('
                  • '); + + /** + * Privilege section + */ + if (guikeysHardware[k] == 'priv') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Loop through each line + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + // Create a new list item for each line + hwItem = $('
                  • '); + + // Determine privilege + args = attrs[guikeysHardware[k]][l].split(' '); + if (args[0] == 'Directory:') { + label = $(''); + hwItem.append(label); + hwItem.append(args[1]); + } else if (args[0] == 'Currently:') { + label = $(''); + hwItem.append(label); + hwItem.append(args[1]); + } + + hwList.append(hwItem); + } + + item.append(hwList); + } + + /** + * Memory section + */ + else if (guikeysHardware[k] == 'memory') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Loop through each value line + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + // Create a new list item for each line + hwItem = $('
                  • '); + hwItem.append(attrs[guikeysHardware[k]][l]); + hwList.append(hwItem); + } + + item.append(hwList); + } + + /** + * Processor section + */ + else if (guikeysHardware[k] == 'proc') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold processor data + var procTable = $('
                    '); + var procBody = $(''); + var procFooter = $(''); + + // Table columns - Type, Address, ID, Base, Dedicated, and Affinity + var procTabRow = $(' Type Address ID Base Dedicated Affinity '); + procTable.append(procTabRow); + var procId, procAff; + + /** + * Remove processor + */ + var contextMenu = [{ + 'Remove' : function(menuItem, menu) { + var addr = $(this).text(); + + // Open dialog to confirm + var confirmDialog = $('

                    Are you sure you want to remove this processor?

                    '); + confirmDialog.dialog({ + title: "Confirm", + modal: true, + width: 300, + buttons: { + "Ok": function(){ + removeProcessor(node, addr); + $(this).dialog("close"); + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); + } + }]; + + // Loop through each processor + var n, temp; + var procType, procAddr, procLink; + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + if (attrs[guikeysHardware[k]][l]) { + args = attrs[guikeysHardware[k]][l].split(' '); + + // Get processor type, address, ID, and affinity + n = 3; + temp = args[args.length - n]; + while (!jQuery.trim(temp)) { + n = n + 1; + temp = args[args.length - n]; + } + procType = $('' + temp + ''); + procAddr = $(''); + procLink = $('' + args[1] + ''); + + // Append context menu to link + procLink.contextMenu(contextMenu, { + theme : 'vista' + }); + + procAddr.append(procLink); + procId = $('' + args[5] + ''); + procAff = $('' + args[args.length - 1] + ''); + + // Base processor + if (args[6] == '(BASE)') { + baseProc = $('' + true + ''); + } else { + baseProc = $('' + false + ''); + } + + // Dedicated processor + if (args[args.length - 3] == 'DEDICATED') { + dedicatedProc = $('' + true + ''); + } else { + dedicatedProc = $('' + false + ''); + } + + // Create a new row for each processor + procTabRow = $(''); + procTabRow.append(procType); + procTabRow.append(procAddr); + procTabRow.append(procId); + procTabRow.append(baseProc); + procTabRow.append(dedicatedProc); + procTabRow.append(procAff); + procBody.append(procTabRow); + } + } + + procTable.append(procBody); + + /** + * Add processor + */ + var addProcLink = $('+ Add temporary processor'); + addProcLink.bind('click', function(event) { + openAddProcDialog(node); + }); + + procFooter.append(addProcLink); + procTable.append(procFooter); + item.append(procTable); + } + + /** + * Disk section + */ + else if (guikeysHardware[k] == 'disk') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold disk (DASD) data + var dasdTable = $('
                    '); + var dasdBody = $(''); + var dasdFooter = $(''); + + /** + * Remove disk + */ + contextMenu = [{ + 'Remove' : function(menuItem, menu) { + var addr = $(this).text(); + + // Open dialog to confirm + var confirmDialog = $('

                    Are you sure you want to remove this disk?

                    '); + confirmDialog.dialog({ + title: "Confirm", + modal: true, + width: 300, + buttons: { + "Ok": function(){ + removeDisk(node, addr); + $(this).dialog("close"); + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); + } + }]; + + // Table columns - Virtual Device, Type, VolID, Type of Access, and Size + var dasdTabRow = $(' Virtual Device # Type VolID Type of Access Size '); + dasdTable.append(dasdTabRow); + var dasdVDev, dasdType, dasdVolId, dasdAccess, dasdSize; + + // Loop through each DASD + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + if (attrs[guikeysHardware[k]][l]) { + args = attrs[guikeysHardware[k]][l].split(' '); + + // Get DASD virtual device, type, volume ID, access, and size + dasdVDev = $(''); + dasdLink = $('' + args[1] + ''); + + // Append context menu to link + dasdLink.contextMenu(contextMenu, { + theme : 'vista' + }); + dasdVDev.append(dasdLink); + + dasdType = $('' + args[2] + ''); + dasdVolId = $('' + args[3] + ''); + dasdAccess = $('' + args[4] + ''); + dasdSize = $('' + args[args.length - 9] + ' ' + args[args.length - 8] + ''); + + // Create a new row for each DASD + dasdTabRow = $(''); + dasdTabRow.append(dasdVDev); + dasdTabRow.append(dasdType); + dasdTabRow.append(dasdVolId); + dasdTabRow.append(dasdAccess); + dasdTabRow.append(dasdSize); + dasdBody.append(dasdTabRow); + } + } + + dasdTable.append(dasdBody); + + /** + * Add disk + */ + var addDasdLink = $('+ Add disk'); + addDasdLink.bind('click', function(event) { + var hcp = attrs['hcp'][0].split('.'); + openAddDiskDialog(node, hcp[0]); + }); + dasdFooter.append(addDasdLink); + dasdTable.append(dasdFooter); + + item.append(dasdTable); + } + + /** + * zFCP section + */ + else if (guikeysHardware[k] == 'zfcp') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold NIC data + var zfcpTable = $('
                    '); + var zfcpBody = $(''); + var zfcpFooter = $(''); + + /** + * Remove zFCP + */ + contextMenu = [ { + 'Remove' : function(menuItem, menu) { + var addr = $(this).text(); + var portName = $(this).parents('tr').find('td:eq(1)').text(); + var unitNo = $(this).parents('tr').find('td:eq(2)').text(); + + // Open dialog to confirm + var confirmDialog = $('

                    Are you sure you want to remove this zFCP device?

                    '); + confirmDialog.dialog({ + title: "Confirm", + modal: true, + width: 300, + buttons: { + "Ok": function(){ + removeZfcp(node, addr, portName, unitNo); + $(this).dialog("close"); + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); + } + } ]; + + // Table columns - Virtual device, Adapter Type, Port Name, # of Devices, MAC Address, and LAN Name + var zfcpTabRow = $(' Virtual Device # Port Name Unit Number Size'); + zfcpTable.append(zfcpTabRow); + var zfcpVDev, zfcpPortName, zfcpLun, zfcpSize; + + // Loop through each zFCP device + if (attrs[guikeysHardware[k]]) { + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + if (attrs[guikeysHardware[k]][l]) { + args = attrs[guikeysHardware[k]][l].split(' '); + + // Get zFCP virtual device, port name (WWPN), unit number (LUN), and size + zfcpVDev = $(''); + zfcpLink = $('' + args[1].replace('0.0.', '') + ''); + + // Append context menu to link + zfcpLink.contextMenu(contextMenu, { + theme : 'vista' + }); + zfcpVDev.append(zfcpLink); + + zfcpPortName = $('' + args[4] + ''); + zfcpLun = $('' + args[7] + ''); + zfcpSize = $('' + args[args.length - 2] + ' ' + args[args.length - 1] + ''); + + // Create a new row for each zFCP device + zfcpTabRow = $(''); + zfcpTabRow.append(zfcpVDev); + zfcpTabRow.append(zfcpPortName); + zfcpTabRow.append(zfcpLun); + zfcpTabRow.append(zfcpSize); + + zfcpBody.append(zfcpTabRow); + } + } + } + + zfcpTable.append(zfcpBody); + + /** + * Add dedicated device + */ + var dedicateDeviceLink = $('+ Add dedicated device').css('display', 'block'); + dedicateDeviceLink.bind('click', function(event) { + var hcp = attrs['hcp'][0].split('.'); + openDedicateDeviceDialog(node, hcp[0]); + }); + + /** + * Add zFCP device + */ + var addZfcpLink = $('+ Add zFCP').css('display', 'block'); + addZfcpLink.bind('click', function(event) { + var hcp = attrs['hcp'][0].split('.'); + var zvm = attrs['host'][0].toLowerCase(); + openAddZfcpDialog(node, hcp[0], zvm); + }); + + zfcpFooter.append(dedicateDeviceLink, addZfcpLink); + zfcpTable.append(zfcpFooter); + + item.append(zfcpTable); + } + + /** + * NIC section + */ + else if (guikeysHardware[k] == 'nic') { + // Create a label - Property name + label = $(''); + item.append(label); + + // Create a table to hold NIC data + var nicTable = $('
                    '); + var nicBody = $(''); + var nicFooter = $(''); + + /** + * Remove NIC + */ + contextMenu = [ { + 'Remove' : function(menuItem, menu) { + var addr = $(this).text(); + + // Open dialog to confirm + var confirmDialog = $('

                    Are you sure you want to remove this NIC?

                    '); + confirmDialog.dialog({ + title: "Confirm", + modal: true, + width: 300, + buttons: { + "Ok": function(){ + removeNic(node, addr); + $(this).dialog("close"); + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); + } + } ]; + + // Table columns - Virtual device, Adapter Type, Port Name, # of Devices, MAC Address, and LAN Name + var nicTabRow = $(' Virtual Device # Adapter Type Port Name # of Devices LAN Name'); + nicTable.append(nicTabRow); + var nicVDev, nicType, nicPortName, nicNumOfDevs, nicLanName; + + // Loop through each NIC (Data contained in 2 lines) + for (l = 0; l < attrs[guikeysHardware[k]].length; l++) { + if (attrs[guikeysHardware[k]][l].indexOf('Adapter') != -1) { + args = attrs[guikeysHardware[k]][l].split(' '); + + // Get NIC virtual device, type, port name, and number of devices + nicVDev = $(''); + nicLink = $('' + args[1] + ''); + + // Append context menu to link + nicLink.contextMenu(contextMenu, { + theme : 'vista' + }); + nicVDev.append(nicLink); + + nicType = $('' + args[3] + ''); + nicPortName = $('' + args[10] + ''); + nicNumOfDevs = $('' + args[args.length - 1] + ''); + + args = attrs[guikeysHardware[k]][l + 1].split(' '); + nicLanName = $('' + args[args.length - 2] + ' ' + args[args.length - 1] + ''); + + // Create a new row for each NIC + nicTabRow = $(''); + nicTabRow.append(nicVDev); + nicTabRow.append(nicType); + nicTabRow.append(nicPortName); + nicTabRow.append(nicNumOfDevs); + nicTabRow.append(nicLanName); + + nicBody.append(nicTabRow); + } + } + + nicTable.append(nicBody); + + /** + * Add NIC + */ + var addNicLink = $('+ Add NIC'); + addNicLink.bind('click', function(event) { + //var hcp = attrs['hcp'][0].split('.'); Old Code + // Pass the full zhcp hostname + openAddNicDialog(node, attrs['hcp'][0]); + }); + nicFooter.append(addNicLink); + nicTable.append(nicFooter); + + item.append(nicTable); + } + + // Ignore any fields not in key + else { + continue; + } + + oList.append(item); + } + + // Append inventory to division + fieldSet.append(oList); + invDiv.append(fieldSet); +}; + +/** + * Load hypervisor inventory + * + * @param data Data from HTTP request + */ +function loadHypervisorInventory(data) { + var args = data.msg.split(','); + + // Get tab ID + var tabId = args[0].replace('out=', ''); + // Get node + var node = args[1].replace('node=', ''); + + // Remove loader + $('#' + tabId).find('img').remove(); + + // Check for error + var error = false; + if (data.rsp.length && data.rsp[0].indexOf('Error') > -1) { + error = true; + + var warn = createWarnBar(data.rsp[0]); + $('#' + tabId).append(warn); + } + + // Get node inventory + var inv = data.rsp[0].split(node + ':'); + + // Create status bar + var statBarId = node + 'StatusBar'; + var statBar = createStatusBar(statBarId); + + // Add loader to status bar and hide it + var loader = createLoader(node + 'StatusBarLoader').hide(); + statBar.find('div').append(loader); + statBar.hide(); + + // Create array of property keys (z/VM hypervisor) + // The keys must match all possible keys that zvm.pm rinv for hypervisor could return. Can add new ones to the end. + var keys = new Array('host', 'hcp', 'arch', 'cecvendor', 'cecmodel', 'hypos', 'hypname', 'lparcputotal', 'lparcpuused', 'lparmemorytotal', 'lparmemoryused', 'lparmemoryoffline', 'hypervisornode'); + + // These two arrays show what keys and what order the data is displayed in the GUI + var guikeysGeneral = new Array('host', 'hypervisornode', 'hcp', 'arch', 'arch', 'cecvendor', 'cecmodel', 'hypos', 'hypname'); + var guikeysHardware = new Array('lparcputotal', 'lparcpuused', 'lparmemorytotal', 'lparmemoryused', 'lparmemoryoffline'); + + + // Create hash table for property names (z/VM hypervisor) + var attrNames = new Object(); + attrNames['host'] = 'z/VM Host:'; + attrNames['hcp'] = 'zHCP:'; + attrNames['arch'] = 'Architecture:'; + attrNames['cecvendor'] = 'CEC Vendor:'; + attrNames['cecmodel'] = 'CEC Model:'; + attrNames['hypos'] = 'Hypervisor OS:'; + attrNames['hypname'] = 'Hypervisor Name:'; + attrNames['lparcputotal'] = 'LPAR CPU Total:'; + attrNames['lparcpuused'] = 'LPAR CPU Used:'; + attrNames['lparmemorytotal'] = 'LPAR Memory Total:'; + attrNames['lparmemoryused'] = 'LPAR Memory Used:'; + attrNames['lparmemoryoffline'] = 'LPAR Memory Offline:'; + attrNames['hypervisornode'] = 'xCAT Hypervisor Node:'; + + // Remove loader + $('#' + tabId).find('img').remove(); + + // Create hash table for node attributes + var attrs; + if (!error) { + attrs = getAttrs(keys, attrNames, inv); + } + + // Create division to hold inventory + var invDivId = node + 'Inventory'; + var invDiv = $('
                    '); + + // Append to tab + $('#' + tabId).append(statBar); + $('#' + tabId).append(invDiv); + + // Do not continue if error + if (error) { + return; + } + + /** + * General info section + */ + var fieldSet = $('
                    '); + var legend = $('General'); + fieldSet.append(legend); + var oList = $('
                      '); + var item, label, args; + + // Loop through each property + for (var k = 0; k < guikeysGeneral.length; k++) { + // Create a list item for each property + item = $('
                    1. '); + + // Create a label - Property name. Change old "z/VM Host label" + if (guikeysGeneral[k] == 'host') { + label = ''; + } else { + label = $(''); + } + item.append(label); + + for (var l = 0; l < attrs[guikeysGeneral[k]].length; l++) { + // Create a input - Property value(s) + // Handle each property uniquely + item.append(attrs[guikeysGeneral[k]][l]); + } + + oList.append(item); + } + // Append to inventory form + fieldSet.append(oList); + invDiv.append(fieldSet); + + /** + * Hardware info section + */ + var hwList, hwItem; + fieldSet = $('
                      '); + legend = $('Hardware'); + fieldSet.append(legend); + oList = $('
                        '); + + // Loop through each property + var label; + for (k = 0; k < guikeysHardware.length; k++) { + // Create a list item for each property + item = $('
                      1. '); + + // Create a label - Property name + label = $(''); + item.append(label); + + for (var l = 0; l < attrs[guikeysHardware[k]].length; l++) { + // Create a input - Property value(s) + // Handle each property uniquely + item.append(attrs[guikeysHardware[k]][l]); + } + + oList.append(item); + } + // Append to inventory form + fieldSet.append(oList); + invDiv.append(fieldSet); + + // Append to inventory form + $('#' + tabId).append(invDiv); +}; + +/** + * Load provision page + * + * @param tabId The provision tab ID + */ +zvmPlugin.prototype.loadProvisionPage = function(tabId) { + if (typeof console == "object") { + console.log("Entering loadProvisionPage "); + } + // Get OS image names + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'osimage', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setOSImageCookies(data); + } + }); + + // Get groups + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'extnoderange', + tgt : '/.*', + args : 'subgroups', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setGroupsCookies(data); + } + }); + + // Get provision tab instance + var inst = tabId.replace('zvmProvisionTab', ''); + + // Create provision form + var provForm = $('
                        '); + + // Create status bar + var statBarId = 'zProvisionStatBar' + inst; + var statBar = createStatusBar(statBarId).hide(); + provForm.append(statBar); + + // Create loader + var loader = createLoader('zProvisionLoader' + inst).hide(); + statBar.find('div').append(loader); + + // Create info bar + var infoBar = createInfoBar('Provision a node on IBM z Systems.'); + provForm.append(infoBar); + + // Append to provision tab + $('#' + tabId).append(provForm); + + var typeFS = $('
                        '); + var typeLegend = $('Type'); + typeFS.append(typeLegend); + provForm.append(typeFS); + + // Create provision type drop down + var provType = $('
                        '); + var typeLabel = $(''); + var typeSelect = $(''); + var provNewNode = $(''); + var provExistNode = $(''); + typeSelect.append(provNewNode); + typeSelect.append(provExistNode); + provType.append(typeLabel); + provType.append(typeSelect); + typeFS.append(provType); + + /** + * Create provision new node division + */ + var provNew = createZProvisionNew(inst); + provForm.append(provNew); + + /** + * Create provision existing node division + */ + var provExisting = createZProvisionExisting(inst); + provForm.append(provExisting); + + // Toggle provision new/existing on select + typeSelect.change(function(){ + var selected = $(this).val(); + if (selected == 'new') { + provNew.toggle(); + provExisting.toggle(); + } else { + provNew.toggle(); + provExisting.toggle(); + } + }); +}; + +/** + * Load the resources + */ +zvmPlugin.prototype.loadResources = function() { + // Reset resource table + setNetworkDataTable(''); + + // Get hardware control points + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodels', + tgt : 'mgt==zvm', + args : 'zvm.hcp;hosts.hostnames', + msg : '' + }, + success : function(data) { + data = decodeRsp(data); + getZResources(data); + } + }); +}; + +/** + * Add node range + */ +zvmPlugin.prototype.addNode = function() { + // Create form to add node range + var addNodeForm = $('
                        '); + var info = createInfoBar('Add a z/VM node range'); + addNodeForm.append(info); + + // Create provision type drop down + var type = $('
                        '); + var typeLabel = $(''); + var typeSelect = $(''); + typeSelect.append(''); + typeSelect.append(''); + type.append(typeLabel); + type.append(typeSelect); + addNodeForm.append(type); + + addNodeForm.append('
                        '); + addNodeForm.append('
                        '); + addNodeForm.append('
                        '); + addNodeForm.append('
                        '); + addNodeForm.append('
                        '); + addNodeForm.append('
                        '); + addNodeForm.append('
                        '); + addNodeForm.append('
                        '); + + // OS field only required for hosts + addNodeForm.find('input[name=os]').parent().hide(); + + // Toggle user Id on select + typeSelect.change(function(){ + var selected = $(this).val(); + if (selected == 'host') { + addNodeForm.find('input[name=userId]').parent().toggle(); + addNodeForm.find('input[name=os]').parent().toggle(); + } else { + addNodeForm.find('input[name=userId]').parent().toggle(); + addNodeForm.find('input[name=os]').parent().toggle(); + } + }); + + // Generate tooltips + addNodeForm.find('div input[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 form as a dialog + addNodeForm.dialog({ + title: 'Add node', + modal: true, + width: 400, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var type = $(this).find('select[name=type]').val(); + var nodeRange = $(this).find('input[name=node]').val(); + var ipRange = $(this).find('input[name=ip]').val(); + var hostnameRange = $(this).find('input[name=hostname]').val(); + var userIdRange = $(this).find('input[name=userId]').val(); + var os = $(this).find('input[name=os]').val(); + var group = $(this).find('input[name=groups]').val(); + var hcp = $(this).find('input[name=hcp]').val(); + + // Check required fields + if (type == 'host') { + if (!nodeRange || !os || !group || !hcp) { + var warn = createWarnBar('Please provide a value for each missing field!'); + warn.prependTo($(this)); + return; + } + } else { + if (!nodeRange || !userIdRange || !group || !hcp) { + var warn = createWarnBar('Please provide a value for each missing field!'); + warn.prependTo($(this)); + return; + } + } + + // Check node range and user ID range + // Range can be given as gpok10-gpok20, gpok[10-20], or gpok10+10 + var errMsg = ''; + var ready = true; + if (nodeRange.indexOf('-') > -1 || userIdRange.indexOf('-') > -1) { + if (nodeRange.indexOf('-') < 0 || userIdRange.indexOf('-') < 0) { + errMsg = errMsg + 'A user ID range and node range needs to be given. '; + ready = false; + } else { + var tmp = nodeRange.split('-'); + + // Get starting index + var nodeStart = parseInt(tmp[0].match(/\d+/)); + // Get ending index + var nodeEnd = parseInt(tmp[1].match(/\d+/)); + + tmp = userIdRange.split('-'); + + // Get starting index + var userIdStart = parseInt(tmp[0].match(/\d+/)); + // Get ending index + var userIdEnd = parseInt(tmp[1].match(/\d+/)); + + var ipStart = "", ipEnd = ""; + if (ipRange != "" && ipRange != null) { + tmp = ipRange.split('-'); + + // Get starting IP address + ipStart = tmp[0].substring(tmp[0].lastIndexOf(".") + 1); + // Get ending IP address + ipEnd = tmp[1].substring(tmp[1].lastIndexOf(".") + 1); + } + + var hostnameStart = "", hostnameEnd = ""; + if (hostnameRange != "" && hostnameRange != null) { + tmp = hostnameRange.split('-'); + + // Get starting hostname + hostnameStart = parseInt(tmp[0].substring(0, tmp[0].indexOf(".")).match(/\d+/)); + // Get ending hostname + hostnameEnd = parseInt(tmp[1].substring(0, tmp[1].indexOf(".")).match(/\d+/)); + } + + // If starting and ending index do not match + if (!(nodeStart == userIdStart) || !(nodeEnd == userIdEnd)) { + errMsg = errMsg + 'The node range and user ID range does not match. '; + ready = false; + } + + // If an IP address range is given and the starting and ending index do not match + if (ipRange != "" && ipRange != null && (!(nodeStart == ipStart) || !(nodeEnd == ipEnd))) { + errMsg = errMsg + 'The node range and IP address range does not match. '; + ready = false; + } + + // If a hostname range is given and the starting and ending index do not match + if (hostnameRange != "" && hostnameRange != null && (!(nodeStart == hostnameStart) || !(nodeEnd == hostnameEnd))) { + errMsg = errMsg + 'The node range and hostname range does not match. '; + ready = false; + } + } + } + + // If there are no errors + if (ready) { + $('#addZvm').append(createLoader()); + + // Change dialog buttons + $('#addZvm').dialog('option', 'buttons', { + 'Close':function() { + $('#addZvm').dialog('destroy').remove(); + } + }); + + // If a node range is given + if (nodeRange.indexOf('-') > -1 && userIdRange.indexOf('-') > -1) { + var tmp = nodeRange.split('-'); + + // Get node base name + var nodeBase = tmp[0].match(/[a-zA-Z]+/); + // Get starting index + var nodeStart = parseInt(tmp[0].match(/\d+/)); + // Get ending index + var nodeEnd = parseInt(tmp[1].match(/\d+/)); + + tmp = userIdRange.split('-'); + + // Get user ID base name + var userIdBase = tmp[0].match(/[a-zA-Z]+/); + + var ipBase = ""; + if (ipRange != "" && ipRange != null) { + tmp = ipRange.split('-'); + + // Get network base + ipBase = tmp[0].substring(0, tmp[0].lastIndexOf(".") + 1); + } + + var domain = ""; + if (hostnameRange != "" && hostnameRange != null) { + tmp = hostnameRange.split('-'); + + // Get domain name + domain = tmp[0].substring(tmp[0].indexOf(".")); + } + + // Loop through each node in the node range + for ( var i = nodeStart; i <= nodeEnd; i++) { + var node = nodeBase + i.toString(); + var userId = userIdBase + i.toString(); + var inst = i + '/' + nodeEnd; + + var args = ""; + if (type == 'host') { + args = node + ';zvm.hcp=' + hcp + + ';nodehm.mgt=zvm;nodetype.arch=s390x;hypervisor.type=zvm;groups=' + group + + ';nodetype.os=' + os; + } else { + args = node + ';zvm.hcp=' + hcp + + ';zvm.userid=' + userId + + ';nodehm.mgt=zvm' + ';nodetype.arch=s390x' + ';groups=' + group; + } + + if (ipRange != "" && ipRange != null) { + var ip = ipBase + i.toString(); + args += ';hosts.ip=' + ip; + } + + if (hostnameRange != "" && hostnameRange != null) { + var hostname = node + domain; + args += ';hosts.hostnames=' + hostname; + } + + /** + * (1) Define node + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeadd', + tgt : '', + args : args, + msg : 'cmd=addnewnode;inst=' + inst + ';noderange=' + nodeRange + }, + + /** + * Return function on successful AJAX call + * + * @param data + * Data returned from HTTP request + * @return Nothing + */ + success : function (data) { + data = decodeRsp(data); + // Get ajax response + var rsp = data.rsp; + var args = data.msg.split(';'); + + // Get instance returned and node range + var inst = args[1].replace('inst=', ''); + var nodeRange = args[2].replace('noderange=', ''); + + // If the last node was added + var tmp = inst.split('/'); + if (tmp[0] == tmp[1]) { + // Update /etc/hosts + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'makehosts', + tgt : '', + args : '', + msg : '' + } + }); + + // Remove loader + $('#addZvm img').remove(); + + // If there was an error, do not continue + if (rsp.length) { + $('#addZvm').prepend(createWarnBar('Failed to create node definitions')); + } else { + $('#addZvm').prepend(createInfoBar('Node definitions created for ' + nodeRange)); + } + } + } + }); + } + } else { + var args = ""; + if (type == 'host') { + args = nodeRange + ';zvm.hcp=' + hcp + + ';nodehm.mgt=zvm;nodetype.arch=s390x;hypervisor.type=zvm;groups=' + group + + ';nodetype.os=' + os; + } else { + args = nodeRange + ';zvm.hcp=' + hcp + + ';zvm.userid=' + userIdRange + + ';nodehm.mgt=zvm' + ';nodetype.arch=s390x' + ';groups=' + group; + } + + if (ipRange) + args += ';hosts.ip=' + ipRange; + + if (hostnameRange) + args += ';hosts.hostnames=' + hostnameRange; + + // Only one node to add + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeadd', + tgt : '', + args : args, + msg : 'cmd=addnewnode;node=' + nodeRange + }, + + /** + * Return function on successful AJAX call + * + * @param data + * Data returned from HTTP request + * @return Nothing + */ + success : function (data) { + data = decodeRsp(data); + // Get ajax response + var rsp = data.rsp; + var args = data.msg.split(';'); + var node = args[1].replace('node=', ''); + + // Update /etc/hosts + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'makehosts', + tgt : '', + args : '', + msg : '' + } + }); + + // Remove loader + $('#addZvm img').remove(); + + // If there was an error, do not continue + if (rsp.length) { + $('#addZvm').prepend(createWarnBar('Failed to create node definitions')); + } else { + $('#addZvm').prepend(createInfoBar('Node definitions created for ' + node)); + } + } + }); + } + } else { + // Show warning message + var warn = createWarnBar(errMsg); + warn.prependTo($(this)); + } + }, + "Cancel": function(){ + $(this).dialog('destroy').remove(); + } + } + }); +}; + +/** + * Migrate page + * + * @param tgtNode Targets to migrate + */ +zvmPlugin.prototype.loadMigratePage = function(tgtNode, fromhcp) { + var hosts = $.cookie('xcat_zvms').split(','); + var radio, zvmBlock, args; + var zvms = new Array(); + var hcp = new Object(); + var invalidDest = ''; + if (typeof console == "object"){ + console.log("Entering loadMigratePage. Target nodes:" + tgtNode + " from hcp:" + fromhcp); + } + + // Create a drop-down for z/VM destinations + var destSelect = $('') + for (var i in hosts) { + args = hosts[i].split(':'); // in format of host: zhcp + if (args[0].length > 0) { + hcp[args[0]] = args[1]; + // Only add target systems that are different than the nodes system + if (-1 == fromhcp.search(args[1]) ) { + zvms.push(args[0]); + destSelect.append($('')); + } else { + invalidDest += args[0] + ' '; + } + } + } + + // Get nodes tab + var tab = getNodesTab(); + + // Generate new tab ID + var inst = 0; + var newTabId = 'migrateTab' + inst; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + inst = inst + 1; + newTabId = 'migrateTab' + inst; + } + + // Open new tab + // Create remote script form + var migrateForm = $('
                        '); + + // Create status bar + var barId = 'migrateStatusBar' + inst; + var statBar = createStatusBar(barId); + statBar.hide(); + migrateForm.append(statBar); + + // Create loader + var loader = createLoader('migrateLoader' + inst); + statBar.find('div').append(loader); + + // Create info bar + var infoBar = createInfoBar('The three actions you can perform from this panel are:
                        Move -- Initiate a VMRELOCATE of the virtual machine.
                        Test - Determine if the specified virtual machine is eligible to be relocated.
                        Cancel -- Stop the relocation of the specified virtual machine.'); + migrateForm.append(infoBar); + + // If any destinations were removed, add information message + if (invalidDest.length) { + infoBar.append("
                        Ineligible destinations have been removed from the destination list because at least one or more of the nodes selected are already associated with the destinations: " + invalidDest) + } + + // Virtual machine label + var vmFS = $('
                        Virtual Machine
                        '); + migrateForm.append(vmFS); + + var vmAttr = $('
                        '); + vmFS.append($('
                        ')); + vmFS.append(vmAttr); + + // Target node or group + var tgt = $('
                        '); + vmAttr.append(tgt); + + // Destination + var dest = $('
                        '); + var destInput = $(''); + destInput.autocomplete({ + source: zvms + }); + + // Create a drop-down if there are known z/VMs + if (zvms.length) { + dest.append(destSelect); + } else { + dest.append(destInput); + } + vmAttr.append(dest); + + // Action Parameter + var actionparam = $('
                        '); + vmAttr.append(actionparam); + + // Parameters label + var optionalFS = $('
                        Optional
                        ').css('margin-top', '20px'); + migrateForm.append(optionalFS); + + var optAttr = $('
                        '); + optionalFS.append($('
                        ')); + optionalFS.append(optAttr); + + // Immediate Parameter + var immediateparam = $('
                        '); + optAttr.append(immediateparam); + immediateparam.change(function() { + if ($('#' + newTabId + ' select[name=immediate]').val() == 'yes') { + $('#' + newTabId + ' input[name=maxQuiesce]').val('0'); + } else { + $('#' + newTabId + ' input[name=maxQuiesce]').val('10'); + } + }); + + // Max total + var maxTotalParam = $('
                        '); + optAttr.append(maxTotalParam); + + // Max quiesce + var maxQuiesceParam = $('
                        '); + optAttr.append(maxQuiesceParam); + + // Force parameter + var forceParam = $('
                        ArchitectureDomainStorage
                        '); + optAttr.append(forceParam); + + // Generate tooltips + migrateForm.find('div input[title],select[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + /** + * Run + */ + var runBtn = createButton('Run'); + runBtn.click(function() { + // Remove any warning messages + $(this).parent().parent().find('.ui-state-error').remove(); + + var tgt = $('#' + newTabId + ' input[name=target]'); + + // Drop-down box exists if z/VM systems are known + // Otherwise, only input box exists + var dest = $('#' + newTabId + ' select[name=dest]'); + if (!dest.length) { + dest = $('#' + newTabId + ' input[name=dest]'); + } + + var action = $('#' + newTabId + ' select[name=action]'); + var immediate = $('#' + newTabId + ' select[name=immediate]'); + var maxTotal = $('#' + newTabId + ' input[name=maxTotal]'); + var maxQuiesce = $('#' + newTabId + ' input[name=maxQuiesce]'); + var tgts = $('#' + newTabId + ' input[name=target]'); + + // Change borders color back to normal + var inputs = $('#' + newTabId + ' input').css('border', 'solid #BDBDBD 1px'); + var inputs = $('#' + newTabId + ' select').css('border', 'solid #BDBDBD 1px'); + + // Check if required arguments are given + var message = ""; + if (!isInteger(maxTotal.val())) { + message += "Max total time must be an integer. "; + maxTotal.css('border', 'solid #FF0000 1px'); + } if (!isInteger(maxQuiesce.val())) { + message += "Max quiesce time must be an integer. "; + maxQuiesce.css('border', 'solid #FF0000 1px'); + } if (!tgt.val()) { + message += "Target must be specified. "; + tgt.css('border', 'solid #FF0000 1px'); + } if (!dest.val()) { + message += "Destination must be specified. "; + dest.css('border', 'solid #FF0000 1px'); + } if (!action.val()) { + message += "Action must be specified. "; + action.css('border', 'solid #FF0000 1px'); + } + + // Show warning message + if (message) { + var warn = createWarnBar(message); + warn.prependTo($(this).parent().parent()); + return; + } + + var args = "destination=" + dest.val() + ";action=" + action.val() + ";immediate=" + immediate.val() + ";"; + + // Append max total argument. Specified <= 0 to accomodate negative values. + if (maxTotal.val() <= 0) { + args = args + "max_total=NOLIMIT;"; + } else { + args = args + "max_total=" + maxTotal.val() + ";"; + } + + // Append max quiesce argument. Specified <= 0 to accomodate negative values. + if (maxQuiesce.val() <= 0) { + args = args + "max_quiesce=NOLIMIT;"; + } else { + args = args + "max_quiesce=" + maxQuiesce.val() + ";"; + } + + // Append force argument + if ($("input[name=force]:checked").length > 0) { + args = args + "'force=" + $("input[name=force]:checked").each(function() { + args += $(this).val() + ' '; + }); + args += "';"; + } + + var statBarId = 'migrateStatusBar' + inst; + $('#' + statBarId).show(); + + // Disable all fields + $('#' + newTabId + ' input').attr('disabled', 'true'); + $('#' + newTabId + ' select').attr('disabled', 'true'); + + // Disable buttons + $('#' + newTabId + ' button').attr('disabled', 'true'); + + // Run migrate + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rmigrate', + tgt : tgts.val(), + args : args, + msg : 'out=migrateStatusBar' + inst + ';cmd=rmigrate;tgt=' + tgts.val() + }, + + success : function(data) { + data = decodeRsp(data); + updateStatusBar(data); + } + }); + }); + migrateForm.append(runBtn); + + // Append to discover tab + tab.add(newTabId, 'Migrate', migrateForm, true); + + // Select new tab + tab.select(newTabId); +}; + +/** + * Load event log configuration page + * + * @param node Source node to clone + */ +zvmPlugin.prototype.loadLogPage = function(node) { + // Get nodes tab + var tab = getNodesTab(); + var newTabId = node + 'LogsTab'; + + // If there is no existing clone tab + if (!$('#' + newTabId).length) { + // Get table headers + var tableId = $('#' + node).parents('table').attr('id'); + var headers = $('#' + tableId).parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr:eq(0) th'); + var cols = new Array(); + for ( var i = 0; i < headers.length; i++) { + var col = headers.eq(i).text(); + cols.push(col); + } + + // Get hardware control point column + var hcpCol = $.inArray('hcp', cols); + + // Get hardware control point + var nodeRow = $('#' + node).parent().parent(); + var datatable = $('#' + getNodesTableId()).dataTable(); + var rowPos = datatable.fnGetPosition(nodeRow.get(0)); + var aData = datatable.fnGetData(rowPos); + var hcp = aData[hcpCol]; + + // Create status bar and hide it + var statBarId = node + 'CloneStatusBar'; + var statBar = createStatusBar(statBarId).hide(); + + // Create info bar + var infoBar = createInfoBar('Retrieve, clear, or set options for event logs.'); + + // Create clone form + var logForm = $('
                        '); + logForm.append(statBar); + logForm.append(infoBar); + + // Create VM fieldset + var vmFS = $('
                        '); + var vmLegend = $('Virtual Machine'); + vmFS.append(vmLegend); + logForm.append(vmFS); + + var vmAttr = $('
                        '); + vmFS.append($('
                        ')); + vmFS.append(vmAttr); + + // Create logs fieldset + var logFS = $('
                        '); + var logLegend = $('Logs'); + logFS.append(logLegend); + logForm.append(logFS); + + var logAttr = $('
                        '); + logFS.append($('
                        ')); + logFS.append(logAttr); + + vmAttr.append('
                        '); + logAttr.append('
                        '); + + var optsLabel = $(''); + var optsList = $('
                          '); + logAttr.append(optsLabel); + logAttr.append(optsList); + + // Create retrieve log checkbox + var retrieveChkBox = $('
                        • '); + optsList.append(retrieveChkBox); + retrieveChkBox.append('Retrieve log'); + + // Create log destination input + var tgtLog = $('
                        • '); + tgtLog.hide(); + optsList.append(tgtLog); + + // Create set log checkbox + var setChkBox = $('
                        • '); + optsList.append(setChkBox); + setChkBox.append('Set options'); + + // Create log options input + var logOpt = $('
                        • '); + logOpt.hide(); + optsList.append(logOpt); + + // Create clear log checkbox + var clearChkBox = $('
                        • '); + optsList.append(clearChkBox); + clearChkBox.append('Clear log'); + + retrieveChkBox.bind('click', function(event) { + tgtLog.toggle(); + }); + + setChkBox.find('input').bind('click', function(event) { + logOpt.toggle(); + }); + + // Generate tooltips + logForm.find('div input[title]').tooltip({ + position : "center right", + offset : [ -2, 10 ], + effect : "fade", + opacity : 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + /** + * Run node + */ + var runBtn = createButton('Run'); + runBtn.bind('click', function(event) { + // Remove any warning messages + $(this).parent().parent().find('.ui-state-error').remove(); + + var ready = true; + var errMsg = ''; + + // Verify required inputs are provided + var inputs = $('#' + newTabId + ' input'); + for ( var i = 0; i < inputs.length; i++) { + if (!inputs.eq(i).val() + && inputs.eq(i).attr('name') != 'tgtLog' + && inputs.eq(i).attr('name') != 'logOpt') { + inputs.eq(i).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + inputs.eq(i).css('border', 'solid #BDBDBD 1px'); + } + } + + // Write error message + if (!ready) { + errMsg = errMsg + 'Please provide a value for each missing field.
                          '; + } + + var tgts = $('#' + newTabId + ' input[name=tgtNode]').val(); + var srcLog = $('#' + newTabId + ' input[name=srcLog]').val(); + + var chkBoxes = $("#" + newTabId + " input[type='checkbox']:checked"); + var optStr = '-s;' + srcLog + ';'; + var opt; + for ( var i = 0; i < chkBoxes.length; i++) { + opt = chkBoxes.eq(i).attr('name'); + optStr += '-' + opt; + + // If it is the retrieve log + if (opt == 't') { + // Append log destination + optStr += ';' + $('#' + newTabId + ' input[name=tgtLog]').val(); + } + + // If it is set options + if (opt == 'o') { + // Append options + optStr += ';' + $('#' + newTabId + ' textarea[name=logOpt]').val(); + } + + // Append ; to end of string + if (i < (chkBoxes.length - 1)) { + optStr += ';'; + } + } + + // If a value is given for every input + if (ready) { + // Do not disable all inputs + //var inputs = $('#' + newTabId + ' input'); + //inputs.attr('disabled', 'disabled'); + + /** + * (1) Retrieve, clear, or set options for event logs + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'reventlog', + tgt : tgts, + args : optStr, + msg : 'out=' + statBarId + ';cmd=reventlog;tgt=' + tgts + }, + + success : function(data) { + data = decodeRsp(data); + updateStatusBar(data); + } + }); + + // Create loader + $('#' + statBarId).find('div').append(createLoader()); + $('#' + statBarId).show(); + + // Do not disable run button + //$(this).attr('disabled', 'true'); + } else { + // Show warning message + var warn = createWarnBar(errMsg); + warn.prependTo($(this).parent().parent()); + } + }); + logForm.append(runBtn); + + // Add clone tab + tab.add(newTabId, 'Logs', logForm, true); + } + + tab.select(newTabId); +}; diff --git a/xCAT-UI/js/custom/zvmUtils.js b/xCAT-UI/js/custom/zvmUtils.js index 3ff044834..8af844457 100644 --- a/xCAT-UI/js/custom/zvmUtils.js +++ b/xCAT-UI/js/custom/zvmUtils.js @@ -1,8140 +1,8345 @@ -/*"use strict"; */ -/** - * Global variables - */ -var diskDatatable; // zVM datatable containing disks -var zfcpDatatable; // zVM datatable containing zFCP devices -var networkDatatable; // zVM datatable containing networks -var builtInXCAT = 1; // 1 means xCAT shipped with zVM -var zhcpQueryCountForDisks = 0; -var zhcpQueryCountForZfcps = 0; -var zhcpQueryCountForNetworks = 0; -var selectedNetworkHash; // Network details for each network - -/** - * Get the disk datatable - * - * @return Data table object - */ -function getDiskDataTable() { - return diskDatatable; -} - -/** - * Set the disk datatable - * - * @param table Data table object - */ -function setDiskDataTable(table) { - diskDatatable = table; -} - -/** - * Get the zFCP datatable - * - * @return Data table object - */ -function getZfcpDataTable() { - return zfcpDatatable; -} - -/** - * Set the zFCP datatable - * - * @param table Data table object - */ -function setZfcpDataTable(table) { - zfcpDatatable = table; -} - -/** - * Get the network datatable - * - * @return Data table object - */ -function getNetworkDataTable() { - return networkDatatable; -} - -/** - * Set the network datatable - * - * @param table Data table object - */ -function setNetworkDataTable(table) { - networkDatatable = table; -} - -/** - * Get the selectedNetworkHash datatable - * - * @return selectedNetworkHash two dimensional hash table object - */ -function getselectedNetworkHash() { - return selectedNetworkHash; -} - -/** - * Set the selectedNetworkHash two dimensional hash table - * - * @param table selectedNetworkHash object - */ -function setselectedNetworkHash(table) { - selectedNetworkHash = table; -} - -/** - * Display hcp node pool lookup finished - */ -function displayNodeHcpFinished(count){ - var infoBar = getNodesTabInfoBar(); - if (infoBar !== null) { - if (count <= 0) { - infoBar.append(" Done."); - }else { - infoBar.append(" ."); - } - } -} - -/** - * Load HCP specific info - * - * @param data Data from HTTP request - */ -function loadHcpInfo(data) { - var args = data.msg.split(';'); - var findingPools = 0; - var findingPoolsCount = 0; - - // Get group - var group = args[0].replace('group=', ''); - // Get hardware control point - var hcp = args[1].replace('hcp=', ''); - - // Get user directory entry - var userEntry = data.rsp; - if (!userEntry.length) - return; - - // Get Nodes info bar - var nodeInfoBar = getNodesTabInfoBar(); - //nodeInfoBar.append("\nEntering loadHcpInfo Load...\n"); - - if (userEntry[0].indexOf('Failed') < 0) { - if (hcp) { - // If there is no cookie for the disk pool names - if (!$.cookie('xcat_' + hcp + 'diskpools') || $.cookie('xcat_' + hcp + 'diskpools') === null) { - if (nodeInfoBar !== null) { - nodeInfoBar.append("
                          Finding pools and networks..."); - findingPools = 1; - findingPoolsCount++; - } - // Get disk pools - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcp, - args : '--diskpoolnames', - msg : hcp - }, - - success : setDiskPoolCookies, - complete : function() { - if (nodeInfoBar !== null) { - findingPoolsCount--; - displayNodeHcpFinished(findingPoolsCount); - } - } - }); - } - - // If there is no cookie for the zFCP pool names - if (!$.cookie('xcat_' + hcp + 'zfcppools') || $.cookie('xcat_' + hcp + 'zfcppools') === null) { - - if (nodeInfoBar !== null) { - if (findingPools = 0) { - nodeInfoBar.append("
                          Finding pools and networks..."); - } - findingPools = 1; - findingPoolsCount++; - } - // Get fcp pools - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcp, - args : '--zfcppoolnames', - msg : hcp - }, - - success : setZfcpPoolCookies, - complete : function() { - if (nodeInfoBar !== null) { - findingPoolsCount--; - displayNodeHcpFinished(findingPoolsCount); - } - } - }); - } - - // If there is no cookie for the network names - if (!$.cookie('xcat_' + hcp + 'networks') || $.cookie('xcat_' + hcp + 'networks') === null) { - - if (nodeInfoBar !== null) { - if (findingPools = 0) { - nodeInfoBar.append("
                          Finding pools and networks..."); - } - findingPools = 1; - findingPoolsCount++; - } - // Get network names - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcp, - args : '--getnetworknames', - msg : hcp - }, - - success : setNetworkCookies, - complete : function() { - if (nodeInfoBar !== null) { - findingPoolsCount--; - displayNodeHcpFinished(findingPoolsCount); - } - } - }); - } - } // End of if (hcp) - } else { - // Create warning dialog - var warning = createWarnBar('z/VM SMAPI is not responding to ' + hcp + '. SMAPI may need to be reset. '+userEntry[0]); - var warnDialog = $('
                          ').append(warning); - - // Open dialog - warnDialog.dialog({ - title:'Warning', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function() { - $(this).dialog("close"); - } - } - }); - } -} - -/** - * Load user entry of a given node - * - * @param data Data from HTTP request - */ -function loadUserEntry(data) { - var args = data.msg.split(';'); - - // Get tab ID - var ueDivId = args[0].replace('out=', ''); - // Get node - var node = args[1].replace('node=', ''); - // Get user directory entry - var userEntry = data.rsp[0].split(node + ':'); - - // Remove loader - $('#' + node + 'TabLoader').remove(); - - var toggleLinkId = node + 'ToggleLink'; - $('#' + toggleLinkId).click(function() { - // Get text within this link - var lnkText = $(this).text(); - - // Toggle user entry division - $('#' + node + 'UserEntry').toggle(); - // Toggle inventory division - $('#' + node + 'Inventory').toggle(); - - // Change text - if (lnkText == 'Show directory entry') { - $(this).text('Show inventory'); - } else { - $(this).text('Show directory entry'); - } - }); - - // Put user entry into a list - var fieldSet = $('
                          '); - var legend = $('Directory Entry'); - fieldSet.append(legend); - - var txtArea = $(''); - for ( var i = 1; i < userEntry.length; i++) { - userEntry[i] = jQuery.trim(userEntry[i]); - txtArea.append(userEntry[i]); - - if (i < userEntry.length) { - txtArea.append('\n'); - } - } - txtArea.attr('readonly', 'readonly'); - fieldSet.append(txtArea); - - /** - * Edit user entry - */ - txtArea.bind('dblclick', function(event) { - txtArea.attr('readonly', ''); - txtArea.css( { - 'border-width' : '1px' - }); - - saveBtn.show(); - cancelBtn.show(); - saveBtn.css('display', 'inline-table'); - cancelBtn.css('display', 'inline-table'); - }); - - /** - * Save - */ - var saveBtn = createButton('Save').hide(); - saveBtn.bind('click', function(event) { - // Show loader - $('#' + node + 'StatusBarLoader').show(); - $('#' + node + 'StatusBar').show(); - - // Replace user entry - var newUserEntry = jQuery.trim(txtArea.val()) + '\n'; - - // Replace user entry - $.ajax( { - url : 'lib/zCmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--replacevs', - att : newUserEntry, - msg : node - }, - - success : updateZNodeStatus - }); - - // Increment node process and save it in a cookie - incrementNodeProcess(node); - - txtArea.attr('readonly', 'readonly'); - txtArea.css( { - 'border-width' : '0px' - }); - - // Disable save button - $(this).hide(); - cancelBtn.hide(); - }); - - /** - * Cancel - */ - var cancelBtn = createButton('Cancel').hide(); - cancelBtn.bind('click', function(event) { - txtArea.attr('readonly', 'readonly'); - txtArea.css( { - 'border-width' : '0px' - }); - - cancelBtn.hide(); - saveBtn.hide(); - }); - - // Create info bar - var infoBar = createInfoBar('Double click on the directory entry to edit it.'); - - // Append user entry into division - $('#' + ueDivId).append(infoBar); - $('#' + ueDivId).append(fieldSet); - $('#' + ueDivId).append(saveBtn); - $('#' + ueDivId).append(cancelBtn); -} - -/** - * Increment number of processes running against a node - * - * @param node Node to increment running processes - */ -function incrementNodeProcess(node) { - // Get current processes - var procs = $.cookie('xcat_' + node + 'processes'); - if (procs) { - // One more process - procs = parseInt(procs) + 1; - $.cookie('xcat_' + node + 'processes', procs); - } else { - $.cookie('xcat_' + node + 'processes', 1); - } -} - -/** - * Update provision new node status - * - * @param data Data returned from HTTP request - */ -function updateZProvisionNewStatus(data) { - // Parse ajax response - var rsp = data.rsp; - var args = data.msg.split(';'); - var lastCmd = args[0].replace('cmd=', ''); - var out2Id = args[1].replace('out=', ''); - if (typeof console == "object"){ - console.log("Entering updateZProvisionNewStatus. Last command:<"+lastCmd+"> All args:<"+args+">"); - } - // IDs for status bar, tab, and loader - var statBarId = 'zProvisionStatBar' + out2Id; - var tabId = 'zvmProvisionTab' + out2Id; - var loaderId = 'zProvisionLoader' + out2Id; - - var node = $('#' + tabId + ' input[name=nodeName]').val(); - - /** - * (2) Create user entry - */ - if (lastCmd == 'nodeadd') { - if (rsp.length) { - $('#' + loaderId).hide(); - $('#' + statBarId).find('div').append('
                          (Error) Failed to create node definition
                          '); - } else { - $('#' + statBarId).find('div').append('
                          Node definition created for ' + node + '
                          '); - - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + statBarId).find('div').append(prg); - - // Create user entry - var userEntry = $('#' + tabId + ' textarea').val(); - $.ajax( { - url : 'lib/zCmd.php', - dataType : 'json', - data : { - cmd : 'mkvm', - tgt : node, - args : '', - att : userEntry, - msg : 'cmd=mkvm;out=' + out2Id - }, - - success : updateZProvisionNewStatus - }); - } - } - - /** - * (3) Update /etc/hosts - */ - else if (lastCmd == 'mkvm') { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + statBarId).find('div').append(prg); - - // If there was an error, quit - if (containErrors(prg.html())) { - $('#' + loaderId).hide(); - } else { - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'makehosts', - tgt : '', - args : '', - msg : 'cmd=makehosts;out=' + out2Id - }, - - success : updateZProvisionNewStatus - }); - } - } - - /** - * If sourceforge xcat: (4) Update DNS - */ - else if ((lastCmd == 'makehosts') && (builtInXCAT == 0)) { - // If there was an error, quit - if (rsp.length) { - $('#' + loaderId).hide(); - $('#' + statBarId).find('div').append('
                          (Error) Failed to update /etc/hosts
                          '); - } else { - $('#' + statBarId).find('div').append('
                          /etc/hosts updated
                          '); - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'makedns', - tgt : '', - args : '', - msg : 'cmd=makedns;out=' + out2Id - }, - - success : updateZProvisionNewStatus - }); - } - } - /** - * If built in zVM xcat and last command was makehosts or - * If sourceforge xCAT and lastCmd was makedns - * (5) Add disk - * - */ - else if (((lastCmd == 'makehosts') && (builtInXCAT == 1)) || - ((lastCmd == 'makedns') && (builtInXCAT == 0))) { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + statBarId).find('div').append(prg); - - // If there was an error, quit - if (rsp.length) { - $('#' + loaderId).hide(); - if (builtInXCAT == 1) { - $('#' + statBarId).find('div').append('
                          (Error) Failed to update /etc/hosts
                          '); - } else { - $('#' + statBarId).find('div').append('
                          (Error) Failed to makedns
                          '); - } - } else { - if (builtInXCAT == 1) { - $('#' + statBarId).find('div').append('
                          /etc/hosts updated
                          '); - } else { - $('#' + statBarId).find('div').append('
                          makedns updated
                          '); - } - - // Set cookie for number of disks - var diskRows = $('#' + tabId + ' table:eq(0):visible tbody tr'); - $.cookie('xcat_disks2add' + out2Id, diskRows.length, {path: '/xcat', secure:true }); - if (diskRows.length > 0) { - for (var i = 0; i < diskRows.length; i++) { - var diskArgs = diskRows.eq(i).find('td'); - var type = diskArgs.eq(1).find('select').val(); - var address = diskArgs.eq(2).find('input').val(); - var size = diskArgs.eq(3).find('input').val(); - var mode = diskArgs.eq(4).find('select').val(); - var pool = diskArgs.eq(5).find('select').val(); - var password = diskArgs.eq(6).find('input').val(); - - // Create ajax arguments - var args = ''; - if (type == '3390') { - args = '--add' + type + ';' + pool + ';' + address - + ';' + size + ';' + mode + ';' + password + ';' - + password + ';' + password; - } else if (type == '9336') { - args = '--add' + type + ';' + pool + ';' + address + ';' - + size + ';' + mode + ';' + password + ';' - + password + ';' + password; - } - - // Attach disk to node - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : args, - msg : 'cmd=chvm-disk;out=' + out2Id - }, - - success : updateZProvisionNewStatus - }); - } - } - - // Set cookie for number of zFCP devices - var zfcpRows = $('#' + tabId + ' table:eq(1):visible tbody tr'); - $.cookie('xcat_zfcp2add' + out2Id, zfcpRows.length, {path: '/xcat', secure:true }); - if (zfcpRows.length > 0) { - for ( var i = 0; i < zfcpRows.length; i++) { - var diskArgs = zfcpRows.eq(i).find('td'); - var address = diskArgs.eq(1).find('input').val(); - var size = diskArgs.eq(2).find('input').val(); - var pool = diskArgs.eq(3).find('select').val(); - var tag = diskArgs.eq(4).find('input').val(); - var portName = diskArgs.eq(5).find('input').val(); - var unitNo = diskArgs.eq(6).find('input').val(); - - // This is either true or false - var loaddev = diskArgs.eq(7).find('input').attr('checked'); - if (loaddev) { - loaddev = "1"; - } else { - loaddev = "0"; - } - - // Create ajax arguments - var args = '--addzfcp;' + pool + ';' + address + ';' + loaddev + ';' + size; - if (tag && tag != "null") { - args += ';' + tag; - } else { - args += ';'; - } if (portName && tag != "null") { - args += ';' + portName; - } else { - args += ';'; - } if (unitNo && tag != "null") { - args += ';' + unitNo; - } else { - args += ';'; - } - - // Attach zFCP device to node - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : args, - msg : 'cmd=chvm-zfcp;out=' + out2Id - }, - - success : updateZProvisionNewStatus - }); - } - } - - // Done if no disks to add - if (diskRows.length < 1 && zfcpRows.length < 1) { - $('#' + statBarId).find('div').append('
                          No disks found to provison, finished.
                          '); - $('#' + loaderId).hide(); - } - } - } - - /** - * (6) Set operating system for given node - */ - else if (lastCmd == 'chvm-disk' || lastCmd == 'chvm-zfcp') { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + statBarId).find('div').append(prg); - - // If there was an error, quit - if (containErrors(prg.html())) { - $('#' + loaderId).hide(); - } else { - // Set cookie for number of disks - // One less disk to add - var disks2add = $.cookie('xcat_disks2add' + out2Id); - if (lastCmd == 'chvm-disk') { - if (disks2add > 0) { - disks2add--; - $.cookie('xcat_disks2add' + out2Id, disks2add, {path: '/xcat', secure:true }); - } - } - - var zfcp2add = $.cookie('xcat_zfcp2add' + out2Id); - if (lastCmd == 'chvm-zfcp') { - if (zfcp2add > 0) { - zfcp2add--; - $.cookie('xcat_zfcp2add' + out2Id, zfcp2add, {path: '/xcat', secure:true }); - } - } - - // Only set operating system if there are no more disks to add - if (zfcp2add < 1 && disks2add < 1) { - // If an operating system image is given - var osImage = $('#' + tabId + ' select[name=os]:visible').val(); - if (osImage) { - // Get operating system, architecture, provision method, and profile - var tmp = osImage.split('-'); - var os = tmp[0]; - var arch = tmp[1]; - var profile = tmp[3]; - - // If the last disk is added - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodeadd', - tgt : '', - args : node + ';noderes.netboot=zvm;nodetype.os=' - + os + ';nodetype.arch=' + arch - + ';nodetype.profile=' + profile, - msg : 'cmd=noderes;out=' + out2Id - }, - - success : updateZProvisionNewStatus - }); - } else { - $('#' + loaderId).hide(); - } - } - } - } - - /** - * (7) If sourceforge xCAT Update DHCP - */ - else if ((lastCmd == 'noderes') && (builtInXCAT == 0)) { - // If there was an error, do not continue - if (rsp.length) { - $('#' + loaderId).hide(); - $('#' + statBarId).find('div').append('
                          (Error) Failed to set operating system
                          '); - } else { - $('#' + statBarId).find('div').append('
                          Operating system for ' + node + ' set
                          '); - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'makedhcp', - tgt : '', - args : '-a', - msg : 'cmd=makedhcp;out=' + out2Id - }, - - success : updateZProvisionNewStatus - }); - } - } - - /** - * (8) Prepare node for boot - */ - else if (((lastCmd == 'noderes') && (builtInXCAT == 1)) || - ((lastCmd == 'makedhcp') && (builtInXCAT == 0))) { - // If there was an error, do not continue - if (rsp.length) { - $('#' + loaderId).hide(); - if (builtInXCAT == 1) { - $('#' + statBarId).find('div').append('
                          (Error) Failed to set operating system
                          '); - } else { - $('#' + statBarId).find('div').append('
                          (Error) Failed to make dhcp
                          '); - } - } else { - if (builtInXCAT == 1) { - $('#' + statBarId).find('div').append('
                          Operating system for ' + node + ' set
                          '); - } else { - $('#' + statBarId).find('div').append('
                          DHCP for ' + node + ' set
                          '); - } - - // Prepare node for boot - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodeset', - tgt : node, - args : 'install', - msg : 'cmd=nodeset;out=' + out2Id - }, - - success : updateZProvisionNewStatus - }); - } - } - - /** - * (9) Boot node to network - */ - else if (lastCmd == 'nodeset') { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + statBarId).find('div').append(prg); - - // If there was an error - // Do not continue - if (containErrors(prg.html())) { - $('#' + loaderId).hide(); - } else { - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'rnetboot', - tgt : node, - args : 'ipl=000C', - msg : 'cmd=rnetboot;out=' + out2Id - }, - - success : updateZProvisionNewStatus - }); - } - } - - /** - * (10) Done - */ - else if (lastCmd == 'rnetboot') { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + statBarId).find('div').append(prg); - if (prg.html().indexOf('Error') < 0) { - $('#' + statBarId).find('div').append('
                          Open a VNC viewer to see the installation progress.  It might take a couple of minutes before you can connect.
                          '); - } - - // Hide loader - $('#' + loaderId).hide(); - } -} - -/** - * Update the provision existing node status - * - * @param data Data returned from HTTP request - */ -function updateZProvisionExistingStatus(data) { - // Get ajax response - var rsp = data.rsp; - var args = data.msg.split(';'); - - // Get command invoked - var cmd = args[0].replace('cmd=', ''); - // Get provision tab instance - var inst = args[1].replace('out=', ''); - if (typeof console == "object"){ - console.log("Entering updateZProvisionExistingStatus. Last command:<"+cmd+"> All args:<"+args+">"); - } - - // Get provision tab and status bar ID - var statBarId = 'zProvisionStatBar' + inst; - var tabId = 'zvmProvisionTab' + inst; - - /** - * (2) Prepare node for boot - */ - if (cmd == 'nodeadd') { - // Get operating system - var bootMethod = $('#' + tabId + ' select[name=bootMethod]').val(); - - // Get nodes that were checked - var dTableId = 'zNodesDatatable' + inst; - var tgts = getNodesChecked(dTableId); - - // Prepare node for boot - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodeset', - tgt : tgts, - args : bootMethod, - msg : 'cmd=nodeset;out=' + inst - }, - - success : updateZProvisionExistingStatus - }); - } - - /** - * (3) Boot node from network - */ - else if (cmd == 'nodeset') { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + statBarId).find('div').append(prg); - - // If there was an error, do not continue - if (containErrors(prg.html())) { - var loaderId = 'zProvisionLoader' + inst; - $('#' + loaderId).remove(); - return; - } - - // Get nodes that were checked - var dTableId = 'zNodesDatatable' + inst; - var tgts = getNodesChecked(dTableId); - - // Boot node from network - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'rnetboot', - tgt : tgts, - args : 'ipl=000C', - msg : 'cmd=rnetboot;out=' + inst - }, - - success : updateZProvisionExistingStatus - }); - } - - /** - * (4) Done - */ - else if (cmd == 'rnetboot') { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + statBarId).find('div').append(prg); - if (prg.html().indexOf('Error') < 0) { - $('#' + statBarId).find('div').append('
                          Open a VNC viewer to see the installation progress.  It might take a couple of minutes before you can connect.
                          '); - } - - var loaderId = 'zProvisionLoader' + inst; - $('#' + loaderId).remove(); - } -} - -/** - * Update zVM node status - * - * @param data Data returned from HTTP request - */ -function updateZNodeStatus(data) { - var node = data.msg; - var rsp = data.rsp; - - // Get cookie for number processes performed against this node - var actions = $.cookie('xcat_' + node + 'processes'); - // One less process - actions = actions - 1; - $.cookie('xcat_' + node + 'processes', actions, {path: '/xcat', secure:true }); - - if (actions < 1) { - // Hide loader when there are no more processes - var statusBarLoaderId = node + 'StatusBarLoader'; - $('#' + statusBarLoaderId).hide(); - } - - var statBarId = node + 'StatusBar'; - - // Write ajax response to status bar - var prg = writeRsp(rsp, node + ': '); - $('#' + statBarId).find('div').append(prg); -} - -/** - * Update clone status - * - * @param data Data returned from HTTP request - */ -function updateZCloneStatus(data) { - // Get ajax response - var rsp = data.rsp; - var args = data.msg.split(';'); - var cmd = args[0].replace('cmd=', ''); - - // Get provision instance - var inst = args[1].replace('inst=', ''); - // Get output division ID - var out2Id = args[2].replace('out=', ''); - - /** - * (2) Update /etc/hosts - */ - if (cmd == 'nodeadd') { - var node = args[3].replace('node=', ''); - - // If there was an error, do not continue - if (rsp.length) { - $('#' + out2Id).find('img').hide(); - $('#' + out2Id).find('div').append('
                          (Error) Failed to create node definition
                          '); - } else { - $('#' + out2Id).find('div').append('
                          Node definition created for ' + node + '
                          '); - - // If last node definition was created - var tmp = inst.split('/'); - if (tmp[0] == tmp[1]) { - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'makehosts', - tgt : '', - args : '', - msg : 'cmd=makehosts;inst=' + inst + ';out=' + out2Id - }, - - success : updateZCloneStatus - }); - } - } - } - - /** - * (3a) Update DNS if source forge xCAT then do makedns - */ - else if ((cmd == 'makehosts') && (builtInXCAT == 0)) { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + out2Id).find('div').append(prg); - - // If there was an error, do not continue - if (rsp.length) { - $('#' + out2Id).find('img').hide(); - $('#' + out2Id).find('div').append('
                          (Error) Failed to update /etc/hosts
                          '); - } else { - $('#' + out2Id).find('div').append('
                          /etc/hosts updated
                          '); - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'makedns', - tgt : '', - args : '', - msg : 'cmd=makedns;inst=' + inst + ';out=' + out2Id - }, - - success : updateZCloneStatus - }); - } - } - - /** - * (3b) Update DNS for built in xCAT and clone - * Just clone for sourceforge xCAT - */ - else if (((cmd == 'makehosts') && (builtInXCAT == 1)) || - ((cmd == 'makedns') && (builtInXCAT == 0))) { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + out2Id).find('div').append(prg); - - // If there was an error, do not continue - if (rsp.length) { - $('#' + out2Id).find('img').hide(); - if (builtInXCAT == 1) { - $('#' + out2Id).find('div').append('
                          (Error) Failed to update /etc/hosts
                          '); - } else { - $('#' + out2Id).find('div').append('
                          (Error) Failed to makedns
                          '); - } - } - // Get clone tab - var tabId = out2Id.replace('CloneStatusBar', 'CloneTab'); - - // If a node range is given - var tgtNodeRange = $('#' + tabId + ' input[name=tgtNode]').val(); - var tgtNodes = ''; - if (tgtNodeRange.indexOf('-') > -1) { - var tmp = tgtNodeRange.split('-'); - - // Get node base name - var nodeBase = tmp[0].match(/[a-zA-Z]+/); - // Get the starting index - var nodeStart = parseInt(tmp[0].match(/\d+/)); - // Get the ending index - var nodeEnd = parseInt(tmp[1].match(/\d+/)); - for ( var i = nodeStart; i <= nodeEnd; i++) { - // Do not append comma for last node - if (i == nodeEnd) { - tgtNodes += nodeBase + i.toString(); - } else { - tgtNodes += nodeBase + i.toString() + ','; - } - } - } else { - tgtNodes = tgtNodeRange; - } - - // Get other inputs - var srcNode = $('#' + tabId + ' input[name=srcNode]').val(); - hcp = $('#' + tabId + ' input[name=newHcp]').val(); - var group = $('#' + tabId + ' input[name=newGroup]').val(); - var diskPool = $('#' + tabId + ' input[name=diskPool]').val(); - var diskPw = $('#' + tabId + ' input[name=diskPw]').val(); - if (!diskPw) { - diskPw = ''; - } - - // Clone - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'mkvm', - tgt : tgtNodes, - args : srcNode + ';pool=' + diskPool + ';pw=' + diskPw, - msg : 'cmd=mkvm;inst=' + inst + ';out=' + out2Id - }, - error: function(jqXHR, textStatus) { - $('#' + out2Id).find('div').append('
                          (Error) Failed in clone call with ' + textStatus + '
                          '); - }, - success : updateZCloneStatus - }); - } - - /** - * (5) Done - */ - else if (cmd == 'mkvm') { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + out2Id).find('div').append(prg); - - // Hide loader - $('#' + out2Id).find('img').hide(); - } -} - -/** - * Get zVM resources - * - * @param data Data from HTTP request - */ -function getZResources(data) { - var tabId = 'zvmResourceTab'; - var info = createInfoBar('Manage storage and networks'); - $('#' + tabId).append(info); - - // Do not continue if there is no output - if (data.rsp.length) { - if (typeof console == "object"){ - console.log("Entering getZResources."); - } - // Push hardware control points into an array - var node, hcp; - var hcpHash = new Object(); - var hostnameHash = new Object(); - for (var i in data.rsp) { - node = data.rsp[i][0]; - hcp = data.rsp[i][1]; - // data will be coming in like "xcat xcat.endicott.ibm.com hosts.hostnames" - // or xcat zhcp.endicott.ibm.com zvm.hcp" - if (data.rsp[i][2]== "zvm.hcp") { - hcpHash[hcp] = 1; - } else { - if (hcp.length) { - hostnameHash[hcp] = node; - } - } - } - - // Create an array for hardware control points - var hcps = new Array(); - for (var key in hcpHash) { - // Get the short host name - //hcp = key.split('.')[0]; //old code - hcp = hostnameHash[key]; - if (typeof console == "object"){ - console.log("getZResources lookup for hostname "+key+" found nodename <"+hcp+">"); - } - if (jQuery.inArray(hcp, hcps) == -1) { - hcps.push(hcp); - } - } - - // Set hardware control point cookie - $.cookie('xcat_hcp', hcps, {path: '/xcat', secure:true }); - - // Delete loader - $('#' + tabId).find('img[src="images/loader.gif"]').remove(); - - // Create accordion panel for disk - var resourcesAccordion = $('
                          '); - var diskSection = $('
                          '); - var diskLnk = $('

                          Disks

                          ').click(function () { - // Do not load panel again if it is already loaded - if ($('#zvmDiskResource').children().length) { - return; - } - else - $('#zvmDiskResource').append(createLoader('')); - - // Resize accordion - $('#zvmResourceAccordion').accordion('resize'); - - // Create a array for hardware control points - var hcps = new Array(); - if ($.cookie('xcat_hcp').indexOf(',') > -1) { - hcps = $.cookie('xcat_hcp').split(','); - } else { - hcps.push($.cookie('xcat_hcp')); - } - - // Query the disk pools for each hcp - var panelId = 'zvmDiskResource'; - var info = $('#' + panelId).find('.ui-state-highlight'); - if (!info.length) { - info = createInfoBar("Querying "+hcps.length+" zhcp(s) for disk pools."); - $('#' + panelId).append(info); - } - zhcpQueryCountForDisks = hcps.length; - - for (var i in hcps) { - var itemcount = +i + 1; - info.append("
                          Querying disk pools from: "+hcps[i]+" ("+itemcount+" of "+hcps.length+")"); - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcps[i], - args : '--diskpoolnames', - msg : hcps[i] - }, - - success : getDiskPool - }); - zhcpQueryCountForDisks--; - } - }); - - // Create accordion panel for zFCP devices - var zfcpSection = $('
                          '); - var zfcpLnk = $('

                          zFCP

                          ').click(function () { - // Do not load panel again if it is already loaded - if ($('#zfcpResource').children().length) - return; - else - $('#zfcpResource').append(createLoader('')); - - // Resize accordion - $('#zvmResourceAccordion').accordion('resize'); - - // Create a array for hardware control points - var hcps = new Array(); - if ($.cookie('xcat_hcp').indexOf(',') > -1) { - hcps = $.cookie('xcat_hcp').split(','); - } else { - hcps.push($.cookie('xcat_hcp')); - - } - - // Query the fcp pools for each hcp - var panelId = 'zfcpResource'; - var info = $('#' + panelId).find('.ui-state-highlight'); - if (!info.length) { - info = createInfoBar("Querying "+hcps.length+" zhcp(s) for fcp pools."); - $('#' + panelId).append(info); - } - zhcpQueryCountForZfcps = hcps.length; - for (var i in hcps) { - // Gather fcp pools from hardware control points - var itemcount = +i + 1; - info.append("
                          Querying fcp pools from: "+hcps[i]+" ("+itemcount+" of "+hcps.length+")"); - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcps[i], - args : '--zfcppoolnames', - msg : hcps[i] - }, - - success : getZfcpPool - }); - zhcpQueryCountForZfcps--; - } - }); - - // Create accordion panel for network - var networkSection = $('
                          '); - var networkLnk = $('

                          Networks

                          ').click(function () { - // Do not load panel again if it is already loaded - if ($('#zvmNetworkResource').children().length) { - return; - } else { - $('#zvmNetworkResource').append(createLoader('')); - } - - // Resize accordion - $('#zvmResourceAccordion').accordion('resize'); - - // Create a array for hardware control points - var hcps = new Array(); - if ($.cookie('xcat_hcp').indexOf(',') > -1) { - hcps = $.cookie('xcat_hcp').split(','); - } else { - hcps.push($.cookie('xcat_hcp')); - - } - // Query the networks for each - var panelId = 'zvmNetworkResource'; - var info = $('#' + panelId).find('.ui-state-highlight'); - if (!info.length) { - info = createInfoBar("Querying "+hcps.length+" zhcp(s) for networks."); - $('#' + panelId).append(info); - } - zhcpQueryCountForNetworks = hcps.length; - for (var i in hcps) { - var itemcount = +i + 1; - info.append("
                          Querying networks from: "+hcps[i]+" ("+itemcount+" of "+hcps.length+")"); - $('#zvmResourceAccordion').accordion('resize'); - // Gather networks from hardware control points - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcps[i], - args : '--getnetworknames', - msg : hcps[i] - }, - - success : getNetwork - }); - zhcpQueryCountForNetworks--; - } - }); - - resourcesAccordion.append(diskLnk, diskSection, zfcpLnk, zfcpSection, networkLnk, networkSection); - - // Append accordion to tab - $('#' + tabId).append(resourcesAccordion); - resourcesAccordion.accordion(); - networkLnk.trigger('click'); - } -} - -/** - * Get node attributes from HTTP request data - * - * @param propNames Hash table of property names - * @param keys Property keys - * @param data Data from HTTP request - * @return Hash table of property values - */ -function getAttrs(keys, propNames, data) { - // Create hash table for property values - var attrs = new Object(); - - // Go through inventory and separate each property out - var curKey = null; // Current property key - var addLine; // Add a line to the current property? - for ( var i = 1; i < data.length; i++) { - addLine = true; - - // Loop through property keys - // Does this line contains one of the properties? - for ( var j = 0; j < keys.length; j++) { - // Find property name - if (data[i].indexOf(propNames[keys[j]]) > -1) { - attrs[keys[j]] = new Array(); - - // Get rid of property name in the line - data[i] = data[i].replace(propNames[keys[j]], ''); - // Trim the line - data[i] = jQuery.trim(data[i]); - - // Do not insert empty line - if (data[i].length > 0) { - attrs[keys[j]].push(data[i]); - } - - curKey = keys[j]; - addLine = false; // This line belongs to a property - } - } - - // Line does not contain a property - // Must belong to previous property - if (addLine && data[i].length > 1) { - data[i] = jQuery.trim(data[i]); - attrs[curKey].push(data[i]); - } - } - - return attrs; -} - -/** - * Create add processor dialog - * - * @param node Node to add processor to - */ -function openAddProcDialog(node) { - // Create form to add processor - var addProcForm = $('
                          '); - // Create info bar - var info = createInfoBar('Add a temporary processor to this virtual server.'); - addProcForm.append(info); - addProcForm.append('
                          '); - addProcForm.append('
                          '); - - // Create drop down for processor type - var procType = $('
                          '); - procType.append(''); - var typeSelect = $(''); - typeSelect.append('' - + '' - + '' - + '' - ); - procType.append(typeSelect); - addProcForm.append(procType); - - // Generate tooltips - addProcForm.find('div input[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 processor - addProcForm.dialog({ - title:'Add processor', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - // Get inputs - var node = $(this).find('input[name=procNode]').val(); - var address = $(this).find('input[name=procAddress]').val(); - var type = $(this).find('select[name=procType]').val(); - - // If inputs are not complete, show warning message - if (!node || !address || !type) { - var warn = createWarnBar('Please provide a value for each missing field.'); - warn.prependTo($(this)); - } else { - // Add processor - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--addprocessoractive;' + address + ';' + type, - msg : node - }, - - success : updateZNodeStatus - }); - - // Increment node process - incrementNodeProcess(node); - - // Show loader - var statusId = node + 'StatusBar'; - var statusBarLoaderId = node + 'StatusBarLoader'; - $('#' + statusBarLoaderId).show(); - $('#' + statusId).show(); - - // Close dialog - $(this).dialog( "close" ); - } - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Create add disk dialog - * - * @param node Node to add disk to - * @param hcp Hardware control point of node - */ -function openAddDiskDialog(node, hcp) { - // Get list of disk pools - var cookie = $.cookie('xcat_' + hcp + 'diskpools'); - var pools = new Array(); - if (cookie) { - pools = cookie.split(','); - } - - // Create form to add disk - var addDiskForm = $('
                          '); - // Create info bar - var info = createInfoBar('Add a ECKD|3390 or FBA|9336 disk to this virtual server.'); - addDiskForm.append(info); - addDiskForm.append('
                          '); - addDiskForm.append('
                          '); - addDiskForm.append('
                          '); - addDiskForm.append('
                          '); - - // Create drop down for disk pool - var diskPool = $('
                          '); - diskPool.append(''); - var poolSelect = $(''); - for ( var i = 0; i < pools.length; i++) { - if( !pools[i] || 0 === pools[i].length) continue; - poolSelect.append(''); - } - diskPool.append(poolSelect); - addDiskForm.append(diskPool); - - // Create drop down for disk mode - var diskMode = $('
                          '); - diskMode.append(''); - var modeSelect = $(''); - modeSelect.append('' - + '' - + '' - + '' - + '' - + '' - + '' - ); - diskMode.append(modeSelect); - addDiskForm.append(diskMode); - - addDiskForm.append('
                          '); - - // Generate tooltips - addDiskForm.find('div input[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 disk - addDiskForm.dialog({ - title:'Add disk', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - // Get inputs - var node = $(this).find('input[name=diskNode]').val(); - var type = $(this).find('select[name=diskType]').val(); - var address = $(this).find('input[name=diskAddress]').val(); - var size = $(this).find('input[name=diskSize]').val(); - var pool = $(this).find('select[name=diskPool]').val(); - var mode = $(this).find('select[name=diskMode]').val(); - var password = $(this).find('input[name=diskPassword]').val(); - - // If inputs are not complete, show warning message - if (!node || !type || !address || !size || !pool || !mode) { - var warn = createWarnBar('Please provide a value for each missing field.'); - warn.prependTo($(this)); - } else { - // Add disk - if (type == '3390') { - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--add3390;' + pool + ';' + address + ';' + size - + ';' + mode + ';' + password + ';' + password + ';' + password, - msg : node - }, - - success : updateZNodeStatus - }); - - // Increment node process - incrementNodeProcess(node); - - // Show loader - var statusId = node + 'StatusBar'; - var statusBarLoaderId = node + 'StatusBarLoader'; - $('#' + statusBarLoaderId).show(); - $('#' + statusId).show(); - } else if (type == '9336') { - // Default block size for FBA volumes = 512 - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--add9336;' + pool + ';' + address + ';' + size - + ';' + mode + ';' + password + ';' + password + ';' + password, - msg : node - }, - - success : updateZNodeStatus - }); - - // Increment node process - incrementNodeProcess(node); - - // Show loader - var statusId = node + 'StatusBar'; - var statusBarLoaderId = node + 'StatusBarLoader'; - $('#' + statusBarLoaderId).show(); - $('#' + statusId).show(); - } - - // Close dialog - $(this).dialog( "close" ); - } // End of else - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Create add zFCP device dialog - * - * @param node Node to add disk to - * @param hcp Hardware control point of node - * @param zvm The z/VM system of node - */ -function openAddZfcpDialog(node, hcp, zvm) { - // Get list of disk pools - var cookie = $.cookie('xcat_' + hcp + 'zfcppools'); - var pools = new Array(); - if (cookie) { - pools = cookie.split(','); - } - - // Create form to add disk - var addZfcpForm = $('
                          '); - // Create info bar - var info = createInfoBar('Add a SCSI|FCP disk to this virtual server.'); - addZfcpForm.append(info); - addZfcpForm.append('
                          '); - addZfcpForm.append('
                          '); - addZfcpForm.append('
                          '); - addZfcpForm.append('
                          '); - - // Create drop down for disk pool - var diskPool = $('
                          '); - diskPool.append(''); - var poolSelect = $(''); - for ( var i = 0; i < pools.length; i++) { - if( !pools[i] || 0 === pools[i].length) continue; - poolSelect.append(''); - } - diskPool.append(poolSelect); - addZfcpForm.append(diskPool); - - // Tag to identify where device will be used - addZfcpForm.append('
                          '); - - // Create advanced link to set advanced zFCP properties - var advancedLnk = $(''); - addZfcpForm.append(advancedLnk); - var advanced = $('
                          ').hide(); - addZfcpForm.append(advanced); - - var portName = $('
                          '); - var unitNo = $('
                          '); - advanced.append(portName, unitNo); - - // Toggle port name and unit number when clicking on advanced link - advancedLnk.click(function() { - advanced.toggle(); - }); - - // Generate tooltips - addZfcpForm.find('div input[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 disk - addZfcpForm.dialog({ - title:'Add zFCP device', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - // Get inputs - var node = $(this).find('input[name=diskNode]').val(); - var address = $(this).find('input[name=diskAddress]').val(); - var loaddev = $(this).find('input[name=diskLoaddev]'); - var size = $(this).find('input[name=diskSize]').val(); - var pool = $(this).find('select[name=diskPool]').val(); - var tag = $(this).find('input[name=diskTag]').val(); - var portName = $(this).find('input[name=diskPortName]').val(); - var unitNo = $(this).find('input[name=diskUnitNo]').val(); - - // If inputs are not complete, show warning message - if (!node || !address || !size || !pool) { - var warn = createWarnBar('Please provide a value for each missing field.'); - warn.prependTo($(this)); - } else { - if (loaddev.attr('checked')) { - loaddev = 1; - } else { - loaddev = 0; - } - - var args = '--addzfcp||' + pool + '||' + address + '||' + loaddev + '||' + size; - - if (tag && tag != "null") { - args += '||' + tag; - } else { - args += '|| ""'; - } - - if ((portName && portName != "null") && (unitNo && unitNo != "null")) { - args += '||' + portName + '||' + unitNo; - } - - // Add zFCP device - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : args, - msg : node - }, - - success : updateZNodeStatus - }); - - // Increment node process - incrementNodeProcess(node); - - // Show loader - var statusId = node + 'StatusBar'; - var statusBarLoaderId = node + 'StatusBarLoader'; - $('#' + statusBarLoaderId).show(); - $('#' + statusId).show(); - - // Close dialog - $(this).dialog( "close" ); - } - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Create dedicate device dialog - * - * @param node Node to dedicate device to - * @param hcp Hardware control point of node - */ -function openDedicateDeviceDialog(node, hcp) { - // Create form to add disk - var dedicateForm = $('
                          '); - // Create info bar - var info = createInfoBar('Add a dedicated device to the configuration'); - dedicateForm.append(info); - - dedicateForm.append('
                          '); - dedicateForm.append('
                          '); - dedicateForm.append('
                          '); - dedicateForm.append('
                          '); - - // Generate tooltips - dedicateForm.find('div input[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 dedicated device - dedicateForm.dialog({ - title:'Add dedicated device', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - // Get inputs - var node = $(this).find('input[name=diskNode]').val(); - var vAddress = $(this).find('input[name=virtualAddress]').val(); - var rAddress = $(this).find('input[name=realAddress]').val() - var mode = $(this).find('select[name=mode]').val(); - - // If inputs are not complete, show warning message - if (!node || !vAddress || !rAddress || !mode) { - var warn = createWarnBar('Please provide a value for each missing field.'); - warn.prependTo($(this)); - } else { - var args = '--dedicatedevice;' + vAddress + ';' + rAddress + ';' + mode; - - // Add zFCP device - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : args, - msg : node - }, - - success : updateZNodeStatus - }); - - // Increment node process - incrementNodeProcess(node); - - // Show loader - var statusId = node + 'StatusBar'; - var statusBarLoaderId = node + 'StatusBarLoader'; - $('#' + statusBarLoaderId).show(); - $('#' + statusId).show(); - - // Close dialog - $(this).dialog( "close" ); - } - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Create add ECKD to system dialog - * - * @param hcp Hardware control point of node - */ -function openAddEckd2SystemDialog(hcp) { - var dialogId = 'zvmAddEckd2System'; - - // Create form to add disk - var addE2SForm = $('
                          '); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - - // Append options for hardware control points - //systemSelect.append($('')); - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - - // Create info bar - var info = createInfoBar('Dynamically add an ECKD disk to a running z/VM system.'); - addE2SForm.append(info); - - addE2SForm.append(system); - addE2SForm.append('
                          '); - - // Generate tooltips - addE2SForm.find('div input[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 disk - addE2SForm.dialog({ - title:'Add ECKD to system', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 420, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - var system = $(this).find('select[name=system]').val(); - var devnum = $(this).find('input[name=devNum]').val(); - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'input[name=devNum]'); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - if (!ready) { - // Show warning message - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : system, - args : "--addeckd;" + devnum, - msg : dialogId - }, - - success : updateResourceDialog - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Create add Volume to system dialog - * - * @param hcp Hardware control point of node - */ -function openAddVolume2SystemDialog(hcp) { - var dialogId = 'zvmAddVolume2System'; - - // Create form to add volume - var addV2SForm = $('
                          '); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - - // Append options for hardware control points - //systemSelect.append($('')); - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - - // Create info bar - var info = createInfoBar('Permanently add a volume to the z/VM system configuration.'); - addV2SForm.append(info); - - addV2SForm.append(system); - addV2SForm.append('
                          '); - addV2SForm.append('
                          '); - - // Generate tooltips - addV2SForm.find('div input[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 volume - addV2SForm.dialog({ - title:'Add volume to system configuration', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 480, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - var system = $(this).find('select[name=system]').val(); - var devnum = $(this).find('input[name=devNum]').val(); - var volser = $(this).find('input[name=volser]').val(); - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'input[name=devNum]', 'input[name=volser]' ); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - if (!ready) { - // Show warning message - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : system, - args : "--addvolume;" + devnum + ";" + volser, - msg : dialogId - }, - - success : updateResourceDialog - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Create remove Volume to system dialog - * - * @param hcp Hardware control point of node - */ -function openRemoveVolumeFromSystemDialog(hcp) { - var dialogId = 'zvmRemoveVolumeFromSystem'; - - // Create form to remove volume - var remVfromSForm = $('
                          '); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - - // Append options for hardware control points - //systemSelect.append($('')); - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - - // Create info bar - var info = createInfoBar('Permanently remove a volume from the z/VM system configuration.'); - remVfromSForm.append(info); - - remVfromSForm.append(system); - remVfromSForm.append('
                          '); - remVfromSForm.append('
                          '); - - // Generate tooltips - remVfromSForm.find('div input[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 remove volume - remVfromSForm.dialog({ - title:'Remove volume from system configuration', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 580, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - var system = $(this).find('select[name=system]').val(); - var devnum = $(this).find('input[name=devNum]').val(); - var volser = $(this).find('input[name=volser]').val(); - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'input[name=devNum]', 'input[name=volser]' ); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - if (!ready) { - // Show warning message - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : system, - args : "--removevolume;" + devnum + ";" + volser, - msg : dialogId - }, - - success : updateResourceDialog - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Create add page or spool dialog - * - * @param hcp Hardware control point of node - */ -function openAddPageSpoolDialog(hcp) { - var dialogId = 'zvmAddPageSpool'; - - // Create form to add disk - var addPageSpoolForm = $('
                          '); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - // Append options for hardware control points - //systemSelect.append($('')); - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - - // Create info bar - var info = createInfoBar('Add a page or spool volume to be used by zVM.'); - addPageSpoolForm.append(info); - - var diskFS = $('
                          Disk
                          '); - addPageSpoolForm.append(diskFS); - var diskAttr = $('
                          '); - diskFS.append($('
                          ')); - diskFS.append(diskAttr); - - diskAttr.append(system); - diskAttr.append('
                          '); - diskAttr.append('
                          '); - diskAttr.append('
                          '); - - // Generate tooltips - addPageSpoolForm.find('div input[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 disk - addPageSpoolForm.dialog({ - title:'Add page or spool', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 500, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - var system = $(this).find('select[name=system]').val(); - var volAddr = $(this).find('input[name=volAddr]').val(); - var volLabel = $(this).find('input[name=volLabel]').val(); - var volUse = $(this).find('select[name=volUse]').val(); - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'input[name=volAddr]', 'input[name=volLabel]', 'select[name=volUse]'); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - if (!ready) { - // Show warning message - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - var pageSpoolArgs = volAddr + ";" + volLabel + ";" + volUse; - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : system, - args : '--addpagespool;' + pageSpoolArgs, - msg : dialogId - }, - - success : updateResourceDialog - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Open dialog to share disk - * - * @param disks2share Disks selected in table - */ -function openShareDiskDialog(disks2share) { - // Create form to share disk - var dialogId = 'zvmShareDisk'; - var shareDiskForm = $('
                          '); - - var args = disks2share.split(';'); - var tgtHcp = args[0]; - var tgtVol = args[1]; - - if (!tgtVol || tgtVol == "undefined") - tgtVol = ""; - - // Create info bar - var info = createInfoBar('Indicate a full-pack minidisk is to be shared by the users of many real and virtual systems.'); - shareDiskForm.append(info); - - // Set region input based on those selected on table (if any) - var node = $('
                          '); - var volAddr = $('
                          '); - var shareEnable = $('
                          '); - shareDiskForm.append(node, volAddr, shareEnable); - - // Generate tooltips - shareDiskForm.find('div input[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 delete disk - shareDiskForm.dialog({ - title:'Share disk', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 500, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - // Get inputs - var node = $(this).find('input[name=node]').val(); - var volAddr = $(this).find('input[name=volAddr]').val(); - var shareEnable = $(this).find('select[name=shareEnable]').val(); - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('input[name=node]', 'input[name=volAddr]', 'select[name=shareEnable]'); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - if (!ready) { - // Show warning message - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - // Remove disk from pool - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : "--sharevolume;" + volAddr + ";" + shareEnable, - msg : dialogId - }, - - success : updateResourceDialog - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Create add SCSI 2 system dialog - * - * @param hcp Hardware control point of node - */ -function openAddScsi2SystemDialog(hcp) { - var dialogId = 'zvmAddScsi2System'; - - // Create form to add disk - var addS2SForm = $('
                          '); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - - // Create info bar - var info = createInfoBar('Dynamically add an SCSI disk to a running z/VM system as an EDEV.'); - addS2SForm.append(info); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - - // Append options for hardware control points - //systemSelect.append($('')); - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - - var devNo = $('
                          '); - var devPathLabel = $(''); - var devPathCount = 1; - //var pathDiv = $('
                          '); - - var devPathDiv = $('
                          '); - var devPathTable = $('
                          '); - var devPathHeader = $(' FCP Device WWPN LUN'); - // Adjust header width - devPathHeader.find('th').css({ - 'width' : '120px' - }); - devPathHeader.find('th').eq(0).css({ - 'width' : '20px' - }); - var devPathBody = $(''); - var devPathFooter = $(''); - - // Create a row - var devPathRow = $(''); - - // Add blank column (remove button replacement) - devPathRow.append(''); - - // Create FCP device number input - var fcpDevNum = $(''); - devPathRow.append(fcpDevNum); - - // Create FCP WWPN input - var fcpWwpn = $(''); - devPathRow.append(fcpWwpn); - - if ($.cookie('xcat_zvms')) { - zvms = $.cookie('xcat_zvms').split(','); - var zvm; - for (var i in zvms) { - if( !zvms[i] || 0 === zvms[i].length) continue; - var args = zvms[i].split(':'); - var zvm = args[0].toLowerCase(); - var iHcp = args[1]; - } - } - - // Create FCP LUN input - var fcpLun = $(''); - devPathRow.append(fcpLun); - - devPathBody.append(devPathRow); - - var addDevPathLink = $('+ Add path'); - addDevPathLink.bind('click', function(event){ - devPathCount = devPathCount + 1; - // Create a row - var devPathRow = $(''); - - // Add remove button - var removeBtn = $('').css({ - "float": "left", - "cursor": "pointer" - }); - var col = $('').append(removeBtn); - removeBtn.bind('click', function(event) { - $(this).parent().parent().remove(); - }); - devPathRow.append(col); - - // Create FCP device number input - var fcpDevNum = $(''); - devPathRow.append(fcpDevNum); - - // Create FCP WWPN input - var fcpWwpn = $(''); - devPathRow.append(fcpWwpn); - - // Create FCP LUN input - var fcpLun = $(''); - devPathRow.append(fcpLun); - - devPathBody.append(devPathRow); - - // Generate tooltips - addS2SForm.find('div input[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()); - } - }); - }); - devPathFooter.append(addDevPathLink); - devPathTable.append(devPathHeader); - devPathTable.append(devPathBody); - devPathTable.append(devPathFooter); - devPathDiv.append(devPathLabel); - devPathDiv.append(devPathTable); - - var option = $('
                          '); - var persist = $('
                          '); - addS2SForm.append(system, devNo, devPathDiv, option, persist); - - // Generate tooltips - addS2SForm.find('div input[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()); - } - }); - - addS2SForm.find('div input[title]').tooltip({ - position: "center right", - offset: [-2, 10], - effect: "fade", - opacity: 0.7, - predelay: 800, - events: { - def: "mouseover,mouseout", - input: "mouseover,mouseout", - widget: "focus mouseover,blur mouseout", - tooltip: "mouseover,mouseout" - } - }); - - // Open dialog to add disk - addS2SForm.dialog({ - title:'Add SCSI to running system', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 675, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - var system = $(this).find('select[name=system]').val(); - var devNo = $(this).find('input[name=devNo]').val(); - var pathArray = ""; - jQuery('.devPath').each(function(index) { - pathArray += $(this).find('input[name=fcpDevNum]').val() + ','; - pathArray += $(this).find('input[name=fcpWwpn]').val() + ','; - pathArray += $(this).find('input[name=fcpLun]').val() + ';'; - }); - var option = $(this).find('select[name=option]').val(); - var persist = $(this).find('select[name=persist]').val(); - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'input[name=fcpDevNum]', 'select[name=option]', 'select[name=persist]'); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - // Show warning message - if (!ready || !pathArray) { - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : system, - args : "--addscsi||" + devNo + "||" + pathArray + "||" + option + "||" + persist, - msg : dialogId - }, - - success : updateResourceDialog - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Delete a real SCSI disk - * - * @param hcp Hardware control point of node - */ -function openRemoveScsiDialog(hcp) { - var dialogId = 'zvmRemoveScsiDialog'; - // Create form to add disk - var removeScsiForm = $('
                          '); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - - // Append options for hardware control points - //systemSelect.append($('')); - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - - // Create info bar - var info = createInfoBar('Delete a real SCSI disk'); - removeScsiForm.append(info, system); - removeScsiForm.append('
                          '); - removeScsiForm.append('
                          '); - addNicForm.append('
                          '); - - // Create drop down for NIC types - var nicType = $('
                          '); - nicType.append(''); - var nicTypeSelect = $(''); - nicTypeSelect.append('' - + '' - + '' - ); - nicType.append(nicTypeSelect); - addNicForm.append(nicType); - - // Create drop down for network types - var networkType = $('
                          '); - networkType.append(''); - var networkTypeSelect = $(''); - networkTypeSelect.append('' - + '' - + '' - ); - networkType.append(networkTypeSelect); - addNicForm.append(networkType); - var hashtable = getselectedNetworkHash(); - if (!hashtable) { - hashtable = [[]]; - setselectedNetworkHash(hashtable); - - if (typeof console == "object") { - console.log("openAddNicDialog. creating new hash[[]] table." ); - } - } - - // Create drop down for network names - var gLansQdioSelect = $(''); - var gLansHipersSelect = $(''); - var vswitchSelect = $(''); - for ( var i = 0; i < networks.length; i++) { - if( !networks[i] || 0 === networks[i].length) continue; - var network = networks[i].split(' '); - var networkOption = $(''); - if (network[0] == 'VSWITCH') { - vswitchSelect.append(networkOption); - - // Load and save specific vswitch details in global table if not there - network[2] = jQuery.trim(network[2]); // Remove new line x012 from end - if (typeof hashtable[node + '_NIC_' + network[2]] === 'undefined') { - if (typeof console == "object"){ - console.log("Calling getNetworkDetails for switch:<"+network[2]+">"); - } - ajaxrequest = 1; - getNetworkDetails(hcpNode, network[2], node + '_NIC_' + network[2], ''); - } - } else if (network[0] == 'LAN:QDIO') { - gLansQdioSelect.append(networkOption); - } else if (network[0] == 'LAN:HIPERS') { - gLansHipersSelect.append(networkOption); - } - } - - // Hide network name drop downs until the NIC type and network type is selected - // QDIO Guest LAN drop down - var guestLanQdio = $('
                          ').hide(); - guestLanQdio.append(''); - guestLanQdio.append(gLansQdioSelect); - addNicForm.append(guestLanQdio); - - // HIPERS Guest LAN drop down - var guestLanHipers = $('
                          ').hide(); - guestLanHipers.append(''); - guestLanHipers.append(gLansHipersSelect); - addNicForm.append(guestLanHipers); - - // VSWITCH drop down - var vswitch = $('
                          ').hide(); - vswitch.append(''); - vswitch.append(vswitchSelect); - - // VLAN id with Porttype - var vswitchvlan = $('
                          '); - vswitchvlan.append('
                          '); - var vswitchPorttype = $(''); - vswitchvlan.append(vswitchPorttype); - vswitchvlan.append('
                          '); - var vswitchVLANId = $(''); - vswitchvlan.append(vswitchVLANId); - - vswitch.append(vswitchvlan); - vswitchvlan.hide(); - addNicForm.append(vswitch); - - // Show network names on change - networkTypeSelect.change(function(){ - // Remove any warning messages - $(this).parent().parent().find('.ui-state-error').remove(); - var networkType = $(this).val(); - - if (typeof console == "object"){ - console.log("Entering networkTypeSelect.change"); - } - // Get NIC type and network type - var nicType = $(this).parent().parent().find('select[name=nicType]').val(); - var networkType = $(this).val(); - - // Hide network name drop downs - var guestLanQdio = $(this).parent().parent().find('select[name=nicLanQdioName]').parent(); - var guestLanHipers = $(this).parent().parent().find('select[name=nicLanHipersName]').parent(); - var vswitch = $(this).parent().parent().find('select[name=nicVSwitchName]').parent(); - var mynode = $(this).parent().parent().find('input[name=nicNode]').val(); - var showvlan = $(this).parent().parent().find('select[name=vswitchVLANporttype]').parent(); - var hashtable = getselectedNetworkHash(); - guestLanQdio.hide(); - guestLanHipers.hide(); - vswitch.hide(); - - // Show correct network name - if (networkType == 'Guest LAN' && nicType == 'QDIO') { - guestLanQdio.show(); - } else if (networkType == 'Guest LAN' && nicType == 'HiperSockets') { - guestLanHipers.show(); - } else if (networkType == 'Virtual Switch') { - if (nicType == 'QDIO') { - vswitch.show(); - // Show vlan information only if vlan aware - var switchname = $(this).parent().parent().find('select[name=nicVSwitchName]').val(); - var tokens = switchname.split(' '); - var switchkeyid = mynode + '_NIC_' + jQuery.trim(tokens[1]); - if (typeof console == "object"){ - console.log("Checking vswitch index:"+switchkeyid); - } - - // Is this a vlanaware switch, if so show the special fields - if (hashtable[switchkeyid]["vlan_awareness"] == "AWARE") { - showvlan.find('input[name=vswitchvlanid]').val(hashtable[switchkeyid]["vlan_id"]); - showvlan.find('select[name=vswitchVLANporttype]').val(hashtable[switchkeyid]["port_type"]); - showvlan.show(); - } else { - showvlan.hide(); - showvlan.find('input[name=vswitchvlanid]').val('default'); - showvlan.find('select[name=vswitchVLANporttype]').val('default'); - } - } else { - // No such thing as HIPERS VSWITCH - var warn = createWarnBar('The selected choices are not valid.'); - warn.prependTo($(this).parent().parent()); - } - } - }); - - // - // Show network names on change - // - nicTypeSelect.change(function(){ - // Remove any warning messages - $(this).parent().parent().find('.ui-state-error').remove(); - - if (typeof console == "object"){ - console.log("Entering nicTypeSelect.change"); - } - - // Get NIC type and network type - var nicType = $(this).val(); - var networkType = $(this).parent().parent().find('select[name=nicNetworkType]').val(); - var mynode = $(this).parent().parent().find('input[name=nicNode]').val(); - - // Hide network name drop downs - var guestLanQdio = $(this).parent().parent().find('select[name=nicLanQdioName]').parent(); - var guestLanHipers = $(this).parent().parent().find('select[name=nicLanHipersName]').parent(); - var vswitch = $(this).parent().parent().find('select[name=nicVSwitchName]').parent(); - var showvlan = $(this).parent().parent().find('select[name=vswitchVLANporttype]').parent(); - var hashtable = getselectedNetworkHash(); - guestLanQdio.hide(); - guestLanHipers.hide(); - vswitch.hide(); - - // Show correct network name - if (networkType == 'Guest LAN' && nicType == 'QDIO') { - guestLanQdio.show(); - } else if (networkType == 'Guest LAN' && nicType == 'HiperSockets') { - guestLanHipers.show(); - } else if (networkType == 'Virtual Switch') { - if (nicType == 'QDIO') { - vswitch.show(); - var switchname = $(this).parent().parent().find('select[name=nicVSwitchName]').val(); - var tokens = switchname.split(' '); - var switchkeyid = mynode + '_NIC_' + jQuery.trim(tokens[1]); - - if (typeof console == "object"){ - console.log("Entering nictypeselect.change. switchkey:<"+switchkeyid); - } - - // Is this a vlanaware switch, if so show the special fields - if (hashtable[switchkeyid]["vlan_awareness"] == "AWARE") { - showvlan.find('input[name=vswitchvlanid]').val(hashtable[switchkeyid]["vlan_id"]); - showvlan.find('select[name=vswitchVLANporttype]').val(hashtable[switchkeyid]["port_type"]); - showvlan.show(); - } else { - showvlan.hide(); - showvlan.find('input[name=vswitchvlanid]').val('default'); - showvlan.find('select[name=vswitchVLANporttype]').val('default'); - } - - } else { - // No such thing as HIPERS VSWITCH - var warn = createWarnBar('The selected choices are not valid.'); - warn.prependTo($(this).parent().parent()); - } - } - }); - - // - // Determine if vlanid fields need to be shown based on vswitch - // - vswitchSelect.change(function(){ - // Remove any warning messages - $(this).parent().parent().find('.ui-state-error').remove(); - - // Get vlan id division - var showvlan = $(this).parent().parent().find('select[name=vswitchVLANporttype]').parent(); - - // Get selected switch name and break it into tokens - var switchname = $(this).val(); - var tokens = switchname.split(' '); - - // Get the node we are doing this for and index for hash table - var mynode = $(this).parent().parent().find('input[name=nicNode]').val(); - - var tokens = switchname.split(' '); - var switchkeyid = mynode + '_NIC_' + jQuery.trim(tokens[1]); - var hashtable = getselectedNetworkHash(); - - if (typeof console == "object"){ - console.log("Entering vswitchselect.change. switchkey:<"+switchkeyid+">"); - } - // Is this a vlanaware switch, if so show the special fields - if (hashtable[switchkeyid]["vlan_awareness"] == "AWARE") { - $(this).find('').val(hashtable[switchkeyid]["vlan_id"]); - showvlan.find('input[name=vswitchvlanid]').val(hashtable[switchkeyid]["vlan_id"]); - showvlan.find('select[name=vswitchVLANporttype]').val(hashtable[switchkeyid]["port_type"]); - showvlan.show(); - } else { - showvlan.hide(); - showvlan.find('input[name=vswitchvlanid]').val('default'); - showvlan.find('select[name=vswitchVLANporttype]').val('default'); - } - }); - - - // Generate tooltips - addNicForm.find('div input[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 NIC - addNicForm.dialog({ - title:'Add NIC', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - var ready = true; - var errMsg = ''; - - // Get inputs - var node = $(this).find('input[name=nicNode]').val(); - var nicType = $(this).find('select[name=nicType]').val(); - var networkType = $(this).find('select[name=nicNetworkType]').val(); - var address = $(this).find('input[name=nicAddress]').val(); - - // If inputs are not complete, show warning message - if (!node || !nicType || !networkType || !address) { - errMsg = 'Please provide a value for each missing field.
                          '; - ready = false; - } - - // If a HIPERS VSWITCH is selected, show warning message - if (nicType == 'HiperSockets' && networkType == 'Virtual Switch') { - errMsg += 'The selected choices are not valid.'; - ready = false; - } - - // If there are errors - if (!ready) { - // Show warning message - var warn = createWarnBar(errMsg); - warn.prependTo($(this)); - } else { - // Add guest LAN - if (networkType == 'Guest LAN') { - var temp; - if (nicType == 'QDIO') { - temp = $(this).find('select[name=nicLanQdioName]').val().split(' '); - } else { - temp = $(this).find('select[name=nicLanHipersName]').val().split(' '); - } - - var lanOwner = temp[0]; - var lanName = temp[1]; - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--addnic;' + address + ';' + nicType + ';3', - msg : 'node=' + node + ';addr=' + address + ';lan=' - + lanName + ';owner=' + lanOwner - }, - success : connect2GuestLan - }); - } - - // Add virtual switch - else if (networkType == 'Virtual Switch' && nicType == 'QDIO') { - var temp = $(this).find('select[name=nicVSwitchName]').val().split(' '); - var vswitchName = jQuery.trim(temp[1]); - var switchkeyid = node + '_NIC_' + vswitchName; - var hashtable = getselectedNetworkHash(); - var awareornot = hashtable[switchkeyid]["vlan_awareness"]; - var porttype = $(this).find('select[name=vswitchVLANporttype]').val(); - var lanid = $(this).find('input[name=vswitchvlanid]').val(); - - // Pass additional lanid data in msg for grant use by connect2VSwitch - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--addnic;' + address + ';' + nicType + ';3', - msg : 'node=' + node + ';addr=' + address + ';vsw=' - + vswitchName + ';vlanaware=' + awareornot + ';porttype=' - + porttype + ';lanid=' + lanid - }, - - success : connect2VSwitch - }); - } - - // Increment node process - incrementNodeProcess(node); - - // Show loader - $('#' + node + 'StatusBarLoader').show(); - $('#' + node + 'StatusBar').show(); - - // Close dialog - $(this).dialog( "close" ); - } // End of else - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); - // Make sure ajax is done before putting up dialog - $(document).ajaxStop(function() { - //Remove loading vswitch gif status bar - statBar.hide(); - }); - if (ajaxrequest == 0) { - //Remove loading vswitch gif status bar - statBar.hide(); - } - -} - -/** - * Create add vSwitch/VLAN dialog - * - * @param hcp Hardware control point of node - */ -function openAddVswitchVlanDialog(hcp) { - var dialogId = 'zvmAddVswitchVlan'; - - // Create form to add disk - var addVswitchForm = $('
                          '); - - // Create info bar - var info = createInfoBar('Create a virtual switch or virtual network LAN.'); - - var netFS = $('
                          '); - var netLegend = $('Network'); - netFS.append(netLegend); - - var typeFS = $('
                          ').hide(); - var typeLegend = $('Network'); - typeFS.append(typeLegend); - addVswitchForm.append(info, netFS, typeFS); - - var netAttr = $('
                          '); - netFS.append($('
                          ')); - netFS.append(netAttr); - - var networkTypeDiv = $('
                          '); - var networkType = $('
                          '); - networkTypeDiv.append(networkType) - netAttr.append(networkTypeDiv); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - netAttr.append(system); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - //systemSelect.append($('')); - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - - var typeAttr = $('
                          '); - typeFS.append($('
                          ')); - typeFS.append(typeAttr); - - // Create vSwitch parameters - var vswitchOptions = $('
                          ').hide(); - vswitchOptions.append($('
                          ')); - vswitchOptions.append($('
                          ')); - vswitchOptions.append($('
                          ')); - - // Create an advanced link to configure optional network settings - var advancedLnk = $(''); - vswitchOptions.append(advancedLnk); - var advanced = $('
                          ').hide(); - vswitchOptions.append(advanced); - - // Show IP address and hostname inputs on-click - advancedLnk.click(function() { - advanced.toggle(); - }); - - advanced.append($('
                          ')); - advanced.append($('
                          ')); - advanced.append($('
                          ')); - advanced.append($('
                          ')); - advanced.append($('
                          ')); - advanced.append($('
                          ')); - advanced.append($('
                          ')); - advanced.append($('
                          ')); - advanced.append($('
                          ')); - - // Create VLAN parameters - var vlanOptions = $('
                          ').hide(); - vlanOptions.append($('
                          ')); - vlanOptions.append($('
                          ')); - vlanOptions.append($('
                          ')); - vlanOptions.append($('
                          ')); - - typeAttr.append(vswitchOptions, vlanOptions); - - networkType.change(function() { - typeFS.show(); - if ($(this).val() == "vswitch") { - typeFS.find("legend").text("vSwitch"); - vswitchOptions.show(); - vlanOptions.hide(); - } else if ($(this).val() == "vlan") { - typeFS.find("legend").text("VLAN"); - vswitchOptions.hide(); - vlanOptions.show(); - } else { - typeFS.find("legend").text(""); - vswitchOptions.hide(); - vlanOptions.hide(); - typeFS.hide(); - } - }); - - // Generate tooltips - addVswitchForm.find('div input[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 vSwitch or VLAN - addVswitchForm.dialog({ - title:'Add vSwitch or VLAN', - modal: true, - close: function() { - $(this).remove(); - }, - width: 750, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - var networkType = $(this).find('select[name=networkType]').val(); - if (networkType == "vswitch") { - var networkArgs = "--addvswitch;"; - var system = $(this).find('select[name=system]').val(); - var switchName = $(this).find('input[name=switchName]').val(); - var deviceAddress = $(this).find('input[name=deviceAddress]').val(); - var portName = switchName; - var controllerName = $(this).find('input[name=controllerName]').val(); - var connection = $(this).find('select[name=connection]').val(); - var queueMemoryLimit = $(this).find('input[name=queueMemoryLimit]').val(); - var routingValue = $(this).find('select[name=routingValue]').val(); - var transportType = $(this).find('select[name=transportType]').val(); - var vlanId = $(this).find('input[name=vlanId]').val(); - var portType = $(this).find('select[name=vswitchVLANporttype]').val(); - var updateSysConfig = $(this).find('select[name=updateSysConfig]').val(); - var gvrp = $(this).find('select[name=gvrp]').val(); - var nativeVlanId = $(this).find('input[name=nativeVlanId]').val(); - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'input[name=switchName]', 'input[name=deviceAddress]', 'input[name=controllerName]'); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - // Show warning message - if (!ready) { - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - if (switchName) - networkArgs += switchName + ";"; - if (deviceAddress) - networkArgs += deviceAddress + ";"; - if (portName) - networkArgs += portName + ";"; - if (controllerName) - networkArgs += controllerName + ";"; - - // Optional parameters - if (connection) - networkArgs += connection + ";"; - if (queueMemoryLimit) - networkArgs += queueMemoryLimit + ";"; - if (routingValue) - networkArgs += routingValue + ";"; - if (transportType) - networkArgs += transportType + ";"; - if (vlanId) - networkArgs += vlanId + ";"; - if (portType) - networkArgs += portType + ";"; - if (updateSysConfig) - networkArgs += updateSysConfig + ";"; - if (gvrp) - networkArgs += gvrp + ";"; - if (nativeVlanId) - networkArgs += nativeVlanId + ";"; - networkArgs = networkArgs.substring(0, networkArgs.length - 1); - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : system, - args : networkArgs, - msg : dialogId - }, - - success : updateResourceDialog - }); - } else if (networkType == "vlan") { - var networkArgs = "--addvlan;"; - var system = $(this).find('select[name=system]').val(); - var vlanName = $(this).find('input[name=vlanName]').val(); - var vlanOwner = $(this).find('input[name=vlanOwner]').val(); - var vlanType = $(this).find('select[name=vlanType]').val(); - var vlanTransport = $(this).find('select[name=vlanTransport]').val(); - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'input[name=vlanName]', 'input[name=vlanOwner]', 'select[name=vlanType]', 'select[name=vlanTransport]'); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - // Show warning message - if (!ready) { - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Ethernet Hipersockets are not supported - if (vlanTransport == "2") { - var warn = createWarnBar('Ethernet Hipersockets are not supported'); - warn.prependTo($(this)); - return; - } - - networkArgs += vlanName + ";"; - networkArgs += vlanOwner + ";"; - networkArgs += vlanType + ";"; - networkArgs += vlanTransport; - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : system, - args : networkArgs, - msg : dialogId - }, - - success : updateResourceDialog - }); - } // End of else if - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Open dialog to delete network - * - * @param node type name for removing network - */ -function openRemoveVswitchVlanDialog(networkList) { - var names = ''; - for (var i in networkList) { - var networkArgs = networkList[i].split(';'); - networkArgs[2] = jQuery.trim(networkArgs[2]); - names += networkArgs[2] + ', '; - } - names = names.substring(0, names.length - 2); // Delete last two characters - - var confirmDialog = $('

                          Are you sure you want to remove ' + names + '?

                          '); - confirmDialog.dialog({ - title: "Confirm", - modal: true, - width: 400, - buttons: { - "Ok": function() { - for (var i in networkList) { - var networkArgs = networkList[i].split(';'); - var node = networkArgs[0]; - var type = networkArgs[1]; - var name = jQuery.trim(networkArgs[2]); - var owner = networkArgs[3]; - - if (type.indexOf("VSWITCH") != -1) { - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : node, - args : '--removevswitch;' + name, - msg : '' - }, - - success: function(data) { - 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; - } - - openDialog("info", infoMsg); - } - }); - } else if (type.indexOf("LAN") != -1) { - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : node, - args : '--removevlan;' + name + ';' + owner, - msg : '' - }, - - success: function(data) { - 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; - } - - openDialog("info", infoMsg); - } - }); - } - } - $(this).dialog("close"); - }, - "Cancel": function() { - $(this).dialog("close"); - } - } - }); -} - -/** - * Remove processor - * - * @param node Node where processor is attached - * @param address Virtual address of processor - */ -function removeProcessor(node, address) { - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--removeprocessor;' + address, - msg : node - }, - - success : updateZNodeStatus - }); - - // Increment node process - incrementNodeProcess(node); - - // Show loader - $('#' + node + 'StatusBarLoader').show(); - $('#' + node + 'StatusBar').show(); -} - -/** - * Remove disk - * - * @param node Node where disk is attached - * @param address Virtual address of disk - */ -function removeDisk(node, address) { - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--removedisk;' + address, - msg : node - }, - - success : updateZNodeStatus - }); - - // Increment node process - incrementNodeProcess(node); - - // Show loader - $('#' + node + 'StatusBarLoader').show(); - $('#' + node + 'StatusBar').show(); -} - -/** - * Remove zFCP device - * - * @param node Node where disk is attached - * @param address Virtual address of zFCP device - * @param wwpn World wide port name of zFCP device - * @param lun Logical unit number of zFCP device - */ -function removeZfcp(node, address, wwpn, lun) { - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--removezfcp||' + address + '||' + wwpn + '||' + lun, - msg : node - }, - - success : updateZNodeStatus - }); - - // Increment node process - incrementNodeProcess(node); - - // Show loader - $('#' + node + 'StatusBarLoader').show(); - $('#' + node + 'StatusBar').show(); -} - -/** - * Remove NIC - * - * @param node Node where NIC is attached - * @param address Virtual address of NIC - */ -function removeNic(node, nic) { - var args = nic.split('.'); - var address = args[0]; - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--removenic;' + address, - msg : node - }, - - success : updateZNodeStatus - }); - - // Increment node process - incrementNodeProcess(node); - - // Show loader - $('#' + node + 'StatusBarLoader').show(); - $('#' + node + 'StatusBar').show(); -} - -/** - * Set a cookie for the network names of a given node - * - * @param data Data from HTTP request - */ -function setNetworkCookies(data) { - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1) { - var node = data.msg; - var networks = data.rsp[0].split(node + ': '); - - // Set cookie to expire in 60 minutes - var exDate = new Date(); - exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); - $.cookie('xcat_' + node + 'networks', networks, { expires: exDate, path: '/xcat', secure:true }); - } -} - -/** - * Get contents of each disk pool - * - * @param data HTTP request data - */ -function getDiskPool(data) { - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Invalid") == -1 && data.rsp[0].indexOf("Error") == -1) { - var hcp = data.msg; - var pools = data.rsp[0].split(hcp + ': '); - - // Get contents of each disk pool - for (var i in pools) { - if (pools[i]) { - pools[i] = jQuery.trim(pools[i]); - - // Get used space - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcp, - args : '--diskpool;' + pools[i] + ';used', - msg : 'hcp=' + hcp + ';pool=' + pools[i] + ';stat=used' - }, - - success : loadDiskPoolTable - }); - - // Get free space - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcp, - args : '--diskpool;' + pools[i] + ';free', - msg : 'hcp=' + hcp + ';pool=' + pools[i] + ';stat=free' - }, - - success : loadDiskPoolTable - }); - } // End of if - } // End of for - } else { - // Display any errors in info bar - if (data.rsp.length) { - var panelId = 'zvmDiskResource'; - var info = $('#' + panelId).find('.ui-state-highlight'); - // If there is no info bar, create info bar - if (!info.length) { - info = createInfoBar("Error: "+data.rsp[0]); - $('#' + panelId).append(info); - } else { - info.append("
                          Error: "+data.rsp[0]); - } - } - // Load empty table - loadDiskPoolTable(""); // Must pass something - } -} - -/** - * Get contents of each zFCP pool - * - * @param data HTTP request data - */ -function getZfcpPool(data) { - if (typeof console == "object"){ - console.log("Entering getZfcpPool."); - } - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Invalid") == -1 && data.rsp[0].indexOf("Error") == -1) { - var hcp = data.msg; - var pools = data.rsp[0].split(hcp + ': '); - zhcpQueryCountForZfcps = 0; - // Get contents of each disk pool - for (var i in pools) { - pools[i] = jQuery.trim(pools[i]); - if (pools[i]) { - - // Query used and free space - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcp, - args : '--zfcppool;' + pools[i] + ';all', - msg : 'hcp=' + hcp + ';pool=' + pools[i] - }, - success : loadZfcpPoolTable - }); - } // End of if - } // End of for - } else { - // Display any errors in info bar - if (data.rsp.length) { - var panelId = 'zfcpResource'; - var info = $('#' + panelId).find('.ui-state-highlight'); - // If there is no info bar, create info bar - if (!info.length) { - info = createInfoBar("Error: "+data.rsp[0]); - $('#' + panelId).append(info); - } else { - info.append("
                          Error: "+data.rsp[0]); - } - } - // Load empty table - loadZfcpPoolTable(""); // Must pass something - } -} - -/** - * Get details of each network - * - * @param data HTTP request data - */ -function getNetwork(data) { - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Invalid") == -1 && data.rsp[0].indexOf("Error") == -1) { - var hcp = data.msg; - var networks = data.rsp[0].split(hcp + ': '); - if (typeof console == "object"){ - console.log("Entering getNetwork data:<"+networks+">"); - } - - // Loop through each network - for ( var i = 1; i < networks.length; i++) { - if( !networks[i] || 0 === networks[i].length) continue; - var args = networks[i].split(' '); - var type = args[0]; - var name = args[2]; - name = name.replace(/\n/g,''); - - // Get network details - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcp, - args : '--getnetwork;' + name + ';' + type, - msg : 'hcp=' + hcp + ';type=' + type + ';network=' + name - }, - - success : loadNetworkTable - }); - } // End of for - } // End of if - else { - if (data.rsp.length) { - var panelId = 'zvmNetworkResource'; - var info = $('#' + panelId).find('.ui-state-highlight'); - // If there is no info bar, create info bar - if (!info.length) { - info = createInfoBar("Error: "+data.rsp[0]); - $('#' + panelId).append(info); - } else { - info.append("
                          Error: "+data.rsp[0]); - } - } - // Normally load empty table, but not for networks - } -} - -/** - * Load disk pool contents into a table - * - * @param data HTTP request data - */ -function loadDiskPoolTable(data) { - // Remove loader if all hcps queried - var panelId = 'zvmDiskResource'; - if (!zhcpQueryCountForDisks) { - $('#' + panelId).find('img[src="images/loader.gif"]').remove(); - } - - var hcp2zvm = new Object(); - var args, hcp, pool, stat, tmp; - if (data && typeof data.rsp != "undefined") { - // Do not continue if the call failed - if (!data.rsp.length && data.rsp[0].indexOf("Failed") > 0 && data.rsp[0].indexOf("Error") > 0) { - return; - } - - // Obtain mapping for zHCP to zVM system - hcp2zvm = getHcpZvmHash(); - - args = data.msg.split(';'); - hcp = args[0].replace('hcp=', ''); - pool = args[1].replace('pool=', ''); - stat = jQuery.trim(args[2].replace('stat=', '')); - tmp = data.rsp[0].split(hcp + ': '); - } else { - // Provide empty values so the table will be generated - hcp = ''; - pool = ''; - stat = ''; - tmp = new Array(); - } - - // Resource tab ID - var info = $('#' + panelId).find('.ui-state-highlight'); - // If there is no info bar - if (!info.length) { - // Create info bar - info = createInfoBar('Below are disks that are defined in the EXTENT CONTROL file.'); - $('#' + panelId).append(info); - } - - // Get datatable - var tableId = 'zDiskDataTable'; - var dTable = getDiskDataTable(); - if (!dTable) { - // Create a datatable - var table = new DataTable(tableId); - // Resource headers: volume ID, device type, start address, and size - table.init( [ '', 'z/VM', 'Pool', 'Status', 'Volume', 'Device type', 'Starting address', 'Size' ]); - - // Append datatable to panel - $('#' + panelId).append(table.object()); - - // Turn into datatable - dTable = $('#' + tableId).dataTable({ - 'iDisplayLength': 50, - "bScrollCollapse": true, - "sScrollY": "400px", - "sScrollX": "110%", - "bAutoWidth": true, - "oLanguage": { - "oPaginate": { - "sNext": "", - "sPrevious": "" - } - } - }); - setDiskDataTable(dTable); - } - - // Skip index 0 and 1 because it contains nothing - for (var i = 2; i < tmp.length; i++) { - tmp[i] = jQuery.trim(tmp[i]); - var diskAttrs = tmp[i].split(' '); - var key = hcp2zvm[hcp] + "-" + pool + "-" + diskAttrs[0]; - var type = diskAttrs[1]; - - // Calculate disk size - var size; - if (type.indexOf('3390') != -1) { - size = convertCylinders2Gb(parseInt(diskAttrs[3])); - } else if (type.indexOf('9336') != -1) { - size = convertBlocks2Gb(parseInt(diskAttrs[3])) - } else { - size = 0; - } - dTable.fnAddData( [ '', hcp2zvm[hcp], pool, stat, diskAttrs[0], type, diskAttrs[2], diskAttrs[3] + " (" + size + "G)" ]); - } - - // Create actions menu - if (!$('#zvmDiskResourceActions').length) { - // Empty filter area - $('#' + tableId + '_length').empty(); - - // Add disk to pool - var addLnk = $('Add'); - addLnk.bind('click', function(event){ - openAddDisk2PoolDialog(); - }); - - // Delete disk from pool - var removeLnk = $('Remove'); - removeLnk.bind('click', function(event){ - var disks = getNodesChecked(tableId); - openRemoveDiskFromPoolDialog(disks); - }); - - // Refresh table - var refreshLnk = $('Refresh'); - refreshLnk.bind('click', function(event){ - $('#zvmDiskResource').empty().append(createLoader('')); - setDiskDataTable(''); - - // Create a array for hardware control points - var hcps = new Array(); - if ($.cookie('xcat_hcp').indexOf(',') > -1) - hcps = $.cookie('xcat_hcp').split(','); - else - hcps.push($.cookie('xcat_hcp')); - - zhcpQueryCountForDisks = hcps.length; - // Query the disk pools for each - for (var i in hcps) { - if( !hcps[i] || 0 === hcps[i].length) continue; - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcps[i], - args : '--diskpoolnames', - msg : hcps[i] - }, - - success : getDiskPool - }); - zhcpQueryCountForDisks--; - } - }); - - // Add ECKD to system - var addEckdLnk = $('Add ECKD'); - addEckdLnk.bind('click', function(event){ - openAddEckd2SystemDialog(hcp); - }); - - // Add Page or Spool - var addPageSpoolLnk = $('Add page/spool') - addPageSpoolLnk.bind('click', function(event){ - openAddPageSpoolDialog(hcp); - }); - - // Add EDEV to system - var addEdevLnk = $('Add EDEV'); - addEdevLnk.bind('click', function(event){ - openAddScsi2SystemDialog(hcp); - }); - - // Remove EDEV - var removeEdevLnk = $('Remove EDEV'); - removeEdevLnk.bind('click', function(event){ - openRemoveScsiDialog(hcp); - }); - - // Indicate disk is to be shared with various users - var shareLnk = $('Share disk'); - shareLnk.bind('click', function(event){ - var disks = getNodesChecked(tableId); - openShareDiskDialog(disks); - }); - - // Add Volume to system - var addVolumeLnk = $('Add volume to system'); - addVolumeLnk.bind('click', function(event){ - openAddVolume2SystemDialog(hcp); - }); - - // Remove Volume from system - var removeVolumeLnk = $('Remove volume from system'); - removeVolumeLnk.bind('click', function(event){ - openRemoveVolumeFromSystemDialog(hcp); - }); - - // Advanced menu - var advancedLnk = 'Advanced'; - var advancedMenu = createMenu([addEckdLnk, addPageSpoolLnk, addEdevLnk, removeEdevLnk, addVolumeLnk, removeVolumeLnk, shareLnk]); - - // Create action bar - var actionBar = $('
                          ').css("width", "450px"); - - // Create an action menu - var actionsMenu = createMenu([refreshLnk, addLnk, removeLnk, [advancedLnk, advancedMenu]]); - 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 + '_length').prepend(menuDiv); - $('#' + tableId + '_length').css({ - 'padding': '0px', - 'width': '500px' - }); - $('#' + tableId + '_filter').css('padding', '10px'); - menuDiv.append(actionBar); - } - - // Resize accordion - $('#zvmResourceAccordion').accordion('resize'); -} - -/** - * Load zFCP pool contents into a table - * - * @param data HTTP request data - */ -function loadZfcpPoolTable(data) { - if (typeof console == "object"){ - console.log("Entering loadZfcpPoolTable."); - } - // Delete loader if last one - var panelId = 'zfcpResource'; - if (zhcpQueryCountForZfcps <= 0) { - $('#' + panelId).find('img[src="images/loader.gif"]').remove(); - } - - var hcp2zvm = new Object(); - var args, hcp, pool, tmp; - - // Resource tab ID - var info = $('#' + panelId).find('.ui-state-highlight'); - - // Is there any data passed? Process if some - if (typeof data.rsp != "undefined") { - // Do not continue if no data to add - if (!data.rsp.length) { - if (typeof console == "object"){ - console.log("data.rsp.length is 0."); - } - // If there is no info bar, create info bar - var msgError = '
                          Unexpected, no data returned on the lsvm --zfcppool call.'; - if (!info.length) { - info = createInfoBar(msgError); - $('#' + panelId).append(info); - } else { - info.append(msgError); - } - return; - } - if (data.rsp[0].indexOf("Failed") > 0 || data.rsp[0].indexOf("Error") > 0) { - if (typeof console == "object"){ - console.log("Failed on lsvm call for --zfcppool"); - } - var msgError = '
                          Error: Error on call to check zfcp pools: '+ data.rsp[0]; - // If there is no info bar, create info bar - if (!info.length) { - info = createInfoBar(msgError); - $('#' + panelId).append(info); - } else { - info.append(msgError); - } - return; - } - - // Obtain mapping for zHCP to zVM system - hcp2zvm = getHcpZvmHash(); - - args = data.msg.split(';'); - hcp = args[0].replace('hcp=', ''); - pool = args[1].replace('pool=', ''); - tmp = data.rsp[0].split(hcp + ': '); - } else { - // Provide empty values so the table will be generated - if (typeof console == "object"){ - console.log("Creating empty zfcp pool table."); - } - hcp = ''; - pool = '' - tmp = new Array(); - } - - // If there is no info bar, create info bar - if (!info.length) { - info = createInfoBar('Below are devices that are defined internally in the zFCP pools.'); - $('#' + panelId).append(info); - } - - // Get datatable - var tableId = 'zFcpDataTable'; - var dTable = getZfcpDataTable(); - if (!dTable) { - // Create a datatable - var table = new DataTable(tableId); - // Resource headers: status, WWPN, LUN, size, owner, channel, tag - table.init( [ '', 'z/VM', 'Pool', 'Status', 'Port name', 'Unit number', 'Size', 'Range', 'Owner', 'Channel', 'Tag' ]); - - // Append datatable to panel - $('#' + panelId).append(table.object()); - - // Turn into datatable - dTable = $('#' + tableId).dataTable({ - 'iDisplayLength': 50, - "bScrollCollapse": true, - "sScrollY": "400px", - "sScrollX": "110%", - "bAutoWidth": true, - "oLanguage": { - "oPaginate": { - "sNext": "", - "sPrevious": "" - } - } - }); - setZfcpDataTable(dTable); - } - if ((typeof data.rsp != "undefined") && (data.rsp.length > 0)) { - // Skip index 0 and 1 because it contains nothing - var key = ""; - for (var i = 2; i < tmp.length; i++) { - tmp[i] = jQuery.trim(tmp[i]); - var diskAttrs = tmp[i].split(','); - diskAttrs[0] = diskAttrs[0].toLowerCase(); - // Key contains row data to be returned when the checkbox is selected - var key = hcp2zvm[hcp] + '-' + pool + '-' + diskAttrs[2] + '-' + diskAttrs[1]; - dTable.fnAddData( [ '', hcp2zvm[hcp], pool, diskAttrs[0], diskAttrs[1], diskAttrs[2], diskAttrs[3], diskAttrs[4], diskAttrs[5], diskAttrs[6], diskAttrs[7] ]); - } - } - // Create actions menu - if (!$('#zFcpResourceActions').length) { - // Empty filter area - $('#' + tableId + '_length').empty(); - - // Add disk to pool - var addLnk = $('Add'); - addLnk.bind('click', function(event){ - openAddZfcp2PoolDialog(); - }); - - // Delete disk from pool - var removeLnk = $('Remove'); - removeLnk.bind('click', function(event){ - if (typeof console == "object"){ - console.log("Remove button clicked for tableId:"+tableId); - } - var disks = getNodesChecked(tableId); - openRemoveZfcpFromPoolDialog(disks); - }); - - // Refresh table - var refreshLnk = $('Refresh'); - refreshLnk.bind('click', function(event){ - $('#zfcpResource').empty().append(createLoader('')); - setZfcpDataTable(''); - - // Create a array for hardware control points - var hcps = new Array(); - if ($.cookie('xcat_hcp').indexOf(',') > -1) - hcps = $.cookie('xcat_hcp').split(','); - else - hcps.push($.cookie('xcat_hcp')); - - // Query the disk pools for each - zhcpQueryCountForZfcps = hcps.length; - for (var i in hcps) { - if( !hcps[i] || 0 === hcps[i].length) continue; - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcps[i], - args : '--zfcppoolnames', - msg : hcps[i] - }, - - success : getZfcpPool - }); - zhcpQueryCountForZfcps--; - } - }); - // Create action bar - var actionBar = $('
                          ').css("width", "450px"); - - // Create an action menu - var actionsMenu = createMenu([addLnk, removeLnk, refreshLnk]); - 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 + '_length').prepend(menuDiv); - $('#' + tableId + '_length').css({ - 'padding': '0px', - 'width': '500px' - }); - $('#' + tableId + '_filter').css('padding', '10px'); - menuDiv.append(actionBar); - } - - // Resize accordion - $('#zvmResourceAccordion').accordion('resize'); -} - -/** - * Open dialog to remove disk from pool - * - * @param disks2remove Disks selected in table - */ -function openRemoveDiskFromPoolDialog(disks2remove) { - // Create form to delete disk from pool - var dialogId = 'zvmDeleteDiskFromPool'; - var deleteDiskForm = $('
                          '); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - - var disks = new Array(); - if (disks2remove.indexOf(',') > -1) - disks = disks2remove.split(','); - else - disks.push(disks2remove); - - // Pick the last zHCP and pool it finds - var args, tgtHcp = "", tgtPool = "", tgtVol = ""; - for (var i in disks) { - if( !disks[i] || 0 === disks[i].length) continue; - args = disks[i].split('-'); - tgtHcp = args[0]; - tgtPool = args[1]; - tgtVol += args[2] + ','; - } - - // Strip out last comma - tgtVol = tgtVol.slice(0, -1); - - // Create info bar - var info = createInfoBar('Remove a disk from a disk pool defined in the EXTENT CONTROL.'); - deleteDiskForm.append(info); - var action = $('
                          '); - var actionSelect = $(''); - action.append(actionSelect); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - - // Set region input based on those selected on table (if any) - var region = $('
                          '); - var group = $('
                          '); - deleteDiskForm.append(action, system, region, group); - - // Append options for hardware control points - //systemSelect.append($('')); - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - systemSelect.val(tgtHcp); - - actionSelect.change(function() { - if ($(this).val() == '1' || $(this).val() == '3') { - region.show(); - group.hide(); - } else if ($(this).val() == '2') { - region.show(); - group.show(); - } else if ($(this).val() == '7') { - region.val('FOOBAR'); - region.hide(); - group.show(); - } - }); - - // Generate tooltips - deleteDiskForm.find('div input[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 delete disk - deleteDiskForm.dialog({ - title:'Delete disk from pool', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 500, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - // Get inputs - var action = $(this).find('select[name=action]').val(); - var system = $(this).find('select[name=system]').val(); - var region = $(this).find('input[name=region]').val(); - var group = $(this).find('input[name=group]').val(); - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'select[name=action]', 'input[name=region]', 'input[name=group]'); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - if (!ready) { - // Show warning message - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - var args; - if (action == '2' || action == '7') - args = region + ';' + group; - else - args = region; - - // Remove disk from pool - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : system, - args : '--removediskfrompool;' + action + ';' + args, - msg : dialogId - }, - - success : updateResourceDialog - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Open dialog to add disk to pool - */ -function openAddDisk2PoolDialog() { - // Create form to add disk to pool - var dialogId = 'zvmAddDisk2Pool'; - var addDiskForm = $('
                          '); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - - // Create info bar - var info = createInfoBar('Add a disk to a disk pool defined in the EXTENT CONTROL. The disk has to already be attached to SYSTEM.'); - addDiskForm.append(info); - var action = $('
                          '); - var actionSelect = $(''); - action.append(actionSelect); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - var volume = $('
                          '); - var group = $('
                          '); - addDiskForm.append(action, system, volume, group); - - // Append options for hardware control points - //systemSelect.append($('')); - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - - // Generate tooltips - addDiskForm.find('div input[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 disk - addDiskForm.dialog({ - title:'Add disk to pool', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 500, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - // Get inputs - var action = $(this).find('select[name=action]').val(); - var system = $(this).find('select[name=system]').val(); - var volume = $(this).find('input[name=volume]').val(); - var group = $(this).find('input[name=group]').val(); - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'select[name=action]', 'input[name=volume]', 'input[name=group]'); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - if (!ready) { - // Show warning message - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - var args; - if (action == '4') - args = volume + ';' + volume + ';' + group; - else - args = volume + ';' + group; - - // Add disk to pool - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : system, - args : '--adddisk2pool;' + action + ';' + args, - msg : dialogId - }, - - success : updateResourceDialog - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Open dialog to remove zFCP from pool - * - * @param devices2remove Comman separated devices selected in table - */ -function openRemoveZfcpFromPoolDialog(devices2remove) { - // Create form to delete device from pool - var dialogId = 'zvmDeleteZfcpFromPool'; - var deleteDiskForm = $('
                          '); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - - // Verify disks are in the same zFCP pool - var devices = devices2remove.split(','); - if (typeof console == "object"){ - console.log("Entering openRemoveZfcpFromPoolDialog. Device to remove:<"+devices2remove+">"); - } - var tmp, tgtPool, tgtHcp; - var tgtPort = ""; - var tgtUnitNo = ""; - for (var i in devices) { - if( !devices[i] || 0 === devices[i].length) continue; - tmp = devices[i].split('-'); - - if (tgtPool && tmp[1] != tgtPool) { - openDialog("warn", "Please select devices in the same zFCP"); - return; - } else { - tgtPool = tmp[1]; - } - - tgtHcp = tmp[0]; // Assume it is just one zHCP. Otherwise, this cannot be done on multiple zHCPs. - tgtUnitNo += tmp[2] + ","; - tgtPort = tmp[3]; - } - - // Strip out last comma - tgtUnitNo = tgtUnitNo.slice(0, -1); - - // Create info bar - var info = createInfoBar('Remove a zFCP device that is defined in a zFCP pool.'); - deleteDiskForm.append(info); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - - var pool = $('
                          '); - var unitNo = $('
                          '); - var portName = $('
                          '); - deleteDiskForm.append(system, pool, unitNo, portName); - - // Append options for hardware control points - //systemSelect.append($('')); - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - systemSelect.val(tgtHcp); - - // Generate tooltips - deleteDiskForm.find('div input[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 delete device - deleteDiskForm.dialog({ - title:'Delete device from pool', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 500, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - var system = $(this).find('select[name=system]').val(); - var pool = $(this).find('input[name=zfcpPool]').val(); - var unitNo = $(this).find('input[name=zfcpUnitNo]').val(); - var portName = $(this).find('input[name=zfcpPortName]').val(); - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'input[name=zfcpPool]', 'input[name=zfcpUnitNo]'); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - if (!ready) { - // Show warning message - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - var args = '--removezfcpfrompool;' + pool + ';' + unitNo; - if (portName) { - args += ';' + portName; - } - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : system, - args : args, - msg : dialogId - }, - - success : function(data) { - updateResourceDialog(data); - } - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Open dialog to add zFCP to pool - */ -function openAddZfcp2PoolDialog() { - // Create form to add disk to pool - var dialogId = 'zvmAddDisk2Pool'; - var addDiskForm = $('
                          '); - var info = createInfoBar('Add a device to a zFCP pool defined in xCAT.'); - addDiskForm.append(info); - - // Obtain mapping for zHCP to zVM system - var hcp2zvm = new Object(); - hcp2zvm = getHcpZvmHash(); - - var system = $('
                          '); - var systemSelect = $(''); - system.append(systemSelect); - - var pool = $('
                          '); - var status = $('
                          '); - var portName = $('
                          '); - var unitNo = $('
                          '); - var size = $('
                          '); - var range = $('
                          '); - var owner = $('
                          '); - addDiskForm.append(system, pool, status, portName, unitNo, size, range, owner); - - // Create a array for hardware control points - //systemSelect.append($('')); - // Append options for hardware control points - for (var hcp in hcp2zvm) { - systemSelect.append($('')); - } - - // Generate tooltips - addDiskForm.find('div input[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 disk - addDiskForm.dialog({ - title:'Add device to pool', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 500, - buttons: { - "Ok": function(){ - // Delete any warning messages - $(this).find('.ui-state-error').remove(); - - var tgtSystem = $(this).find('select[name=system]').val(); - var tgtPool = $(this).find('input[name=zfcpPool]').val(); - var tgtStatus = $(this).find('select[name=zfcpStatus]').val(); - var tgtPortName = $(this).find('input[name=zfcpPortName]').val(); - var tgtUnitNo = $(this).find('input[name=zfcpUnitNo]').val(); - var tgtSize = $(this).find('input[name=zfcpSize]').val(); - var tgtRange = $(this).find('input[name=zfcpRange]').val(); - - // Device owner is optional - var tgtOwner = ""; - if ($(this).find('input[name=zfcpOwner]').val()) { - tgtOwner = $(this).find('input[name=zfcpOwner]').val(); - } - - // If inputs are not complete, show warning message - var ready = true; - var args = new Array('select[name=system]', 'input[name=zfcpPool]', 'select[name=zfcpStatus]', 'input[name=zfcpPortName]', 'input[name=zfcpUnitNo]'); - for (var i in args) { - if (!$(this).find(args[i]).val()) { - $(this).find(args[i]).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); - } - } - - if (!ready) { - // Show warning message - var warn = createWarnBar('Please provide a value for each required field.'); - warn.prependTo($(this)); - return; - } - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - // zFCP range and owner are optional - var args = '--addzfcp2pool||' + tgtPool + '||' + tgtStatus + '||"' + tgtPortName + '"||' + tgtUnitNo + '||' + tgtSize; - if (tgtRange) { - args += '||' + tgtRange; - } if (tgtOwner) { - args += '||' + tgtOwner; - } - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chhypervisor', - tgt : tgtSystem, - args : args, - msg : dialogId - }, - - success : updateResourceDialog - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Update resource dialog - * - * @param data HTTP request data - */ -function updateResourceDialog(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': '90%' - }); - - infoBar.append(icon, msg, close); - infoBar.prependTo($('#' + dialogId)); -} - -/** - * Select all checkboxes in the datatable - * - * @param event Event on element - * @param obj Object triggering event - */ -function selectAllDisk(event, obj) { - // This will ascend from - var tableObj = obj.parents('.datatable'); - var status = obj.attr('checked'); - tableObj.find(' :checkbox').attr('checked', status); - - // Handle datatable scroll - tableObj = obj.parents('.dataTables_scroll'); - if (tableObj.length) { - tableObj.find(' :checkbox').attr('checked', status); - } - - event.stopPropagation(); -} - -/** - * Load network details into a table - * - * @param data HTTP request data - */ -function loadNetworkTable(data) { - // Remove loader if last one - var panelId = 'zvmNetworkResource'; - if (!zhcpQueryCountForNetworks) { - $('#' + panelId).find('img[src="images/loader.gif"]').remove(); - } - - // Get zVM host names - if (!$.cookie('xcat_zvms')) { - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - async: false, - data : { - cmd : 'webportal', - tgt : '', - args : 'lszvm', - msg : '' - }, - - success : function(data) { - setzVMCookies(data); - } - }); - } - - var zvms = $.cookie('xcat_zvms').split(','); - var hcp2zvm = new Object(); - var args, zvm, iHcp, tmp; - for (var i in zvms) { - if( !zvms[i] || 0 === zvms[i].length) continue; - args = zvms[i].split(':'); - zvm = args[0].toLowerCase(); - - if (args[1].indexOf('.') != -1) { - tmp = args[1].split('.'); - iHcp = tmp[0]; - } else { - iHcp = args[1]; - } - - hcp2zvm[iHcp] = zvm; - } - - var args = data.msg.split(';'); - var hcp = args[0].replace('hcp=', ''); - var type = args[1].replace('type=', ''); - var name = jQuery.trim(args[2].replace('network=', '')); - tmp = data.rsp[0].split(hcp + ': '); - - // Resource tab ID - var info = $('#' + panelId).find('.ui-state-highlight'); - // If there is no info bar - if (!info.length) { - // Create info bar - info = createInfoBar('Below are LANs/VSWITCHes available to use.'); - $('#' + panelId).append(info); - } - - // Get datatable - var dTable = getNetworkDataTable(); - if (!dTable) { - // Create table - var tableId = 'zNetworkDataTable'; - var table = new DataTable(tableId); - table.init( [ '', 'z/VM', 'Type', 'Name', 'Layer', 'Owner', 'Controller', 'Details' ]); - - // Append datatable to tab - $('#' + panelId).append(table.object()); - - // Turn into datatable - dTable = $('#' + tableId).dataTable({ - 'iDisplayLength': 50, - "bScrollCollapse": true, - "sScrollY": "400px", - "sScrollX": "110%", - "bAutoWidth": true, - "oLanguage": { - "oPaginate": { - "sNext": "", - "sPrevious": "" - } - } - }); - setNetworkDataTable(dTable); - - // Set the column width - var cols = table.object().find('thead tr th'); - cols.eq(0).css('width', '20px'); // HCP column - cols.eq(1).css('width', '20px'); // Type column - cols.eq(2).css('width', '20px'); // Name column - cols.eq(3).css({'width': '600px'}); // Details column - } - - // Skip index 0 because it contains nothing - var details = '
                          ';
                          -    for ( var i = 1; i < tmp.length; i++) {
                          -        details += tmp[i];
                          -    }
                          -    details += '
                          '; - - // Determine the OSI layer - var layer = "3"; - if (details.indexOf("ETHERNET") != -1) { - layer = "2"; - } - - // Find the vSwitch/VLAN owner - var regex = /(LAN|VSWITCH) (.*?)(?:\s|$)/g; - var owner = ""; - var match = ""; - if (type == "VSWITCH") { - owner = "SYSTEM"; - } else { - owner = regex.exec(details)[2]; - } - - // Find the vSwitch controller - regex = /(?:^|\s)Controller: (.*?)(?:\s|$)/g; - var controllers = ""; - match = ""; - while (match = regex.exec(details)) { - controllers += match[1] + ","; - } - controllers = controllers.substring(0, controllers.length - 1); // Delete last two characters - - dTable.fnAddData(['', '
                          ' + hcp2zvm[hcp] + '
                          ', '
                          ' + type + '
                          ', '
                          ' + name + '
                          ', '
                          ' + layer + '
                          ', '
                          ' + owner + '
                          ', '
                          ' + controllers + '
                          ', details]); - - // Create actions menu - if (!$('#networkResourceActions').length) { - // Empty filter area - $('#' + tableId + '_length').empty(); - - // Add Vswitch/Vlan - var addLnk = $('Add'); - addLnk.bind('click', function(event){ - openAddVswitchVlanDialog(); - }); - - // Remove Vswitch/Vlan - var removeLnk = $('Remove'); - removeLnk.bind('click', function(event){ - var networkList = getNodesChecked(tableId).split(','); - if (networkList) { - openRemoveVswitchVlanDialog(networkList); - } - }); - - // Refresh table - var refreshLnk = $('Refresh'); - refreshLnk.bind('click', function(event){ - $('#zvmNetworkResource').empty().append(createLoader('')); - setNetworkDataTable(''); - - // Create a array for hardware control points - var hcps = new Array(); - if ($.cookie('xcat_hcp').indexOf(',') > -1) - hcps = $.cookie('xcat_hcp').split(','); - else - hcps.push($.cookie('xcat_hcp')); - - // Query networks - zhcpQueryCountForNetworks = hcps.length; - for (var i in hcps) { - if( !hcps[i] || 0 === hcps[i].length) continue; - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : hcps[i], - args : '--getnetworknames', - msg : hcps[i] - }, - - success : getNetwork - }); - zhcpQueryCountForNetworks--; - } - }); - - // Create action bar - var actionBar = $('
                          ').css("width", "450px"); - - // Create an action menu - var actionsMenu = createMenu([addLnk, removeLnk, refreshLnk]); - 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 + '_length').prepend(menuDiv); - $('#' + tableId + '_length').css({ - 'padding': '0px', - 'width': '500px' - }); - $('#' + tableId + '_filter').css('padding', '10px'); - menuDiv.append(actionBar); - } - - // Resize accordion - $('#zvmResourceAccordion').accordion('resize'); -} - -/** - * Connect a NIC to a Guest LAN - * - * @param data Data from HTTP request - */ -function connect2GuestLan(data) { - var rsp = data.rsp; - var args = data.msg.split(';'); - var node = args[0].replace('node=', ''); - var address = args[1].replace('addr=', ''); - var lanName = args[2].replace('lan=', ''); - var lanOwner = args[3].replace('owner=', ''); - - // Write ajax response to status bar - var prg = writeRsp(rsp, node + ': '); - $('#' + node + 'StatusBar').find('div').append(prg); - - // Continue if no errors found - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1) { - // Connect NIC to Guest LAN - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--connectnic2guestlan;' + address + ';' + lanName + ';' - + lanOwner, - msg : node - }, - - success : updateZNodeStatus - }); - } else { - // Hide loader when error - var statusBarLoaderId = node + 'StatusBarLoader'; - $('#' + statusBarLoaderId).hide(); - } -} - -/** - * Connect a NIC to a VSwitch - * - * @param data Data from HTTP request - */ -function connect2VSwitch(data) { - var rsp = data.rsp; - var args = data.msg.split(';'); - var node = args[0].replace('node=', ''); - var address = args[1].replace('addr=', ''); - var vswitchName = args[2].replace('vsw=', ''); - var vswitchAware = args[3].replace('vlanaware=', ''); - var vswitchPortType = args[4].replace('porttype=', ''); - var vswitchLanId = args[5].replace('lanid=', ''); - - // Set variables to empty string if notaware or they contain "default" - if (vswitchAware.toLowerCase() == 'notaware' ) { - vswitchPortType = ''; - vswitchLanId = ''; - } else { - if (vswitchPortType.toLowerCase() == 'default' ) { - vswitchPortType = ''; - } - if (vswitchLanId.toLowerCase() == 'default' ) { - vswitchLanId = ''; - } - } - - // Write ajax response to status bar - var prg = writeRsp(rsp, node + ': '); - $('#' + node + 'StatusBar').find('div').append(prg); - - // Continue if no errors found - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1) { - // Connect NIC to VSwitch - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chvm', - tgt : node, - args : '--connectnic2vswitch;' + address + ';' + vswitchName + ';' - + vswitchPortType + ';' + vswitchLanId, - msg : node - }, - - success : updateZNodeStatus - }); - } else { - // Hide loader when error - var statusBarLoaderId = node + 'StatusBarLoader'; - $('#' + statusBarLoaderId).hide(); - } -} - -/** - * Create provision existing node division - * - * @param inst Provision tab instance - * @return Provision existing node division - */ -function createZProvisionExisting(inst) { - // Create provision existing and hide it - var provExisting = $('
                          ').hide(); - - var vmFS = $('
                          '); - var vmLegend = $('Virtual Machine'); - vmFS.append(vmLegend); - provExisting.append(vmFS); - - var vmAttr = $('
                          '); - vmFS.append($('
                          ')); - vmFS.append(vmAttr); - - var osFS = $('
                          '); - var osLegend = $('Operating System'); - osFS.append(osLegend); - provExisting.append(osFS); - - var osAttr = $('
                          '); - osFS.append($('
                          ')); - osFS.append(osAttr); - - // Create group input - var group = $('
                          '); - var groupLabel = $(''); - group.append(groupLabel); - - // Turn on auto complete for group - 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) { - if( !tmp[i] || 0 === tmp[i].length) continue; - // 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, 'zNodesDatatableDIV' + inst); - } - }); - } else { - // If no groups are cookied - var groupInput = $(''); - group.append(groupInput); - } - vmAttr.append(group); - - // Create node input - var node = $('
                          '); - var nodeLabel = $(''); - var nodeDatatable = $('

                          Select a group to view its nodes

                          '); - node.append(nodeLabel); - node.append(nodeDatatable); - vmAttr.append(node); - - // Create operating system image input - var os = $('
                          '); - var osLabel = $(''); - var osSelect = $(''); - osSelect.append($('')); - - var imageNames = $.cookie('xcat_imagenames').split(','); - if (imageNames) { - imageNames.sort(); - for (var i in imageNames) { - if( !imageNames[i] || 0 === imageNames[i].length) continue; - osSelect.append($('')); - } - } - os.append(osLabel); - os.append(osSelect); - osAttr.append(os); - - // Create boot method drop down - var bootMethod = $('
                          '); - var methoddLabel = $(''); - var methodSelect = $(''); - methodSelect.append('' - + '' - + '' - + '' - + '' - ); - bootMethod.append(methoddLabel); - bootMethod.append(methodSelect); - osAttr.append(bootMethod); - - // Generate tooltips - provExisting.find('div input[title],select[title]').tooltip({ - position: "center right", - offset: [-2, 10], - effect: "fade", - opacity: 0.7, - predelay: 800, - events: { - def: "mouseover,mouseout", - input: "mouseover,mouseout", - widget: "focus mouseover,blur mouseout", - tooltip: "mouseover,mouseout" - } - }); - - /** - * Provision existing - */ - var provisionBtn = createButton('Provision'); - provisionBtn.bind('click', function(event) { - // Remove any warning messages - $(this).parent().parent().find('.ui-state-error').remove(); - - var ready = true; - var errMsg = ''; - - // Get provision tab ID - var thisTabId = $(this).parent().parent().parent().attr('id'); - // Get provision tab instance - var inst = thisTabId.replace('zvmProvisionTab', ''); - - // Get nodes that were checked - var dTableId = 'zNodesDatatable' + inst; - var tgts = getNodesChecked(dTableId); - if (!tgts) { - errMsg += 'You need to select a node.
                          '; - ready = false; - } - - // Check operating system image - var os = $('#' + thisTabId + ' select[name=os]:visible'); - if (!os.val()) { - errMsg += 'You need to select a operating system image.'; - os.css('border', 'solid #FF0000 1px'); - ready = false; - } else { - os.css('border', 'solid #BDBDBD 1px'); - } - - // If all inputs are valid, ready to provision - if (ready) { - // Disable provision button - $(this).attr('disabled', 'true'); - - // Show loader - $('#zProvisionStatBar' + inst).show(); - $('#zProvisionLoader' + inst).show(); - - // Disable all inputs - var inputs = $('#' + thisTabId + ' input:visible'); - inputs.attr('disabled', 'disabled'); - - // Disable all selects - var selects = $('#' + thisTabId + ' select'); - selects.attr('disabled', 'disabled'); - - // Get operating system image - var osImage = $('#' + thisTabId + ' select[name=os]:visible').val(); - var tmp = osImage.split('-'); - var os = tmp[0]; - var arch = tmp[1]; - var profile = tmp[3]; - - /** - * (1) Set operating system - */ - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodeadd', - tgt : '', - args : tgts + ';noderes.netboot=zvm;nodetype.os=' + os + ';nodetype.arch=' + arch + ';nodetype.profile=' + profile, - msg : 'cmd=nodeadd;out=' + inst - }, - - success : updateZProvisionExistingStatus - }); - } else { - // Show warning message - var warn = createWarnBar(errMsg); - warn.prependTo($(this).parent().parent()); - } - }); - provExisting.append(provisionBtn); - - return provExisting; -} - -/** - * Create provision new node division - * - * @param inst Provision tab instance - * @return Provision new node division - */ -function createZProvisionNew(inst) { - if (typeof console == "object"){ - console.log("Entering createZProvisionNew. Inst value:"+inst); - } - // Create provision new node division - var provNew = $('
                          '); - - // Create VM fieldset - var vmFS = $('
                          '); - var vmLegend = $('Virtual Machine'); - vmFS.append(vmLegend); - provNew.append(vmFS); - - var vmAttr = $('
                          '); - vmFS.append($('
                          ')); - vmFS.append(vmAttr); - - // Create OS fieldset - var osFS = $('
                          '); - var osLegend = $('Operating System'); - osFS.append(osLegend); - provNew.append(osFS); - - // Create hardware fieldset - var hwFS = $('
                          '); - var hwLegend = $('Hardware'); - hwFS.append(hwLegend); - provNew.append(hwFS); - - var hwAttr = $('
                          '); - hwFS.append($('
                          ')); - hwFS.append(hwAttr); - - // Create tabs for basic and advanced hardware configuration - var hwTab = new Tab('hwConfig' + inst); - hwTab.init(); - hwAttr.append(hwTab.object()); - - var osAttr = $('
                          '); - osFS.append($('
                          ')); - osFS.append(osAttr); - - // Create group input - var group = $('
                          '); - var groupLabel = $(''); - var groupInput = $(''); - // Get groups on-focus - 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); - vmAttr.append(group); - - // Create node input - var nodeName = $('
                          '); - var nodeLabel = $(''); - var nodeInput = $(''); - nodeName.append(nodeLabel); - nodeName.append(nodeInput); - vmAttr.append(nodeName); - - // Create user ID input - var userId = $('
                          '); - vmAttr.append(userId); - - // Create hardware control point input - var hcpDiv = $('
                          '); - var hcpNodeLabel = $(''); - var hcpNodeInput = $(''); - var hcpHiddenInput = $(''); - hcpNodeInput.blur(function() { - - if (typeof console == "object") { - console.log("Display loading bar "); - } - // Show the status bar with a message and loading gif - $('#'+'zProvisionStatBar'+inst).find('div').append("Loading zhcp information..."); - $('#'+'zProvisionStatBar'+inst).find('div').append(""); - $('#'+'zProvisionStatBar'+inst).show(); - - // list of calls after the zhcp is verified. Used to determine when in progress gif is to be removed. - var ajaxCalls = {"diskpoolnames":1, "zfcppoolnames":1, "userprofilenames":1}; - var zhcpToCheck = $(this).val(); - var zhcpField = $(this); - var provisionStatusBar = $('#'+'zProvisionStatBar'+inst); - - // Make sure border is set back to black - zhcpField.css('border', 'solid #BDBDBD 1px'); - - if ($(this).val()) { - // Check if this is a valid node by making network names call. - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : zhcpToCheck, - args : '--getnetworknames', - msg : zhcpToCheck - }, - - success: function(data) { - if (data.rsp.length && (data.rsp[0].indexOf("Failed") > -1 || data.rsp[0].indexOf("Invalid") > -1 || data.rsp[0].indexOf("Error") > -1) ) { - // Remove the progress gif, since bailing out - removeProvisionLoadingGif(provisionStatusBar); - - // Create warning dialog - var warning = createWarnBar('Failure getting network data for hardware control point ' + zhcpToCheck + '
                          The hcp field must be a xCAT node name.'); - var warnDialog = $('
                          ').append(warning); - - // highlight the hcp field - zhcpField.css('border', 'solid #FF0000 1px'); - - // Open warning dialog - warnDialog.dialog({ - title:'Warning', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function() { - $(this).dialog("close"); - } - } - }); - - } else { - // Node is good, now set some cookies from network, then check/set other cookies - setNetworkCookies(data); - - // Get the HCP name from the hcp node name - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsdef', - tgt : '', - args : zhcpToCheck, - msg : 'zhcpFullName' - }, - - success: function(data) { - if (data.rsp.length && (data.rsp[0].indexOf("Failed") > -1 || data.rsp[0].indexOf("Invalid") > -1) ) { - // Remove the progress gif, since bailing out - removeProvisionLoadingGif(provisionStatusBar); - - // Create warning dialog - var warning = createWarnBar('Failure getting hcp data from hardware control point ' + zhcpToCheck + '
                          The hcp field must be a valid xCAT node name.'); - var warnDialog = $('
                          ').append(warning); - - // highlight the hcp field - zhcpField.css('border', 'solid #FF0000 1px'); - - // Open warning dialog - warnDialog.dialog({ - title:'Warning', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function() { - $(this).dialog("close"); - } - } - }); - } else { - // Now set the hidden hcp field with the full name - // Clear hash table containing definable node attributes - nodeAttrs = new Array(); - - // Get definable attributes - // Data returned - var rsp = data.rsp; - // Group name - var group = data.msg; - // Hash of node attributes - var attrs = new Object(); - - // Go through each attribute - var node, args; - for (var i in rsp) { - // Get node name, skip processing - if (rsp[i].indexOf('Object name:') > -1) { - i++; - } - - // Get key and value - args = rsp[i].split('=', 2); - var key = jQuery.trim(args[0]); - var val = jQuery.trim(rsp[i].substring(rsp[i].indexOf('=') + 1, rsp[i].length)); - - // If this is zhcp key then save full name in hidden field - if (key == "hcp") { - hcpHiddenInput.val(val); - } - - } - - } - } - }); - - if (typeof console == "object"){ - console.log("Looking for cookies from <" + zhcpToCheck + ">"); - } - - if (!$.cookie('xcat_' + zhcpToCheck + 'diskpools')) { - // Get disk pools - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : zhcpToCheck, - args : '--diskpoolnames', - msg : zhcpToCheck - }, - - success : setDiskPoolCookies, - complete : function() { - checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "diskpoolnames"); - } - }); - } else { - checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "diskpoolnames"); - } - - if (!$.cookie('xcat_' + zhcpToCheck + 'zfcppools')) { - // Get zFCP pools - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : zhcpToCheck, - args : '--zfcppoolnames', - msg : zhcpToCheck - }, - - success : setZfcpPoolCookies, - complete : function() { - checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "zfcppoolnames"); - } - }); - } else { - checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "zfcppoolnames"); - } - - if (!$.cookie('xcat_' + zhcpToCheck + 'userprofiles')) { - // Get zFCP pools - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - async: false, - data : { - cmd : 'lsvm', - tgt : zhcpToCheck, - args : '--userprofilenames', - msg : zhcpToCheck - }, - - success : setUserProfilesCookies, - complete : function() { - checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "userprofilenames"); - } - }); - } else { - checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "userprofilenames"); - } - - // Reset user profile and network drop down box - var thisTabId = zhcpField.parents('.tab').attr('id'); - var thisUserProfile = $('#' + thisTabId + ' select[name=userProfile]'); - thisUserProfile.children().remove(); - - var definedUserProfiles = $.cookie('xcat_' + zhcpToCheck + 'userprofiles').split(','); - for (var i in definedUserProfiles) { - if( !definedUserProfiles[i] || 0 === definedUserProfiles[i].length) continue; - thisUserProfile.append(''); - } - - var thisNetwork = $('#' + thisTabId + ' select[name=network]'); - thisNetwork.children().remove(); - thisNetwork.append(''); // No profile option - var definedNetworks = $.cookie('xcat_' + zhcpToCheck + 'networks').split(','); - for (var i in definedNetworks) { - if( !definedNetworks[i] || 0 === definedNetworks[i].length) continue; - if (!jQuery.trim(definedNetworks[i])) - continue; - - var directoryEntry, interfaceName; - - // Generate directory entry statement for vSwitch, hipersocket, and guest LAN - if (definedNetworks[i].indexOf('VSWITCH ') != -1) { - interfaceName = jQuery.trim(definedNetworks[i].replace('VSWITCH ', '')); - directoryEntry = "TYPE QDIO LAN " + interfaceName; - } else if (definedNetworks[i].indexOf('LAN:HIPERS ') != -1) { - interfaceName = jQuery.trim(definedNetworks[i].replace('LAN:HIPERS ', '')); - directoryEntry = "TYPE HIPERSOCKETS LAN " + interfaceName; - } else { - interfaceName = jQuery.trim(definedNetworks[i].replace('LAN:QDIO ', '')); - directoryEntry = "TYPE QDIO LAN " + interfaceName; - } - - thisNetwork.append(''); - } - - // Update user entry on change - thisNetwork.change(function() { - updateUserEntry(thisTabId); - }); - - thisUserProfile.change(function() { - updateUserEntry(thisTabId); - }); - } - } - }); - } - }); - hcpDiv.append(hcpNodeLabel); - hcpDiv.append(hcpNodeInput); - hcpDiv.append(hcpHiddenInput); - vmAttr.append(hcpDiv); - - // Create an advanced link to set IP address and hostname - var advancedLnk = $(''); - vmAttr.append(advancedLnk); - var advanced = $('
                          ').hide(); - vmAttr.append(advanced); - - var ip = $('
                          '); - advanced.append(ip); - var hostname = $('
                          '); - advanced.append(hostname); - - // Show IP address and hostname inputs on-click - advancedLnk.click(function() { - advanced.toggle(); - }); - - // Create operating system image input - var os = $('
                          '); - var osLabel = $(''); - var osSelect = $(''); - osSelect.append($('')); - - var imageNames = $.cookie('xcat_imagenames').split(','); - if (imageNames) { - imageNames.sort(); - for (var i in imageNames) { - if( !imageNames[i] || 0 === imageNames[i].length) continue; - osSelect.append($('')); - } - } - os.append(osLabel); - os.append(osSelect); - osAttr.append(os); - - // Create user entry input - var defaultChkbox = $('').click(function() { - // Remove any warning messages - $(this).parents('.form').find('.ui-state-error').remove(); - - // Get tab Id - var thisTabId = $(this).parents('.ui-tabs-panel').parents('.ui-tabs-panel').attr('id'); - - // Get objects for HCP, user ID, and OS - var userId = $('#' + thisTabId + ' input[name=userId]'); - var os = $('#' + thisTabId + ' select[name=os]'); - - // Get default user entry when clicked - if ($(this).attr('checked')) { - if (!os.val() || !userId.val()) { - // Show warning message - var warn = createWarnBar('Please specify the operating system and user ID before checking this box'); - warn.prependTo($(this).parents('.form')); - - // Highlight empty fields - jQuery.each([os, userId], function() { - if (!$(this).val()) { - $(this).css('border', 'solid #FF0000 1px'); - } - }); - } else { - // Un-highlight empty fields - jQuery.each([os, userId], function() { - $(this).css('border', 'solid #BDBDBD 1px'); - }); - - // Get profile name - var tmp = os.val().split('-'); - var profile = tmp[3]; - - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'getdefaultuserentry;' + profile, - msg : thisTabId - }, - - success:function(data) { - // Populate user entry - var tabId = data.msg; - var entry = new String(data.rsp); - var userId = $('#' + tabId + ' input[name=userId]').val(); - entry = entry.replace(new RegExp('LXUSR', 'g'), userId); - $('#' + tabId + ' textarea:visible').val(entry); - } - }); - } - } else { - $('#' + thisTabId + ' textarea:visible').val(''); - - // Un-highlight empty fields - jQuery.each([os, userId], function() { - $(this).css('border', 'solid #BDBDBD 1px'); - }); - } - }); - var userEntry = $('
                          '); - userEntry.append($('').append(defaultChkbox, 'Use default')); - - // Add division on basic tab for specifying: memory, # of CPUs, privilege, user profile, and network. - var basicConfig = $('
                          '); - var userProfile = $('
                          '); - var cpuSelect = $('').change(function() { - updateUserEntry('zvmProvisionTab' + inst); - }); - var cpuCount = $('
                          ').append(cpuSelect); - var memorySlider = $('
                          '); - var memorySize = $(''); - var memory = $('
                          ').append(memorySlider, memorySize); - var acceptableMemorySize = ['512M', '1024M', '2G', '3G', '4G', '5G', '6G', '7G', '8G']; - memorySlider.slider({ - value: 0, - min: 0, - max: 8, - step: 1, - slide: function(event, ui) { - $('#basicConfig' + inst + ' input[name=memory]').val(acceptableMemorySize[ui.value]); - - // Update user entry on change - updateUserEntry('zvmProvisionTab' + inst); - } - }); - - // Initialize storage size - memorySize.val(acceptableMemorySize[0]); - - var privilege = $('
                          ' + - '
                          ' + - ' A - Primary system operator
                          ' + - ' B - System resource operator
                          ' + - ' C - System programmer
                          ' + - ' D - Spooling operator
                          ' + - ' E - System analyst
                          ' + - ' F - IBM service representative
                          ' + - ' G - General user
                          ' + - '
                          ' + - '
                          '); - privilege.find('input').change(function() { - updateUserEntry('zvmProvisionTab' + inst); - }); - - var network = $('
                          '); - - var vswitchvlan = $('

                          ' + - '
                          ' + - '
                          '); - vswitchvlan.find('input').change(function() { - updateUserEntry('zvmProvisionTab' + inst); - }); - vswitchvlan.find('select').change(function() { - updateUserEntry('zvmProvisionTab' + inst); - }); - - vswitchvlan.hide(); - basicConfig.append(userProfile, cpuCount, memory, privilege, network, vswitchvlan); - hwTab.add('basicConfig' + inst, 'Basic', basicConfig, false); - - // Add division on advanced tab for specifying user directory entry - hwTab.add('advancedConfig' + inst, 'Advanced', userEntry, false); - - // Create disk table - var diskDiv = $('
                          '); - var diskLabel = $(''); - var diskTable = $('
                          '); - var diskHeader = $(' Type Address Size Mode Pool Password IPLNone
                          '); - // Adjust header width - diskHeader.find('th').css( { - 'width' : '80px' - }); - diskHeader.find('th').eq(0).css( { - 'width' : '20px' - }); - var diskBody = $(''); - var diskFooter = $(''); - - /** - * Add disks - */ - var addDiskLink = $('Add disk'); - addDiskLink.bind('click', function(event) { - // Get list of disk pools - var thisTabId = $(this).parents('.tab').attr('id'); - var thisHcp = $('#' + thisTabId + ' input[name=hcp]').val(); - var definedPools = null; - if (thisHcp) { - // Get node without domain name - var temp = thisHcp.split('.'); - definedPools = $.cookie('xcat_' + temp[0] + 'diskpools').split(','); - } else { - var warning = createWarnBar('You must fill in a hardware control point before adding a disk.'); - var warnDialog = $('
                          ').append(warning); - - // Open dialog - warnDialog.dialog({ - title:'Warning', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function() { - $(this).dialog("close"); - } - } - }); - return false; - } - - // Create a row - var diskRow = $(''); - - // Add remove button - var removeBtn = $(''); - var col = $('').append(removeBtn); - removeBtn.bind('click', function(event) { - diskRow.remove(); - }); - diskRow.append(col); - - // Create disk type drop down - var diskType = $(''); - var diskTypeSelect = $(''); - diskTypeSelect.append('' - + '' - ); - diskType.append(diskTypeSelect); - diskRow.append(diskType); - - // Create disk address input - var diskAddr = $(''); - diskRow.append(diskAddr); - - // Create disk size input - var diskSize = $(''); - diskRow.append(diskSize); - - // Create disk mode input - var diskMode = $(''); - var diskModeSelect = $(''); - diskModeSelect.append('' - + '' - + '' - + '' - + '' - + '' - + '' - ); - diskMode.append(diskModeSelect); - diskRow.append(diskMode); - - // Create disk pool drop down - var diskPool = $(''); - var diskPoolSelect = $(''); - for (var i in definedPools) { - diskPoolSelect.append(''); - } - diskPool.append(diskPoolSelect); - diskRow.append(diskPool); - - // Create disk password input - var diskPw = $(''); - diskRow.append(diskPw); - - // Create IPL checkbox - //var diskIpl = $(''); - var diskIpl = $(''); - diskRow.append(diskIpl); - diskIpl.find('input').change(function() { - updateUserEntry(thisTabId); - }); - - diskBody.append(diskRow); - - // Generate tooltips - diskBody.find('td input[title],select[title]').tooltip({ - position: "top right", - offset: [-4, 4], - effect: "fade", - opacity: 0.7, - predelay: 800, - events: { - def: "mouseover,mouseout", - input: "mouseover,mouseout", - widget: "focus mouseover,blur mouseout", - tooltip: "mouseover,mouseout" - } - }); - }); - - // Create disk table - diskFooter.append(addDiskLink); - diskTable.append(diskHeader); - diskTable.append(diskBody); - diskTable.append(diskFooter); - - diskDiv.append(diskLabel); - diskDiv.append(diskTable); - hwAttr.append(diskDiv); - - // Create zFCP table - var zfcpDiv = $('
                          '); - var zfcpLabel = $(''); - var zfcpTable = $('
                          '); - var zfcpHeader = $(' Address Size Pool Tag Port Name Unit # LOADDEV'); - // Adjust header width - zfcpHeader.find('th').css({ - 'width' : '80px' - }); - zfcpHeader.find('th').eq(0).css({ - 'width' : '20px' - }); - var zfcpBody = $(''); - var zfcpFooter = $(''); - - /** - * Add zFCP devices - */ - var addZfcpLink = $('Add zFCP'); - addZfcpLink.bind('click', function(event) { - // Get list of disk pools - var thisTabId = $(this).parents('.tab').attr('id'); - var thisHcp = $('#' + thisTabId + ' input[name=hcp]').val(); - var definedPools = null; - if (thisHcp) { - // Get node without domain name - var temp = thisHcp.split('.'); - definedPools = $.cookie('xcat_' + temp[0] + 'zfcppools').split(','); - } else { - var warning = createWarnBar('You must fill in a hardware control point before adding a zFCP.'); - var warnDialog = $('
                          ').append(warning); - - // Open dialog - warnDialog.dialog({ - title:'Warning', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function() { - $(this).dialog("close"); - } - } - }); - - } - - // Create a row - var zfcpRow = $(''); - - // Add remove button - var removeBtn = $(''); - var col = $('').append(removeBtn); - removeBtn.bind('click', function(event) { - zfcpRow.remove(); - }); - zfcpRow.append(col); - - // Create disk address input - var zfcpAddr = $(''); - zfcpRow.append(zfcpAddr); - - // Create disk size input - var zfcpSize = $(''); - zfcpRow.append(zfcpSize); - - // Create zFCP pool drop down - var zfcpPool = $(''); - var zfcpPoolSelect = $(''); - for (var i in definedPools) { - zfcpPoolSelect.append(''); - } - zfcpPool.append(zfcpPoolSelect); - zfcpRow.append(zfcpPool); - - // Create disk tag - var zfcpTag = $(''); - zfcpRow.append(zfcpTag); - - // Create device port name - var zfcpPortName = $(''); - zfcpRow.append(zfcpPortName); - - // Create device unit number - var zfcpUnitNo = $(''); - zfcpRow.append(zfcpUnitNo); - - // Create LOADDEV radio button - var zfcpLoaddev = $(''); - zfcpRow.append(zfcpLoaddev); - - zfcpBody.append(zfcpRow); - - // Generate tooltips - zfcpBody.find('td input[title],select[title]').tooltip({ - position: "top right", - offset: [-4, 4], - effect: "fade", - opacity: 0.7, - predelay: 800, - events: { - def: "mouseover,mouseout", - input: "mouseover,mouseout", - widget: "focus mouseover,blur mouseout", - tooltip: "mouseover,mouseout" - } - }); - }); - - zfcpFooter.append(addZfcpLink); - zfcpTable.append(zfcpHeader); - zfcpTable.append(zfcpBody); - zfcpTable.append(zfcpFooter); - - zfcpDiv.append(zfcpLabel); - zfcpDiv.append(zfcpTable); - hwAttr.append(zfcpDiv); - - // Generate tooltips - provNew.find('div input[title],select[title],textarea[title]').tooltip({ - position: "center right", - offset: [-2, 10], - effect: "fade", - opacity: 0.7, - predelay: 800, - events: { - def: "mouseover,mouseout", - input: "mouseover,mouseout", - widget: "focus mouseover,blur mouseout", - tooltip: "mouseover,mouseout" - } - }); - - // Disable IPL column if advanced tab is selected - hwTab.object().tabs({ - select: function(event, ui) { - // Get provision tab instance - var thisTabId = $(this).parents('.ui-tabs-panel').attr('id'); - var inst = thisTabId.replace('zvmProvisionTab', ''); - - // Disable and de-select IPL device - if (ui.index == 1) { - $('#' + thisTabId + ' table:eq(0):visible tbody tr td:nth-child(8) input').attr('disabled','disabled'); - } else { - $('#' + thisTabId + ' table:eq(0):visible tbody tr td:nth-child(8) input').removeAttr('disabled'); - } - - $('#' + thisTabId + ' table:eq(0):visible tbody tr td:nth-child(8) input').removeAttr('checked'); - } - }); - - /** - * Provision new - */ - var provisionBtn = createButton('Provision'); - provisionBtn.bind('click', function(event) { - // Remove any warning messages - $(this).parent().parent().find('.ui-state-error').remove(); - - var ready = true; - var errMsg = ''; - - // Get tab ID - var thisTabId = $(this).parents('.ui-tabs-panel').attr('id'); - // Get provision tab instance - var inst = thisTabId.replace('zvmProvisionTab', ''); - - // Get the selected hardware configuration tab - // Basic tab index = 0 & advanced tab index = 1 - var hwTabIndex = $("#hwConfig" + inst).tabs('option', 'selected'); - - // Check node name, userId, hardware control point, and group - // Check disks and zFCP devices - var inputs = $('#' + thisTabId + ' input:visible'); - for (var i = 0; i < inputs.length; i++) { - // Do not check some inputs - if (inputs.eq(i).attr('name') == 'memory') { - // There should always be a value for memory - // Do not change the border - continue; - } else if (!inputs.eq(i).val() - && inputs.eq(i).attr('type') != 'password' - && inputs.eq(i).attr('name') != 'zfcpTag' - && inputs.eq(i).attr('name') != 'zfcpPortName' - && inputs.eq(i).attr('name') != 'zfcpUnitNo') { - inputs.eq(i).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - inputs.eq(i).css('border', 'solid #BDBDBD 1px'); - } - } - - var selects = $('#' + thisTabId + ' select:visible'); - for (var i = 0; i < selects.length; i++) { - if (!selects.eq(i).val() && selects.eq(i).attr('name') != 'os' && selects.eq(i).attr('name') != 'userProfile' && selects.eq(i).attr('name') != 'network') { - selects.eq(i).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - selects.eq(i).css('border', 'solid #BDBDBD 1px'); - } - } - - if (hwTabIndex == 1) { - // Check user entry - var thisUserEntry = $('#' + thisTabId + ' textarea:visible'); - thisUserEntry.val(thisUserEntry.val().toUpperCase()); - if (!thisUserEntry.val()) { - thisUserEntry.css('border', 'solid #FF0000 1px'); - ready = false; - } else { - thisUserEntry.css('border', 'solid #BDBDBD 1px'); - } - - // Check if user entry contains user ID - var thisUserId = $('#' + thisTabId + ' input[name=userId]:visible'); - var pos = thisUserEntry.val().indexOf('USER ' + thisUserId.val().toUpperCase()); - if (pos < 0) { - - pos = thisUserEntry.val().indexOf('IDENTITY ' + thisUserId.val().toUpperCase()); - if (pos < 0) { - errMsg = errMsg + 'The directory entry does not contain the correct user/identity ID.
                          '; - ready = false; - } - } - } - var hostnameCheck = $('#' + thisTabId + ' input[name=hostname]').val(); - if (hostnameCheck.length > 70) { - errMsg = errMsg + 'The host name cannot be longer than 70 characters.
                          '; - $('#' + thisTabId + ' input[name=hostname]').css('border', 'solid #FF0000 1px'); - ready = false; - } - - // Show error message for missing inputs - if (!ready) { - errMsg = errMsg + 'Please provide a value for each missing field.
                          '; - } - - // If no operating system is specified, create only user entry - os = $('#' + thisTabId + ' select[name=os]:visible'); - - // Check number of disks - var diskRows = $('#' + thisTabId + ' table tr'); - // If an OS is given, disks are needed - if (os.val() && (diskRows.length < 1)) { - errMsg = errMsg + 'You need to add at some disks.
                          '; - ready = false; - } - - // If this is basic mode, check for a disk with IPL radio button and zFCP with LOADDEV button - // Cannot have both. (In advanced mode they create the directory entries.) - if (hwTabIndex == 0) { - // Find a device to be IPLed? - var ECKD_FBA_diskRows = $('#' + thisTabId + ' table:eq(0):visible tbody tr'); - var iplSet = 0; - for (var i = 0; i < ECKD_FBA_diskRows.length; i++) { - var diskArgs = ECKD_FBA_diskRows.eq(i).find('td'); - if (diskArgs.eq(7).find('input').attr("checked") === true) { - iplSet = 1; - break; - } - } - - // Check if zFCP loaddev checked - var zfcpRows = $('#' + thisTabId + ' table:eq(1):visible tbody tr'); - if (zfcpRows.length > 0) { - for ( var i = 0; i < zfcpRows.length; i++) { - var diskArgs = zfcpRows.eq(i).find('td'); - // This is either true or false - var loaddev = diskArgs.eq(7).find('input').attr('checked'); - if (loaddev && iplSet) { - errMsg = errMsg + 'You cannot have both disk IPL and zFCP LOADDEV, can only IPL one device.
                          '; - ready = false; - } - } - } - } - - // If inputs are valid, ready to provision - if (ready) { - // Generate user directory entry if basic tab is selected - if (hwTabIndex == 0) { - updateUserEntry(thisTabId); - } - - if (!os.val()) { - // If no OS is given, create a virtual server - var msg = ''; - if (diskRows.length > 0) { - msg = 'Do you want to create a virtual server without an operating system?'; - } else { - // If no disks are given, create a virtual server (no disk) - msg = 'Do you want to create a virtual server without an operating system or disks?'; - } - - // Open dialog to confirm - var confirmDialog = $('

                          ' + msg + '

                          '); - confirmDialog.dialog({ - title:'Confirm', - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Ok": function(){ - // Disable provision button - provisionBtn.attr('disabled', 'true'); - - // Show loader - $('#zProvisionStatBar' + inst).show(); - $('#zProvisionLoader' + inst).show(); - - // Disable add disk button - addDiskLink.attr('disabled', 'true'); - - // Disable close button on disk table - $('#' + thisTabId + ' table span').unbind('click'); - - // Disable all inputs - var inputs = $('#' + thisTabId + ' input'); - inputs.attr('disabled', 'disabled'); - - // Disable all selects - var selects = $('#' + thisTabId + ' select'); - selects.attr('disabled', 'disabled'); - - // Add a new line at the end of the user entry - var textarea = $('#' + thisTabId + ' textarea'); - var tmp = jQuery.trim(textarea.val()); - textarea.val(tmp + '\n'); - textarea.attr('readonly', 'readonly'); - textarea.css( { - 'background-color' : '#F2F2F2' - }); - - // Get node name - var node = $('#' + thisTabId + ' input[name=nodeName]').val(); - // Get userId - var userId = $('#' + thisTabId + ' input[name=userId]').val(); - // Get hardware control point - var hcp = $('#' + thisTabId + ' input[name=hcp]').val(); - // Get group - var group = $('#' + thisTabId + ' input[name=group]').val(); - // Get IP address and hostname - var ip = $('#' + thisTabId + ' input[name=ip]').val(); - var hostname = $('#' + thisTabId + ' input[name=hostname]').val(); - - // Generate arguments to sent - var args = node + ';zvm.hcp=' + hcp - + ';zvm.userid=' + userId - + ';nodehm.mgt=zvm' - + ';groups=' + group; - if (ip) - args += ';hosts.ip=' + ip; - - if (hostname) - args += ';hosts.hostnames=' + hostname; - - /** - * (1) Define node - */ - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodeadd', - tgt : '', - args : args, - msg : 'cmd=nodeadd;out=' + inst - }, - - success : updateZProvisionNewStatus - }); - - $(this).dialog("close"); - }, - "Cancel": function() { - $(this).dialog("close"); - } - } - }); - } else { - /** - * Create a virtual server and install OS - */ - - // Disable provision button - $(this).attr('disabled', 'true'); - - // Show loader - $('#zProvisionStatBar' + inst).show(); - $('#zProvisionLoader' + inst).show(); - - // Disable add disk button - addDiskLink.attr('disabled', 'true'); - - // Disable close button on disk table - $('#' + thisTabId + ' table span').unbind('click'); - - // Disable all inputs - var inputs = $('#' + thisTabId + ' input'); - inputs.attr('disabled', 'disabled'); - inputs.css( { - 'background-color' : '#F2F2F2' - }); - - // Disable all selects - var selects = $('#' + thisTabId + ' select'); - selects.attr('disabled', 'disabled'); - selects.css( { - 'background-color' : '#F2F2F2' - }); - - // Add a new line at the end of the user entry - var textarea = $('#' + thisTabId + ' textarea'); - var tmp = jQuery.trim(textarea.val()); - textarea.val(tmp + '\n'); - textarea.attr('readonly', 'readonly'); - textarea.css( { - 'background-color' : '#F2F2F2' - }); - - // Get node name - var node = $('#' + thisTabId + ' input[name=nodeName]').val(); - // Get userId - var userId = $('#' + thisTabId + ' input[name=userId]').val(); - // Get hardware control point - var hcp = $('#' + thisTabId + ' input[name=hcp]').val(); - // Get group - var group = $('#' + thisTabId + ' input[name=group]').val(); - // Get IP address and hostname - var ip = $('#' + thisTabId + ' input[name=ip]').val(); - var hostname = $('#' + thisTabId + ' input[name=hostname]').val(); - - // Generate arguments to sent - var args = node + ';zvm.hcp=' + hcp - + ';zvm.userid=' + userId - + ';nodehm.mgt=zvm' - + ';groups=' + group; - if (ip) - args += ';hosts.ip=' + ip; - - if (hostname) - args += ';hosts.hostnames=' + hostname; - - /** - * (1) Define node - */ - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodeadd', - tgt : '', - args : args, - msg : 'cmd=nodeadd;out=' + inst - }, - - success : updateZProvisionNewStatus - }); - } - } else { - // Show warning message - var warn = createWarnBar(errMsg); - warn.prependTo($(this).parent().parent()); - } - }); - provNew.append(provisionBtn); - - return provNew; -} -/** - * Remove zprovision loading gif for zhcp and message - * - * @param division holding the gif and message - */ -function removeProvisionLoadingGif(provisionStatBar) { - - // Only remove the status bar message and gif we added, then hide the status bar - var items = provisionStatBar.find('div').children(); - for (var i = 0; i< items.length; i++) { - var nname = items[i].nodeName; - var myid = items[i].id; - if (nname == "B" && myid == "loadzhcp") { - items[i].remove() - } else if (nname == "IMG" && myid == "loadingpic") { - items[i].remove(); - } - } - provisionStatBar.hide(); -} - -/** - * Set hash entry to 0 and check if all are 0. If so call - * removeProvisionLoadingGif - * - * @param division holding the gif and message, and hash, and - * key - */ -function checkProvisionCallsDone(provisionStatBar, table, finishedKey) { - - table[finishedKey] = 0; - - for (var key in table) { - if (table[key] == 1) { - return; // More to do - } - } - - removeProvisionLoadingGif(provisionStatBar); -} - -/** - * Load zVMs into column (service page) - * - * @param col Table column where OS images will be placed - */ -function loadzVMs(col) { - // Get group names and description and append to group column - if (!$.cookie('xcat_zvms')) { - var infoBar = createInfoBar('No selectable z/VM available'); - col.append(infoBar); - return; - } - - var zNames = $.cookie('xcat_zvms').split(','); - - var radio, zBlock, args, zvm, hcp; - for (var i in zNames) { - if( !zNames[i] || 0 === zNames[i].length) continue; - args = zNames[i].split(':'); - zvm = args[0]; - hcp = args[1]; - - // Create block for each group - zBlock = $('
                          ').css({ - 'border': '1px solid', - 'max-width': '200px', - 'margin': '5px auto', - 'padding': '5px', - 'display': 'block', - 'vertical-align': 'middle', - 'cursor': 'pointer', - 'white-space': 'normal' - }).click(function(){ - $(this).children('input:radio').attr('checked', 'checked'); - $(this).parents('td').find('div').attr('class', 'ui-state-default'); - $(this).attr('class', 'ui-state-active'); - }); - radio = $('').css('display', 'none'); - zBlock.append(radio, $('' + zvm + ' managed by ' + hcp + '')); - zBlock.children('span').css({ - 'display': 'block', - 'margin': '5px', - 'text-align': 'left' - }); - col.append(zBlock); - } -} - -/** - * Load groups into column - * - * @param col Table column where OS images will be placed - */ -function loadSrvGroups(col) { - // Get group names and description and append to group column - if (!$.cookie('xcat_srv_groups')) { - var infoBar = createInfoBar('No selectable group available'); - col.append(infoBar); - return; - } - - var groupNames = $.cookie('xcat_srv_groups').split(','); - - var groupBlock, radio, args, name, ip, hostname, desc; - for (var i in groupNames) { - if( !groupNames[i] || 0 === groupNames[i].length) continue; - args = groupNames[i].split(':'); - name = args[0]; - ip = args[1]; - hostname = args[2]; - desc = args[3]; - - // Create block for each group - groupBlock = $('
                          ').css({ - 'border': '1px solid', - 'max-width': '200px', - 'margin': '5px auto', - 'padding': '5px', - 'display': 'block', - 'vertical-align': 'middle', - 'cursor': 'pointer', - 'white-space': 'normal' - }).click(function(){ - $(this).children('input:radio').attr('checked', 'checked'); - $(this).parents('td').find('div').attr('class', 'ui-state-default'); - $(this).attr('class', 'ui-state-active'); - }); - radio = $('').css('display', 'none'); - groupBlock.append(radio, $('' + name + ': ' + desc + '')); - groupBlock.children('span').css({ - 'display': 'block', - 'margin': '5px', - 'text-align': 'left' - }); - col.append(groupBlock); - } -} - -/** - * Load OS images into column - * - * @param col Table column where OS images will be placed - */ -function loadOSImages(col) { - // Get group names and description and append to group column - if (!$.cookie('xcat_srv_imagenames')) { - var infoBar = createInfoBar('No selectable image available'); - col.append(infoBar); - return; - } - - var imgNames = $.cookie('xcat_srv_imagenames').split(','); - - var imgBlock, radio, args, name, desc; - for (var i in imgNames) { - if( !imgNames[i] || 0 === imgNames[i].length) continue; - args = imgNames[i].split(':'); - name = args[0]; - desc = args[1]; - - // Create block for each image - imgBlock = $('
                          ').css({ - 'border': '1px solid', - 'max-width': '200px', - 'margin': '5px auto', - 'padding': '5px', - 'display': 'block', - 'vertical-align': 'middle', - 'cursor': 'pointer', - 'white-space': 'normal' - }).click(function(){ - $(this).children('input:radio').attr('checked', 'checked'); - $(this).parents('td').find('div').attr('class', 'ui-state-default'); - $(this).attr('class', 'ui-state-active'); - - $('#select-table tbody tr:eq(0) td:eq(3) input[name="master"]').attr('checked', ''); - $('#select-table tbody tr:eq(0) td:eq(3) input[name="master"]').parents('td').find('div').attr('class', 'ui-state-default'); - }); - radio = $('').css('display', 'none'); - imgBlock.append(radio, $('' + name + ': ' + desc + '')); - imgBlock.children('span').css({ - 'display': 'block', - 'margin': '5px', - 'text-align': 'left' - }); - col.append(imgBlock); - } -} - -/** - * Load golden images into column - * - * @param col Table column where master copies will be placed - */ -function loadGoldenImages(col) { - // Get group names and description and append to group column - if (!$.cookie('xcat_srv_goldenimages')) { - var infoBar = createInfoBar('No selectable master copies available'); - col.append(infoBar); - return; - } - - var imgNames = $.cookie('xcat_srv_goldenimages').split(','); - - var imgBlock, radio, args, name, desc; - for (var i in imgNames) { - if( !imgNames[i] || 0 === imgNames[i].length) continue; - args = imgNames[i].split(':'); - name = args[0]; - desc = args[1]; - - // Create block for each image - imgBlock = $('
                          ').css({ - 'border': '1px solid', - 'max-width': '200px', - 'margin': '5px auto', - 'padding': '5px', - 'display': 'block', - 'vertical-align': 'middle', - 'cursor': 'pointer', - 'white-space': 'normal' - }).click(function(){ - $(this).children('input:radio').attr('checked', 'checked'); - $(this).parents('td').find('div').attr('class', 'ui-state-default'); - $(this).attr('class', 'ui-state-active'); - - // Un-select zVM and image - $('#select-table tbody tr:eq(0) td:eq(2) input[name="image"]').attr('checked', ''); - $('#select-table tbody tr:eq(0) td:eq(2) input[name="image"]').parents('td').find('div').attr('class', 'ui-state-default'); - - $('#select-table tbody tr:eq(0) td:eq(0) input[name="hcp"]').attr('checked', ''); - $('#select-table tbody tr:eq(0) td:eq(0) input[name="hcp"]').parents('td').find('div').attr('class', 'ui-state-default'); - }); - radio = $('').css('display', 'none'); - imgBlock.append(radio, $('' + name + ': ' + desc + '')); - imgBlock.children('span').css({ - 'display': 'block', - 'margin': '5px', - 'text-align': 'left' - }); - col.append(imgBlock); - } -} - -/** - * Set a cookie for zVM host names (service page) - * - * @param data Data from HTTP request - */ -function setzVMCookies(data) { - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1) { - var zvms = new Array(); - var hosts = data.rsp[0].split("\n"); - for ( var i = 0; i < hosts.length; i++) { - if (hosts[i] != null && hosts[i] != "") { - zvms.push(hosts[i]); - if (typeof console == "object"){ - console.log("Setting a zVM cookie:<"+hosts[i]+">"); - } - } - } - - // Set cookie to expire in 60 minutes - var exDate = new Date(); - exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); - $.cookie('xcat_zvms', zvms, { expires: exDate, path: '/xcat', secure:true }); - } -} - -/** - * Set a cookie for master copies (service page) - * - * @param data Data from HTTP request - */ -function setGoldenImagesCookies(data) { - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1) { - var copies = new Array(); - var tmp = data.rsp[0].split(","); - for ( var i = 0; i < tmp.length; i++) { - if (tmp[i] != null && tmp[i] != "") { - copies.push(tmp[i]); - } - } - - // Set cookie to expire in 60 minutes - var exDate = new Date(); - exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); - $.cookie('xcat_srv_goldenimages', copies, { expires: exDate, path: '/xcat', secure:true }); - } -} - -/** - * Set a cookie for disk pool names of a given node - * - * @param data Data from HTTP request - */ -function setDiskPoolCookies(data) { - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1) { - var node = data.msg; - var pools = data.rsp[0].split(node + ": "); - var pools2 = []; - for (var j in pools) { - if (pools[j] != "") { - pools2.push(jQuery.trim(pools[j])); - } - } - - // Set cookie to expire in 60 minutes - var exDate = new Date(); - exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); - $.cookie('xcat_' + node + 'diskpools', pools2, { expires: exDate, path: '/xcat', secure:true }); - } -} - -/** - * Set a cookie for zFCP pool names of a given node - * - * @param data Data from HTTP request - */ -function setZfcpPoolCookies(data) { - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1) { - var node = data.msg; - var pools = data.rsp[0].split(node + ': '); - var pools2 = []; - for (var j in pools) { - if (pools[j] != "") { - pools2.push(jQuery.trim(pools[j])); - } - } - - // Set cookie to expire in 60 minutes - var exDate = new Date(); - exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); - $.cookie('xcat_' + node + 'zfcppools', pools2, { expires: exDate, path: '/xcat', secure:true }); - } -} - -/** - * Set a cookie for zHCP host names - * - * @param zhcps List of zHCPs known - */ -function setzHcpCookies(zhcps) { - if (zhcps.length) { - // Set cookie to expire in 60 minutes - var exDate = new Date(); - exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); - $.cookie('xcat_zhcps', zhcps, { expires: exDate, path: '/xcat', secure:true }); - } -} - -/** - * Set a cookie for z/VM user profile names of a given node - * - * @param data Data from HTTP request - */ -function setUserProfilesCookies(data) { - if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1) { - var node = data.msg; - var profiles = data.rsp[0].split(node + ': '); - var profiles2 = []; - for (var j in profiles) { - if (profiles[j] != "") { - profiles2.push(jQuery.trim(profiles[j])); - } - } - - // Set cookie to expire in 60 minutes - var exDate = new Date(); - exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); - $.cookie('xcat_' + node + 'userprofiles', profiles2, { expires: exDate, path: '/xcat', secure:true }); - } -} - -/** - * Create virtual machine (service page) - * - * @param tabId Tab ID - * @param group Group - * @param hcp Hardware control point - * @param img OS image - */ -function createzVM(tabId, group, hcp, img, owner) { - // Submit request to create VM - // webportal provzlinux [group] [hcp] [image] [owner] - var iframe = createIFrame('lib/srv_cmd.php?cmd=webportal&tgt=&args=provzlinux;' + group + ';' + hcp + ';' + img + ';' + owner + '&msg=&opts=flush'); - iframe.prependTo($('#' + tabId)); -} - -/** - * Query the profiles that exists - * - * @param panelId Panel ID - */ -function queryProfiles(panelId) { - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'tabdump', - tgt : '', - args : 'osimage', - msg : panelId - }, - - success : function(data) { - var panelId = data.msg; - setOSImageCookies(data); - configProfilePanel(panelId); - } - }); -} - -/** - * Panel to configure directory entries and disks for a profile - * - * @param panelId Panel ID - */ -function configProfilePanel(panelId) { - // Wipe panel clean - $('#' + panelId).empty(); - - // Add info bar - $('#' + panelId).append(createInfoBar('Create, edit, and delete profiles for the self-service portal. It is important to note the default z/VM user ID for any profile should be LXUSR.')); - - // Create table - var tableId = 'zvmProfileTable'; - var table = new DataTable(tableId); - table.init(['', 'Profile', 'Disk pool', 'Disk size', 'Directory entry']); - - // Insert profiles into table - var profiles = $.cookie('xcat_profiles').split(','); - profiles.push('default'); // Add default profile - for (var i in profiles) { - if (profiles[i]) { - // Columns are: profile, selectable, description, disk pool, disk size, and directory entry - var cols = new Array(profiles[i], '', '', ''); - - // 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", "450px"); - - // Create a profile - var createLnk = $('Create'); - createLnk.click(function() { - profileDialog(); - }); - - // Edit a profile - var editLnk = $('Edit'); - editLnk.click(function() { - var profiles = $('#' + tableId + ' input[type=checkbox]:checked'); - for (var i in profiles) { - var profile = profiles.eq(i).attr('name'); - if (profile) { - // Column order is: profile, selectable, disk pool, disk size, and directory entry - var cols = profiles.eq(i).parents('tr').find('td'); - var pool = cols.eq(2).text(); - var size = cols.eq(3).text(); - var entry = cols.eq(4).html().replace(new RegExp('
                          ', 'g'), '\n'); - - editProfileDialog(profile, pool, size, entry); - } - } - }); - - // Delete a profile - var deleteLnk = $('Delete'); - deleteLnk.click(function() { - var profiles = getNodesChecked(tableId); - if (profiles) { - deleteProfileDialog(profiles); - } - }); - - // Refresh profiles table - var refreshLnk = $('Refresh'); - refreshLnk.click(function() { - queryProfiles(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'); - - // Query directory entries and disk pool/size for each profile - for (var i in profiles) { - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'getdefaultuserentry;' + profiles[i], - msg : 'out=' + panelId + ';profile=' + profiles[i] - }, - - success: insertDirectoryEntry - }); - - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'getzdiskinfo;' + profiles[i], - msg : 'out=' + panelId + ';profile=' + profiles[i] - }, - - success: insertDiskInfo - }); - } -} - -/** - * Insert the directory entry into the profile table - * - * @param data Data from HTTP request - */ -function insertDirectoryEntry(data) { - var tableId = 'zvmProfileTable'; - var args = data.msg.split(';'); - - var profile = args[1].replace('profile=', ''); - - // Do not continue if there is nothing - if (!data.rsp.length) - return; - - var entry = data.rsp[0].replace(new RegExp('\n', 'g'), '
                          '); - - // Get the row containing the profile - var rowPos = findRow(profile, '#' + tableId, 1); - if (rowPos < 0) - return; - - // Update the directory entry column - var dTable = $('#' + tableId).dataTable(); - dTable.fnUpdate(entry, rowPos, 4, false); - - // Adjust table styling - $('#' + tableId + ' td:nth-child(5)').css({ - 'text-align': 'left' - }); - adjustColumnSize(tableId); -} - -/** - * Insert the disk info into the profile table - * - * @param data Data from HTTP request - */ -function insertDiskInfo(data) { - var tableId = 'zvmProfileTable'; - var args = data.msg.split(';'); - - var profile = args[1].replace('profile=', ''); - - // Do not continue if there is nothing - if (!data.rsp.length) - return; - - // Get the row containing the profile - var rowPos = findRow(profile, '#' + tableId, 1); - if (rowPos < 0) - return; - - // Update the disk info columns - var dTable = $('#' + tableId).dataTable(); - - var tmp = ""; - var pool = ""; - var eckdSize = 0; - var info = data.rsp[0].split('\n'); - for (var i in info) { - if (info[i].indexOf('diskpool') > -1) { - tmp = info[i].split('='); - pool = jQuery.trim(tmp[1]); - - dTable.fnUpdate(pool, rowPos, 2, false); - } if (info[i].indexOf('eckd_size') > -1) { - tmp = info[i].split('='); - eckdSize = jQuery.trim(tmp[1]); - - dTable.fnUpdate(eckdSize, rowPos, 3, false); - } - } - - // Adjust table styling - adjustColumnSize(tableId); -} - -/** - * Open profile dialog - */ -function profileDialog() { - // Create form to add profile - var dialogId = 'zvmCreateProfile'; - var profileForm = $('
                          '); - - // Create info bar - var info = createInfoBar('Configure the default settings for a profile'); - profileForm.append(info); - - // Insert profiles into select - var profileSelect = $(''); - var profiles = $.cookie('xcat_profiles').split(','); - profiles.push('default'); // Add default profile - for (var i in profiles) { - if (profiles[i]) { - profileSelect.append($('')); - } - } - - profileForm.append($('
                          ').append(profileSelect)); - profileForm.append('
                          '); - profileForm.append('
                          '); - profileForm.append('
                          '); + for ( var i = 1; i < userEntry.length; i++) { + userEntry[i] = jQuery.trim(userEntry[i]); + txtArea.append(userEntry[i]); + + if (i < userEntry.length) { + txtArea.append('\n'); + } + } + txtArea.attr('readonly', 'readonly'); + fieldSet.append(txtArea); + + /** + * Edit user entry + */ + txtArea.bind('dblclick', function(event) { + txtArea.attr('readonly', ''); + txtArea.css( { + 'border-width' : '1px' + }); + + saveBtn.show(); + cancelBtn.show(); + saveBtn.css('display', 'inline-table'); + cancelBtn.css('display', 'inline-table'); + }); + + /** + * Save + */ + var saveBtn = createButton('Save').hide(); + saveBtn.bind('click', function(event) { + // Show loader + $('#' + node + 'StatusBarLoader').show(); + $('#' + node + 'StatusBar').show(); + + // Replace user entry + var newUserEntry = jQuery.trim(txtArea.val()) + '\n'; + + // Replace user entry + $.ajax( { + url : 'lib/zCmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--replacevs', + att : newUserEntry, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + + // Increment node process and save it in a cookie + incrementNodeProcess(node); + + txtArea.attr('readonly', 'readonly'); + txtArea.css( { + 'border-width' : '0px' + }); + + // Disable save button + $(this).hide(); + cancelBtn.hide(); + }); + + /** + * Cancel + */ + var cancelBtn = createButton('Cancel').hide(); + cancelBtn.bind('click', function(event) { + txtArea.attr('readonly', 'readonly'); + txtArea.css( { + 'border-width' : '0px' + }); + + cancelBtn.hide(); + saveBtn.hide(); + }); + + // Create info bar + var infoBar = createInfoBar('Double click on the directory entry to edit it.'); + + // Append user entry into division + $('#' + ueDivId).append(infoBar); + $('#' + ueDivId).append(fieldSet); + $('#' + ueDivId).append(saveBtn); + $('#' + ueDivId).append(cancelBtn); +} + +/** + * Increment number of processes running against a node + * + * @param node Node to increment running processes + */ +function incrementNodeProcess(node) { + // Get current processes + var procs = $.cookie('xcat_' + node + 'processes'); + if (procs) { + // One more process + procs = parseInt(procs) + 1; + $.cookie('xcat_' + node + 'processes', procs); + } else { + $.cookie('xcat_' + node + 'processes', 1); + } +} + +/** + * Update provision new node status + * + * @param data Data returned from HTTP request + */ +function updateZProvisionNewStatus(data) { + // Parse ajax response + var rsp = data.rsp; + var args = data.msg.split(';'); + var lastCmd = args[0].replace('cmd=', ''); + var out2Id = args[1].replace('out=', ''); + if (typeof console == "object"){ + console.log("Entering updateZProvisionNewStatus. Last command:<"+lastCmd+"> All args:<"+args+">"); + } + // IDs for status bar, tab, and loader + var statBarId = 'zProvisionStatBar' + out2Id; + var tabId = 'zvmProvisionTab' + out2Id; + var loaderId = 'zProvisionLoader' + out2Id; + + var node = $('#' + tabId + ' input[name=nodeName]').val(); + + /** + * (2) Create user entry + */ + if (lastCmd == 'nodeadd') { + if (rsp.length) { + $('#' + loaderId).hide(); + $('#' + statBarId).find('div').append('
                          (Error) Failed to create node definition
                          '); + } else { + $('#' + statBarId).find('div').append('
                          Node definition created for ' + node + '
                          '); + + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + + // Create user entry + var userEntry = $('#' + tabId + ' textarea').val(); + $.ajax( { + url : 'lib/zCmd.php', + dataType : 'json', + data : { + cmd : 'mkvm', + tgt : node, + args : '', + att : userEntry, + msg : 'cmd=mkvm;out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + } + } + + /** + * (3) Update /etc/hosts + */ + else if (lastCmd == 'mkvm') { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + + // If there was an error, quit + if (containErrors(prg.html())) { + $('#' + loaderId).hide(); + } else { + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'makehosts', + tgt : '', + args : '', + msg : 'cmd=makehosts;out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + } + } + + /** + * If sourceforge xcat: (4) Update DNS + */ + else if ((lastCmd == 'makehosts') && (builtInXCAT == 0)) { + // If there was an error, quit + if (rsp.length) { + $('#' + loaderId).hide(); + $('#' + statBarId).find('div').append('
                          (Error) Failed to update /etc/hosts
                          '); + } else { + $('#' + statBarId).find('div').append('
                          /etc/hosts updated
                          '); + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'makedns', + tgt : '', + args : '', + msg : 'cmd=makedns;out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + } + } + /** + * If built in zVM xcat and last command was makehosts or + * If sourceforge xCAT and lastCmd was makedns + * (5) Add disk + * + */ + else if (((lastCmd == 'makehosts') && (builtInXCAT == 1)) || + ((lastCmd == 'makedns') && (builtInXCAT == 0))) { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + + // If there was an error, quit + if (rsp.length) { + $('#' + loaderId).hide(); + if (builtInXCAT == 1) { + $('#' + statBarId).find('div').append('
                          (Error) Failed to update /etc/hosts
                          '); + } else { + $('#' + statBarId).find('div').append('
                          (Error) Failed to makedns
                          '); + } + } else { + if (builtInXCAT == 1) { + $('#' + statBarId).find('div').append('
                          /etc/hosts updated
                          '); + } else { + $('#' + statBarId).find('div').append('
                          makedns updated
                          '); + } + + // Set cookie for number of disks + var diskRows = $('#' + tabId + ' table:eq(0):visible tbody tr'); + $.cookie('xcat_disks2add' + out2Id, diskRows.length, {path: '/xcat', secure:true }); + if (diskRows.length > 0) { + for (var i = 0; i < diskRows.length; i++) { + var diskArgs = diskRows.eq(i).find('td'); + var type = diskArgs.eq(1).find('select').val(); + var address = diskArgs.eq(2).find('input').val(); + var size = diskArgs.eq(3).find('input').val(); + var mode = diskArgs.eq(4).find('select').val(); + var pool = diskArgs.eq(5).find('select').val(); + var password = diskArgs.eq(6).find('input').val(); + + // Create ajax arguments + var args = ''; + if (type == '3390') { + args = '--add' + type + ';' + pool + ';' + address + + ';' + size + ';' + mode + ';' + password + ';' + + password + ';' + password; + } else if (type == '9336') { + args = '--add' + type + ';' + pool + ';' + address + ';' + + size + ';' + mode + ';' + password + ';' + + password + ';' + password; + } + + // Attach disk to node + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : args, + msg : 'cmd=chvm-disk;out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + } + } + + // Set cookie for number of zFCP devices + var zfcpRows = $('#' + tabId + ' table:eq(1):visible tbody tr'); + $.cookie('xcat_zfcp2add' + out2Id, zfcpRows.length, {path: '/xcat', secure:true }); + if (zfcpRows.length > 0) { + for ( var i = 0; i < zfcpRows.length; i++) { + var diskArgs = zfcpRows.eq(i).find('td'); + var address = diskArgs.eq(1).find('input').val(); + var size = diskArgs.eq(2).find('input').val(); + var pool = diskArgs.eq(3).find('select').val(); + var tag = diskArgs.eq(4).find('input').val(); + var portName = diskArgs.eq(5).find('input').val(); + var unitNo = diskArgs.eq(6).find('input').val(); + + // This is either true or false + var loaddev = diskArgs.eq(7).find('input').attr('checked'); + if (loaddev) { + loaddev = "1"; + } else { + loaddev = "0"; + } + + // Create ajax arguments + var args = '--addzfcp;' + pool + ';' + address + ';' + loaddev + ';' + size; + if (tag && tag != "null") { + args += ';' + tag; + } else { + args += ';'; + } + if (portName && tag != "null") { + args += ';' + portName; + } else { + args += ';'; + } if (unitNo && tag != "null") { + args += ';' + unitNo; + } else { + args += ';'; + } + + // Attach zFCP device to node + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : args, + msg : 'cmd=chvm-zfcp;out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + } + } + + // Done if no disks to add + if (diskRows.length < 1 && zfcpRows.length < 1) { + $('#' + statBarId).find('div').append('
                          No disks found to provison, finished.
                          '); + $('#' + loaderId).hide(); + } + } + } + + /** + * (6) Set operating system for given node + */ + else if (lastCmd == 'chvm-disk' || lastCmd == 'chvm-zfcp') { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + + // If there was an error, quit + if (containErrors(prg.html())) { + $('#' + loaderId).hide(); + } else { + // Set cookie for number of disks + // One less disk to add + var disks2add = $.cookie('xcat_disks2add' + out2Id); + if (lastCmd == 'chvm-disk') { + if (disks2add > 0) { + disks2add--; + $.cookie('xcat_disks2add' + out2Id, disks2add, {path: '/xcat', secure:true }); + } + } + + var zfcp2add = $.cookie('xcat_zfcp2add' + out2Id); + if (lastCmd == 'chvm-zfcp') { + if (zfcp2add > 0) { + zfcp2add--; + $.cookie('xcat_zfcp2add' + out2Id, zfcp2add, {path: '/xcat', secure:true }); + } + } + + // Only set operating system if there are no more disks to add + if (zfcp2add < 1 && disks2add < 1) { + // If an operating system image is given + var osImage = $('#' + tabId + ' select[name=os]:visible').val(); + if (osImage) { + // Get operating system, architecture, provision method, and profile + var tmp = osImage.split('-'); + var os = tmp[0]; + var arch = tmp[1]; + var profile = tmp[3]; + + // If the last disk is added + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeadd', + tgt : '', + args : node + ';noderes.netboot=zvm;nodetype.os=' + + os + ';nodetype.arch=' + arch + + ';nodetype.profile=' + profile, + msg : 'cmd=noderes;out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + } else { + $('#' + loaderId).hide(); + } + } + } + } + + /** + * (7) If sourceforge xCAT Update DHCP + */ + else if ((lastCmd == 'noderes') && (builtInXCAT == 0)) { + // If there was an error, do not continue + if (rsp.length) { + $('#' + loaderId).hide(); + $('#' + statBarId).find('div').append('
                          (Error) Failed to set operating system
                          '); + } else { + $('#' + statBarId).find('div').append('
                          Operating system for ' + node + ' set
                          '); + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'makedhcp', + tgt : '', + args : '-a', + msg : 'cmd=makedhcp;out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + } + } + + /** + * (8) Prepare node for boot + */ + else if (((lastCmd == 'noderes') && (builtInXCAT == 1)) || + ((lastCmd == 'makedhcp') && (builtInXCAT == 0))) { + // If there was an error, do not continue + if (rsp.length) { + $('#' + loaderId).hide(); + if (builtInXCAT == 1) { + $('#' + statBarId).find('div').append('
                          (Error) Failed to set operating system
                          '); + } else { + $('#' + statBarId).find('div').append('
                          (Error) Failed to make dhcp
                          '); + } + } else { + if (builtInXCAT == 1) { + $('#' + statBarId).find('div').append('
                          Operating system for ' + node + ' set
                          '); + } else { + $('#' + statBarId).find('div').append('
                          DHCP for ' + node + ' set
                          '); + } + + // Prepare node for boot + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeset', + tgt : node, + args : 'install', + msg : 'cmd=nodeset;out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + } + } + + /** + * (9) Boot node to network + */ + else if (lastCmd == 'nodeset') { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + + // If there was an error + // Do not continue + if (containErrors(prg.html())) { + $('#' + loaderId).hide(); + } else { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rnetboot', + tgt : node, + args : 'ipl=000C', + msg : 'cmd=rnetboot;out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + } + } + + /** + * (10) Done + */ + else if (lastCmd == 'rnetboot') { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + if (prg.html().indexOf('Error') < 0) { + $('#' + statBarId).find('div').append('
                          Open a VNC viewer to see the installation progress.  It might take a couple of minutes before you can connect.
                          '); + } + + // Hide loader + $('#' + loaderId).hide(); + } +} + +/** + * Update the provision existing node status + * + * @param data Data returned from HTTP request + */ +function updateZProvisionExistingStatus(data) { + // Get ajax response + var rsp = data.rsp; + var args = data.msg.split(';'); + + // Get command invoked + var cmd = args[0].replace('cmd=', ''); + // Get provision tab instance + var inst = args[1].replace('out=', ''); + if (typeof console == "object"){ + console.log("Entering updateZProvisionExistingStatus. Last command:<"+cmd+"> All args:<"+args+">"); + } + + // Get provision tab and status bar ID + var statBarId = 'zProvisionStatBar' + inst; + var tabId = 'zvmProvisionTab' + inst; + + /** + * (2) Prepare node for boot + */ + if (cmd == 'nodeadd') { + // Get operating system + var bootMethod = $('#' + tabId + ' select[name=bootMethod]').val(); + + // Get nodes that were checked + var dTableId = 'zNodesDatatable' + inst; + var tgts = getNodesChecked(dTableId); + + // Prepare node for boot + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeset', + tgt : tgts, + args : bootMethod, + msg : 'cmd=nodeset;out=' + inst + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionExistingStatus(data); + } + }); + } + + /** + * (3) Boot node from network + */ + else if (cmd == 'nodeset') { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + + // If there was an error, do not continue + if (containErrors(prg.html())) { + var loaderId = 'zProvisionLoader' + inst; + $('#' + loaderId).remove(); + return; + } + + // Get nodes that were checked + var dTableId = 'zNodesDatatable' + inst; + var tgts = getNodesChecked(dTableId); + + // Boot node from network + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rnetboot', + tgt : tgts, + args : 'ipl=000C', + msg : 'cmd=rnetboot;out=' + inst + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionExistingStatus(data); + } + }); + } + + /** + * (4) Done + */ + else if (cmd == 'rnetboot') { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + if (prg.html().indexOf('Error') < 0) { + $('#' + statBarId).find('div').append('
                          Open a VNC viewer to see the installation progress.  It might take a couple of minutes before you can connect.
                          '); + } + + var loaderId = 'zProvisionLoader' + inst; + $('#' + loaderId).remove(); + } +} + +/** + * Update zVM node status + * + * @param data Data returned from HTTP request + */ +function updateZNodeStatus(data) { + var node = data.msg; + var rsp = data.rsp; + + // Get cookie for number processes performed against this node + var actions = $.cookie('xcat_' + node + 'processes'); + // One less process + actions = actions - 1; + $.cookie('xcat_' + node + 'processes', actions, {path: '/xcat', secure:true }); + + if (actions < 1) { + // Hide loader when there are no more processes + var statusBarLoaderId = node + 'StatusBarLoader'; + $('#' + statusBarLoaderId).hide(); + } + + var statBarId = node + 'StatusBar'; + + // Write ajax response to status bar + var prg = writeRsp(rsp, node + ': '); + $('#' + statBarId).find('div').append(prg); +} + +/** + * Update clone status + * + * @param data Data returned from HTTP request + */ +function updateZCloneStatus(data) { + // Get ajax response + var rsp = data.rsp; + var args = data.msg.split(';'); + var cmd = args[0].replace('cmd=', ''); + + // Get provision instance + var inst = args[1].replace('inst=', ''); + // Get output division ID + var out2Id = args[2].replace('out=', ''); + + /** + * (2) Update /etc/hosts + */ + if (cmd == 'nodeadd') { + var node = args[3].replace('node=', ''); + + // If there was an error, do not continue + if (rsp.length) { + $('#' + out2Id).find('img').hide(); + $('#' + out2Id).find('div').append('
                          (Error) Failed to create node definition
                          '); + } else { + $('#' + out2Id).find('div').append('
                          Node definition created for ' + node + '
                          '); + + // If last node definition was created + var tmp = inst.split('/'); + if (tmp[0] == tmp[1]) { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'makehosts', + tgt : '', + args : '', + msg : 'cmd=makehosts;inst=' + inst + ';out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZCloneStatus(data); + } + }); + } + } + } + + /** + * (3a) Update DNS if source forge xCAT then do makedns + */ + else if ((cmd == 'makehosts') && (builtInXCAT == 0)) { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + out2Id).find('div').append(prg); + + // If there was an error, do not continue + if (rsp.length) { + $('#' + out2Id).find('img').hide(); + $('#' + out2Id).find('div').append('
                          (Error) Failed to update /etc/hosts
                          '); + } else { + $('#' + out2Id).find('div').append('
                          /etc/hosts updated
                          '); + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'makedns', + tgt : '', + args : '', + msg : 'cmd=makedns;inst=' + inst + ';out=' + out2Id + }, + + success : function(data) { + data = decodeRsp(data); + updateZCloneStatus(data); + } + }); + } + } + + /** + * (3b) Update DNS for built in xCAT and clone + * Just clone for sourceforge xCAT + */ + else if (((cmd == 'makehosts') && (builtInXCAT == 1)) || + ((cmd == 'makedns') && (builtInXCAT == 0))) { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + out2Id).find('div').append(prg); + + // If there was an error, do not continue + if (rsp.length) { + $('#' + out2Id).find('img').hide(); + if (builtInXCAT == 1) { + $('#' + out2Id).find('div').append('
                          (Error) Failed to update /etc/hosts
                          '); + } else { + $('#' + out2Id).find('div').append('
                          (Error) Failed to makedns
                          '); + } + } + // Get clone tab + var tabId = out2Id.replace('CloneStatusBar', 'CloneTab'); + + // If a node range is given + var tgtNodeRange = $('#' + tabId + ' input[name=tgtNode]').val(); + var tgtNodes = ''; + if (tgtNodeRange.indexOf('-') > -1) { + var tmp = tgtNodeRange.split('-'); + + // Get node base name + var nodeBase = tmp[0].match(/[a-zA-Z]+/); + // Get the starting index + var nodeStart = parseInt(tmp[0].match(/\d+/)); + // Get the ending index + var nodeEnd = parseInt(tmp[1].match(/\d+/)); + for ( var i = nodeStart; i <= nodeEnd; i++) { + // Do not append comma for last node + if (i == nodeEnd) { + tgtNodes += nodeBase + i.toString(); + } else { + tgtNodes += nodeBase + i.toString() + ','; + } + } + } else { + tgtNodes = tgtNodeRange; + } + + // Get other inputs + var srcNode = $('#' + tabId + ' input[name=srcNode]').val(); + hcp = $('#' + tabId + ' input[name=newHcp]').val(); + var group = $('#' + tabId + ' input[name=newGroup]').val(); + var diskPool = $('#' + tabId + ' input[name=diskPool]').val(); + var diskPw = $('#' + tabId + ' input[name=diskPw]').val(); + if (!diskPw) { + diskPw = ''; + } + + // Clone + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'mkvm', + tgt : tgtNodes, + args : srcNode + ';pool=' + diskPool + ';pw=' + diskPw, + msg : 'cmd=mkvm;inst=' + inst + ';out=' + out2Id + }, + error: function(jqXHR, textStatus) { + $('#' + out2Id).find('div').append('
                          (Error) Failed in clone call with ' + textStatus + '
                          '); + }, + success : function(data) { + data = decodeRsp(data); + updateZCloneStatus(data); + } + }); + } + + /** + * (5) Done + */ + else if (cmd == 'mkvm') { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + out2Id).find('div').append(prg); + + // Hide loader + $('#' + out2Id).find('img').hide(); + } +} + +/** + * Get zVM resources + * + * @param data Data from HTTP request + */ +function getZResources(data) { + var tabId = 'zvmResourceTab'; + var info = createInfoBar('Manage storage and networks'); + $('#' + tabId).append(info); + + // Do not continue if there is no output + if (data.rsp.length) { + if (typeof console == "object"){ + console.log("Entering getZResources."); + } + // Push hardware control points into an array + var node, hcp; + var hcpHash = new Object(); + var hostnameHash = new Object(); + for (var i in data.rsp) { + node = data.rsp[i][0]; + hcp = data.rsp[i][1]; + // data will be coming in like "xcat xcat.endicott.ibm.com hosts.hostnames" + // or xcat zhcp.endicott.ibm.com zvm.hcp" + if (data.rsp[i][2]== "zvm.hcp") { + hcpHash[hcp] = 1; + } else { + if (hcp.length) { + hostnameHash[hcp] = node; + } + } + } + + // Create an array for hardware control points + var hcps = new Array(); + for (var key in hcpHash) { + // Get the short host name + //hcp = key.split('.')[0]; //old code + hcp = hostnameHash[key]; + if (typeof console == "object"){ + console.log("getZResources lookup for hostname "+key+" found nodename <"+hcp+">"); + } + if (jQuery.inArray(hcp, hcps) == -1) { + hcps.push(hcp); + } + } + + // Set hardware control point cookie + $.cookie('xcat_hcp', hcps, {path: '/xcat', secure:true }); + + // Delete loader + $('#' + tabId).find('img[src="images/loader.gif"]').remove(); + + // Create accordion panel for disk + var resourcesAccordion = $('
                          '); + var diskSection = $('
                          '); + var diskLnk = $('

                          Disks

                          ').click(function () { + // Do not load panel again if it is already loaded + if ($('#zvmDiskResource').children().length) { + return; + } + else + $('#zvmDiskResource').append(createLoader('')); + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('xcat_hcp').indexOf(',') > -1) { + hcps = $.cookie('xcat_hcp').split(','); + } else { + hcps.push($.cookie('xcat_hcp')); + } + + // Query the disk pools for each hcp + var panelId = 'zvmDiskResource'; + var info = $('#' + panelId).find('.ui-state-highlight'); + if (!info.length) { + info = createInfoBar("Querying "+hcps.length+" zhcp(s) for disk pools."); + $('#' + panelId).append(info); + } + zhcpQueryCountForDisks = hcps.length; + + for (var i in hcps) { + var itemcount = +i + 1; + info.append("
                          Querying disk pools from: "+hcps[i]+" ("+itemcount+" of "+hcps.length+")"); + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcps[i], + args : '--diskpoolnames', + msg : hcps[i] + }, + + success : function(data) { + data = decodeRsp(data); + getDiskPool(data); + } + }); + zhcpQueryCountForDisks--; + } + }); + + // Create accordion panel for zFCP devices + var zfcpSection = $('
                          '); + var zfcpLnk = $('

                          zFCP

                          ').click(function () { + // Do not load panel again if it is already loaded + if ($('#zfcpResource').children().length) + return; + else + $('#zfcpResource').append(createLoader('')); + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('xcat_hcp').indexOf(',') > -1) { + hcps = $.cookie('xcat_hcp').split(','); + } else { + hcps.push($.cookie('xcat_hcp')); + + } + + // Query the fcp pools for each hcp + var panelId = 'zfcpResource'; + var info = $('#' + panelId).find('.ui-state-highlight'); + if (!info.length) { + info = createInfoBar("Querying "+hcps.length+" zhcp(s) for fcp pools."); + $('#' + panelId).append(info); + } + zhcpQueryCountForZfcps = hcps.length; + for (var i in hcps) { + // Gather fcp pools from hardware control points + var itemcount = +i + 1; + info.append("
                          Querying fcp pools from: "+hcps[i]+" ("+itemcount+" of "+hcps.length+")"); + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcps[i], + args : '--zfcppoolnames', + msg : hcps[i] + }, + + success : function(data) { + data = decodeRsp(data); + getZfcpPool(data); + } + }); + zhcpQueryCountForZfcps--; + } + }); + + // Create accordion panel for network + var networkSection = $('
                          '); + var networkLnk = $('

                          Networks

                          ').click(function () { + // Do not load panel again if it is already loaded + if ($('#zvmNetworkResource').children().length) { + return; + } else { + $('#zvmNetworkResource').append(createLoader('')); + } + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('xcat_hcp').indexOf(',') > -1) { + hcps = $.cookie('xcat_hcp').split(','); + } else { + hcps.push($.cookie('xcat_hcp')); + + } + // Query the networks for each + var panelId = 'zvmNetworkResource'; + var info = $('#' + panelId).find('.ui-state-highlight'); + if (!info.length) { + info = createInfoBar("Querying "+hcps.length+" zhcp(s) for networks."); + $('#' + panelId).append(info); + } + zhcpQueryCountForNetworks = hcps.length; + for (var i in hcps) { + var itemcount = +i + 1; + info.append("
                          Querying networks from: "+hcps[i]+" ("+itemcount+" of "+hcps.length+")"); + $('#zvmResourceAccordion').accordion('resize'); + // Gather networks from hardware control points + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcps[i], + args : '--getnetworknames', + msg : hcps[i] + }, + + success : function(data) { + data = decodeRsp(data); + getNetwork(data); + } + }); + zhcpQueryCountForNetworks--; + } + }); + + resourcesAccordion.append(diskLnk, diskSection, zfcpLnk, zfcpSection, networkLnk, networkSection); + + // Append accordion to tab + $('#' + tabId).append(resourcesAccordion); + resourcesAccordion.accordion(); + networkLnk.trigger('click'); + } +} + +/** + * Get node attributes from HTTP request data + * + * @param propNames Hash table of property names + * @param keys Property keys + * @param data Data from HTTP request + * @return Hash table of property values + */ +function getAttrs(keys, propNames, data) { + // Create hash table for property values + var attrs = new Object(); + + // Go through inventory and separate each property out + var curKey = null; // Current property key + var addLine; // Add a line to the current property? + for ( var i = 1; i < data.length; i++) { + addLine = true; + + // Loop through property keys + // Does this line contains one of the properties? + for ( var j = 0; j < keys.length; j++) { + // Find property name + if (data[i].indexOf(propNames[keys[j]]) > -1) { + attrs[keys[j]] = new Array(); + + // Get rid of property name in the line + data[i] = data[i].replace(propNames[keys[j]], ''); + // Trim the line + data[i] = jQuery.trim(data[i]); + + // Do not insert empty line + if (data[i].length > 0) { + attrs[keys[j]].push(data[i]); + } + + curKey = keys[j]; + addLine = false; // This line belongs to a property + } + } + + // Line does not contain a property + // Must belong to previous property + if (addLine && data[i].length > 1) { + data[i] = jQuery.trim(data[i]); + attrs[curKey].push(data[i]); + } + } + + return attrs; +} + +/** + * Create add processor dialog + * + * @param node Node to add processor to + */ +function openAddProcDialog(node) { + // Create form to add processor + var addProcForm = $('
                          '); + // Create info bar + var info = createInfoBar('Add a temporary processor to this virtual server.'); + addProcForm.append(info); + addProcForm.append('
                          '); + addProcForm.append('
                          '); + + // Create drop down for processor type + var procType = $('
                          '); + procType.append(''); + var typeSelect = $(''); + typeSelect.append('' + + '' + + '' + + '' + ); + procType.append(typeSelect); + addProcForm.append(procType); + + // Generate tooltips + addProcForm.find('div input[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 processor + addProcForm.dialog({ + title:'Add processor', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var node = $(this).find('input[name=procNode]').val(); + var address = $(this).find('input[name=procAddress]').val(); + var type = $(this).find('select[name=procType]').val(); + + // If inputs are not complete, show warning message + if (!node || !address || !type) { + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this)); + } else { + // Add processor + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--addprocessoractive;' + address + ';' + type, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + var statusId = node + 'StatusBar'; + var statusBarLoaderId = node + 'StatusBarLoader'; + $('#' + statusBarLoaderId).show(); + $('#' + statusId).show(); + + // Close dialog + $(this).dialog( "close" ); + } + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Create add disk dialog + * + * @param node Node to add disk to + * @param hcp Hardware control point of node + */ +function openAddDiskDialog(node, hcp) { + // Get list of disk pools + var cookie = $.cookie('xcat_' + hcp + 'diskpools'); + var pools = new Array(); + if (cookie) { + pools = cookie.split(','); + } + + // Create form to add disk + var addDiskForm = $('
                          '); + // Create info bar + var info = createInfoBar('Add a ECKD|3390 or FBA|9336 disk to this virtual server.'); + addDiskForm.append(info); + addDiskForm.append('
                          '); + addDiskForm.append('
                          '); + addDiskForm.append('
                          '); + addDiskForm.append('
                          '); + + // Create drop down for disk pool + var diskPool = $('
                          '); + diskPool.append(''); + var poolSelect = $(''); + for ( var i = 0; i < pools.length; i++) { + if( !pools[i] || 0 === pools[i].length) continue; + poolSelect.append(''); + } + diskPool.append(poolSelect); + addDiskForm.append(diskPool); + + // Create drop down for disk mode + var diskMode = $('
                          '); + diskMode.append(''); + var modeSelect = $(''); + modeSelect.append('' + + '' + + '' + + '' + + '' + + '' + + '' + ); + diskMode.append(modeSelect); + addDiskForm.append(diskMode); + + addDiskForm.append('
                          '); + + // Generate tooltips + addDiskForm.find('div input[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 disk + addDiskForm.dialog({ + title:'Add disk', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var node = $(this).find('input[name=diskNode]').val(); + var type = $(this).find('select[name=diskType]').val(); + var address = $(this).find('input[name=diskAddress]').val(); + var size = $(this).find('input[name=diskSize]').val(); + var pool = $(this).find('select[name=diskPool]').val(); + var mode = $(this).find('select[name=diskMode]').val(); + var password = $(this).find('input[name=diskPassword]').val(); + + // If inputs are not complete, show warning message + if (!node || !type || !address || !size || !pool || !mode) { + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this)); + } else { + // Add disk + if (type == '3390') { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--add3390;' + pool + ';' + address + ';' + size + + ';' + mode + ';' + password + ';' + password + ';' + password, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + var statusId = node + 'StatusBar'; + var statusBarLoaderId = node + 'StatusBarLoader'; + $('#' + statusBarLoaderId).show(); + $('#' + statusId).show(); + } else if (type == '9336') { + // Default block size for FBA volumes = 512 + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--add9336;' + pool + ';' + address + ';' + size + + ';' + mode + ';' + password + ';' + password + ';' + password, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + var statusId = node + 'StatusBar'; + var statusBarLoaderId = node + 'StatusBarLoader'; + $('#' + statusBarLoaderId).show(); + $('#' + statusId).show(); + } + + // Close dialog + $(this).dialog( "close" ); + } // End of else + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Create add zFCP device dialog + * + * @param node Node to add disk to + * @param hcp Hardware control point of node + * @param zvm The z/VM system of node + */ +function openAddZfcpDialog(node, hcp, zvm) { + // Get list of disk pools + var cookie = $.cookie('xcat_' + hcp + 'zfcppools'); + var pools = new Array(); + if (cookie) { + pools = cookie.split(','); + } + + // Create form to add disk + var addZfcpForm = $('
                          '); + // Create info bar + var info = createInfoBar('Add a SCSI|FCP disk to this virtual server.'); + addZfcpForm.append(info); + addZfcpForm.append('
                          '); + addZfcpForm.append('
                          '); + addZfcpForm.append('
                          '); + addZfcpForm.append('
                          '); + + // Create drop down for disk pool + var diskPool = $('
                          '); + diskPool.append(''); + var poolSelect = $(''); + for ( var i = 0; i < pools.length; i++) { + if( !pools[i] || 0 === pools[i].length) continue; + poolSelect.append(''); + } + diskPool.append(poolSelect); + addZfcpForm.append(diskPool); + + // Tag to identify where device will be used + addZfcpForm.append('
                          '); + + // Create advanced link to set advanced zFCP properties + var advancedLnk = $(''); + addZfcpForm.append(advancedLnk); + var advanced = $('
                          ').hide(); + addZfcpForm.append(advanced); + + var portName = $('
                          '); + var unitNo = $('
                          '); + advanced.append(portName, unitNo); + + // Toggle port name and unit number when clicking on advanced link + advancedLnk.click(function() { + advanced.toggle(); + }); + + // Generate tooltips + addZfcpForm.find('div input[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 disk + addZfcpForm.dialog({ + title:'Add zFCP device', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var node = $(this).find('input[name=diskNode]').val(); + var address = $(this).find('input[name=diskAddress]').val(); + var loaddev = $(this).find('input[name=diskLoaddev]'); + var size = $(this).find('input[name=diskSize]').val(); + var pool = $(this).find('select[name=diskPool]').val(); + var tag = $(this).find('input[name=diskTag]').val(); + var portName = $(this).find('input[name=diskPortName]').val(); + var unitNo = $(this).find('input[name=diskUnitNo]').val(); + + // If inputs are not complete, show warning message + if (!node || !address || !size || !pool) { + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this)); + } else { + if (loaddev.attr('checked')) { + loaddev = 1; + } else { + loaddev = 0; + } + + var args = '--addzfcp||' + pool + '||' + address + '||' + loaddev + '||' + size; + + if (tag && tag != "null") { + args += '||' + tag; + } else { + args += '|| ""'; + } + + if ((portName && portName != "null") && (unitNo && unitNo != "null")) { + args += '||' + portName + '||' + unitNo; + } + + // Add zFCP device + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : args, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + var statusId = node + 'StatusBar'; + var statusBarLoaderId = node + 'StatusBarLoader'; + $('#' + statusBarLoaderId).show(); + $('#' + statusId).show(); + + // Close dialog + $(this).dialog( "close" ); + } + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Create dedicate device dialog + * + * @param node Node to dedicate device to + * @param hcp Hardware control point of node + */ +function openDedicateDeviceDialog(node, hcp) { + // Create form to add disk + var dedicateForm = $('
                          '); + // Create info bar + var info = createInfoBar('Add a dedicated device to the configuration'); + dedicateForm.append(info); + + dedicateForm.append('
                          '); + dedicateForm.append('
                          '); + dedicateForm.append('
                          '); + dedicateForm.append('
                          '); + + // Generate tooltips + dedicateForm.find('div input[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 dedicated device + dedicateForm.dialog({ + title:'Add dedicated device', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var node = $(this).find('input[name=diskNode]').val(); + var vAddress = $(this).find('input[name=virtualAddress]').val(); + var rAddress = $(this).find('input[name=realAddress]').val() + var mode = $(this).find('select[name=mode]').val(); + + // If inputs are not complete, show warning message + if (!node || !vAddress || !rAddress || !mode) { + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this)); + } else { + var args = '--dedicatedevice;' + vAddress + ';' + rAddress + ';' + mode; + + // Add zFCP device + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : args, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + var statusId = node + 'StatusBar'; + var statusBarLoaderId = node + 'StatusBarLoader'; + $('#' + statusBarLoaderId).show(); + $('#' + statusId).show(); + + // Close dialog + $(this).dialog( "close" ); + } + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Create add ECKD to system dialog + * + * @param hcp Hardware control point of node + */ +function openAddEckd2SystemDialog(hcp) { + var dialogId = 'zvmAddEckd2System'; + + // Create form to add disk + var addE2SForm = $('
                          '); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + + // Append options for hardware control points + //systemSelect.append($('')); + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + + // Create info bar + var info = createInfoBar('Dynamically add an ECKD disk to a running z/VM system.'); + addE2SForm.append(info); + + addE2SForm.append(system); + addE2SForm.append('
                          '); + + // Generate tooltips + addE2SForm.find('div input[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 disk + addE2SForm.dialog({ + title:'Add ECKD to system', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 420, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + var system = $(this).find('select[name=system]').val(); + var devnum = $(this).find('input[name=devNum]').val(); + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'input[name=devNum]'); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + if (!ready) { + // Show warning message + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : system, + args : "--addeckd;" + devnum, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Create add Volume to system dialog + * + * @param hcp Hardware control point of node + */ +function openAddVolume2SystemDialog(hcp) { + var dialogId = 'zvmAddVolume2System'; + + // Create form to add volume + var addV2SForm = $('
                          '); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + + // Append options for hardware control points + //systemSelect.append($('')); + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + + // Create info bar + var info = createInfoBar('Permanently add a volume to the z/VM system configuration.'); + addV2SForm.append(info); + + addV2SForm.append(system); + addV2SForm.append('
                          '); + addV2SForm.append('
                          '); + + // Generate tooltips + addV2SForm.find('div input[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 volume + addV2SForm.dialog({ + title:'Add volume to system configuration', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 480, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + var system = $(this).find('select[name=system]').val(); + var devnum = $(this).find('input[name=devNum]').val(); + var volser = $(this).find('input[name=volser]').val(); + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'input[name=devNum]', 'input[name=volser]' ); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + if (!ready) { + // Show warning message + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : system, + args : "--addvolume;" + devnum + ";" + volser, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Create remove Volume to system dialog + * + * @param hcp Hardware control point of node + */ +function openRemoveVolumeFromSystemDialog(hcp) { + var dialogId = 'zvmRemoveVolumeFromSystem'; + + // Create form to remove volume + var remVfromSForm = $('
                          '); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + + // Append options for hardware control points + //systemSelect.append($('')); + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + + // Create info bar + var info = createInfoBar('Permanently remove a volume from the z/VM system configuration.'); + remVfromSForm.append(info); + + remVfromSForm.append(system); + remVfromSForm.append('
                          '); + remVfromSForm.append('
                          '); + + // Generate tooltips + remVfromSForm.find('div input[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 remove volume + remVfromSForm.dialog({ + title:'Remove volume from system configuration', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 580, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + var system = $(this).find('select[name=system]').val(); + var devnum = $(this).find('input[name=devNum]').val(); + var volser = $(this).find('input[name=volser]').val(); + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'input[name=devNum]', 'input[name=volser]' ); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + if (!ready) { + // Show warning message + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : system, + args : "--removevolume;" + devnum + ";" + volser, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Create add page or spool dialog + * + * @param hcp Hardware control point of node + */ +function openAddPageSpoolDialog(hcp) { + var dialogId = 'zvmAddPageSpool'; + + // Create form to add disk + var addPageSpoolForm = $('
                          '); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + // Append options for hardware control points + //systemSelect.append($('')); + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + + // Create info bar + var info = createInfoBar('Add a page or spool volume to be used by zVM.'); + addPageSpoolForm.append(info); + + var diskFS = $('
                          Disk
                          '); + addPageSpoolForm.append(diskFS); + var diskAttr = $('
                          '); + diskFS.append($('
                          ')); + diskFS.append(diskAttr); + + diskAttr.append(system); + diskAttr.append('
                          '); + diskAttr.append('
                          '); + diskAttr.append('
                          '); + + // Generate tooltips + addPageSpoolForm.find('div input[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 disk + addPageSpoolForm.dialog({ + title:'Add page or spool', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 500, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + var system = $(this).find('select[name=system]').val(); + var volAddr = $(this).find('input[name=volAddr]').val(); + var volLabel = $(this).find('input[name=volLabel]').val(); + var volUse = $(this).find('select[name=volUse]').val(); + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'input[name=volAddr]', 'input[name=volLabel]', 'select[name=volUse]'); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + if (!ready) { + // Show warning message + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + var pageSpoolArgs = volAddr + ";" + volLabel + ";" + volUse; + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : system, + args : '--addpagespool;' + pageSpoolArgs, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Open dialog to share disk + * + * @param disks2share Disks selected in table + */ +function openShareDiskDialog(disks2share) { + // Create form to share disk + var dialogId = 'zvmShareDisk'; + var shareDiskForm = $('
                          '); + + var args = disks2share.split(';'); + var tgtHcp = args[0]; + var tgtVol = args[1]; + + if (!tgtVol || tgtVol == "undefined") + tgtVol = ""; + + // Create info bar + var info = createInfoBar('Indicate a full-pack minidisk is to be shared by the users of many real and virtual systems.'); + shareDiskForm.append(info); + + // Set region input based on those selected on table (if any) + var node = $('
                          '); + var volAddr = $('
                          '); + var shareEnable = $('
                          '); + shareDiskForm.append(node, volAddr, shareEnable); + + // Generate tooltips + shareDiskForm.find('div input[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 delete disk + shareDiskForm.dialog({ + title:'Share disk', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 500, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var node = $(this).find('input[name=node]').val(); + var volAddr = $(this).find('input[name=volAddr]').val(); + var shareEnable = $(this).find('select[name=shareEnable]').val(); + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('input[name=node]', 'input[name=volAddr]', 'select[name=shareEnable]'); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + if (!ready) { + // Show warning message + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + // Remove disk from pool + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : "--sharevolume;" + volAddr + ";" + shareEnable, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Create add SCSI 2 system dialog + * + * @param hcp Hardware control point of node + */ +function openAddScsi2SystemDialog(hcp) { + var dialogId = 'zvmAddScsi2System'; + + // Create form to add disk + var addS2SForm = $('
                          '); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + + // Create info bar + var info = createInfoBar('Dynamically add an SCSI disk to a running z/VM system as an EDEV.'); + addS2SForm.append(info); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + + // Append options for hardware control points + //systemSelect.append($('')); + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + + var devNo = $('
                          '); + var devPathLabel = $(''); + var devPathCount = 1; + //var pathDiv = $('
                          '); + + var devPathDiv = $('
                          '); + var devPathTable = $('
                          '); + var devPathHeader = $(' FCP Device WWPN LUN'); + // Adjust header width + devPathHeader.find('th').css({ + 'width' : '120px' + }); + devPathHeader.find('th').eq(0).css({ + 'width' : '20px' + }); + var devPathBody = $(''); + var devPathFooter = $(''); + + // Create a row + var devPathRow = $(''); + + // Add blank column (remove button replacement) + devPathRow.append(''); + + // Create FCP device number input + var fcpDevNum = $(''); + devPathRow.append(fcpDevNum); + + // Create FCP WWPN input + var fcpWwpn = $(''); + devPathRow.append(fcpWwpn); + + if ($.cookie('xcat_zvms')) { + zvms = $.cookie('xcat_zvms').split(','); + var zvm; + for (var i in zvms) { + if( !zvms[i] || 0 === zvms[i].length) continue; + var args = zvms[i].split(':'); + var zvm = args[0].toLowerCase(); + var iHcp = args[1]; + } + } + + // Create FCP LUN input + var fcpLun = $(''); + devPathRow.append(fcpLun); + + devPathBody.append(devPathRow); + + var addDevPathLink = $('+ Add path'); + addDevPathLink.bind('click', function(event){ + devPathCount = devPathCount + 1; + // Create a row + var devPathRow = $(''); + + // Add remove button + var removeBtn = $('').css({ + "float": "left", + "cursor": "pointer" + }); + var col = $('').append(removeBtn); + removeBtn.bind('click', function(event) { + $(this).parent().parent().remove(); + }); + devPathRow.append(col); + + // Create FCP device number input + var fcpDevNum = $(''); + devPathRow.append(fcpDevNum); + + // Create FCP WWPN input + var fcpWwpn = $(''); + devPathRow.append(fcpWwpn); + + // Create FCP LUN input + var fcpLun = $(''); + devPathRow.append(fcpLun); + + devPathBody.append(devPathRow); + + // Generate tooltips + addS2SForm.find('div input[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()); + } + }); + }); + devPathFooter.append(addDevPathLink); + devPathTable.append(devPathHeader); + devPathTable.append(devPathBody); + devPathTable.append(devPathFooter); + devPathDiv.append(devPathLabel); + devPathDiv.append(devPathTable); + + var option = $('
                          '); + var persist = $('
                          '); + addS2SForm.append(system, devNo, devPathDiv, option, persist); + + // Generate tooltips + addS2SForm.find('div input[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()); + } + }); + + addS2SForm.find('div input[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events: { + def: "mouseover,mouseout", + input: "mouseover,mouseout", + widget: "focus mouseover,blur mouseout", + tooltip: "mouseover,mouseout" + } + }); + + // Open dialog to add disk + addS2SForm.dialog({ + title:'Add SCSI to running system', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 675, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + var system = $(this).find('select[name=system]').val(); + var devNo = $(this).find('input[name=devNo]').val(); + var pathArray = ""; + jQuery('.devPath').each(function(index) { + pathArray += $(this).find('input[name=fcpDevNum]').val() + ','; + pathArray += $(this).find('input[name=fcpWwpn]').val() + ','; + pathArray += $(this).find('input[name=fcpLun]').val() + ';'; + }); + var option = $(this).find('select[name=option]').val(); + var persist = $(this).find('select[name=persist]').val(); + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'input[name=fcpDevNum]', 'select[name=option]', 'select[name=persist]'); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + // Show warning message + if (!ready || !pathArray) { + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : system, + args : "--addscsi||" + devNo + "||" + pathArray + "||" + option + "||" + persist, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Delete a real SCSI disk + * + * @param hcp Hardware control point of node + */ +function openRemoveScsiDialog(hcp) { + var dialogId = 'zvmRemoveScsiDialog'; + // Create form to add disk + var removeScsiForm = $('
                          '); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + + // Append options for hardware control points + //systemSelect.append($('')); + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + + // Create info bar + var info = createInfoBar('Delete a real SCSI disk'); + removeScsiForm.append(info, system); + removeScsiForm.append('
                          '); + removeScsiForm.append('
                          '); + addNicForm.append('
                          '); + + // Create drop down for NIC types + var nicType = $('
                          '); + nicType.append(''); + var nicTypeSelect = $(''); + nicTypeSelect.append('' + + '' + + '' + ); + nicType.append(nicTypeSelect); + addNicForm.append(nicType); + + // Create drop down for network types + var networkType = $('
                          '); + networkType.append(''); + var networkTypeSelect = $(''); + networkTypeSelect.append('' + + '' + + '' + ); + networkType.append(networkTypeSelect); + addNicForm.append(networkType); + var hashtable = getselectedNetworkHash(); + if (!hashtable) { + hashtable = [[]]; + setselectedNetworkHash(hashtable); + + if (typeof console == "object") { + console.log("openAddNicDialog. creating new hash[[]] table." ); + } + } + + // Create drop down for network names + var gLansQdioSelect = $(''); + var gLansHipersSelect = $(''); + var vswitchSelect = $(''); + for ( var i = 0; i < networks.length; i++) { + if( !networks[i] || 0 === networks[i].length) continue; + var network = networks[i].split(' '); + var networkOption = $(''); + if (network[0] == 'VSWITCH') { + vswitchSelect.append(networkOption); + + // Load and save specific vswitch details in global table if not there + network[2] = jQuery.trim(network[2]); // Remove new line x012 from end + if (typeof hashtable[node + '_NIC_' + network[2]] === 'undefined') { + if (typeof console == "object"){ + console.log("Calling getNetworkDetails for switch:<"+network[2]+">"); + } + ajaxrequest = 1; + getNetworkDetails(hcpNode, network[2], node + '_NIC_' + network[2], ''); + } + } else if (network[0] == 'LAN:QDIO') { + gLansQdioSelect.append(networkOption); + } else if (network[0] == 'LAN:HIPERS') { + gLansHipersSelect.append(networkOption); + } + } + + // Hide network name drop downs until the NIC type and network type is selected + // QDIO Guest LAN drop down + var guestLanQdio = $('
                          ').hide(); + guestLanQdio.append(''); + guestLanQdio.append(gLansQdioSelect); + addNicForm.append(guestLanQdio); + + // HIPERS Guest LAN drop down + var guestLanHipers = $('
                          ').hide(); + guestLanHipers.append(''); + guestLanHipers.append(gLansHipersSelect); + addNicForm.append(guestLanHipers); + + // VSWITCH drop down + var vswitch = $('
                          ').hide(); + vswitch.append(''); + vswitch.append(vswitchSelect); + + // VLAN id with Porttype + var vswitchvlan = $('
                          '); + vswitchvlan.append('
                          '); + var vswitchPorttype = $(''); + vswitchvlan.append(vswitchPorttype); + vswitchvlan.append('
                          '); + var vswitchVLANId = $(''); + vswitchvlan.append(vswitchVLANId); + + vswitch.append(vswitchvlan); + vswitchvlan.hide(); + addNicForm.append(vswitch); + + // Show network names on change + networkTypeSelect.change(function(){ + // Remove any warning messages + $(this).parent().parent().find('.ui-state-error').remove(); + var networkType = $(this).val(); + + if (typeof console == "object"){ + console.log("Entering networkTypeSelect.change"); + } + // Get NIC type and network type + var nicType = $(this).parent().parent().find('select[name=nicType]').val(); + var networkType = $(this).val(); + + // Hide network name drop downs + var guestLanQdio = $(this).parent().parent().find('select[name=nicLanQdioName]').parent(); + var guestLanHipers = $(this).parent().parent().find('select[name=nicLanHipersName]').parent(); + var vswitch = $(this).parent().parent().find('select[name=nicVSwitchName]').parent(); + var mynode = $(this).parent().parent().find('input[name=nicNode]').val(); + var showvlan = $(this).parent().parent().find('select[name=vswitchVLANporttype]').parent(); + var hashtable = getselectedNetworkHash(); + guestLanQdio.hide(); + guestLanHipers.hide(); + vswitch.hide(); + + // Show correct network name + if (networkType == 'Guest LAN' && nicType == 'QDIO') { + guestLanQdio.show(); + } else if (networkType == 'Guest LAN' && nicType == 'HiperSockets') { + guestLanHipers.show(); + } else if (networkType == 'Virtual Switch') { + if (nicType == 'QDIO') { + vswitch.show(); + // Show vlan information only if vlan aware + var switchname = $(this).parent().parent().find('select[name=nicVSwitchName]').val(); + var tokens = switchname.split(' '); + var switchkeyid = mynode + '_NIC_' + jQuery.trim(tokens[1]); + if (typeof console == "object"){ + console.log("Checking vswitch index:"+switchkeyid); + } + + // Is this a vlanaware switch, if so show the special fields + if (hashtable[switchkeyid]["vlan_awareness"] == "AWARE") { + showvlan.find('input[name=vswitchvlanid]').val(hashtable[switchkeyid]["vlan_id"]); + showvlan.find('select[name=vswitchVLANporttype]').val(hashtable[switchkeyid]["port_type"]); + showvlan.show(); + } else { + showvlan.hide(); + showvlan.find('input[name=vswitchvlanid]').val('default'); + showvlan.find('select[name=vswitchVLANporttype]').val('default'); + } + } else { + // No such thing as HIPERS VSWITCH + var warn = createWarnBar('The selected choices are not valid.'); + warn.prependTo($(this).parent().parent()); + } + } + }); + + // + // Show network names on change + // + nicTypeSelect.change(function(){ + // Remove any warning messages + $(this).parent().parent().find('.ui-state-error').remove(); + + if (typeof console == "object"){ + console.log("Entering nicTypeSelect.change"); + } + + // Get NIC type and network type + var nicType = $(this).val(); + var networkType = $(this).parent().parent().find('select[name=nicNetworkType]').val(); + var mynode = $(this).parent().parent().find('input[name=nicNode]').val(); + + // Hide network name drop downs + var guestLanQdio = $(this).parent().parent().find('select[name=nicLanQdioName]').parent(); + var guestLanHipers = $(this).parent().parent().find('select[name=nicLanHipersName]').parent(); + var vswitch = $(this).parent().parent().find('select[name=nicVSwitchName]').parent(); + var showvlan = $(this).parent().parent().find('select[name=vswitchVLANporttype]').parent(); + var hashtable = getselectedNetworkHash(); + guestLanQdio.hide(); + guestLanHipers.hide(); + vswitch.hide(); + + // Show correct network name + if (networkType == 'Guest LAN' && nicType == 'QDIO') { + guestLanQdio.show(); + } else if (networkType == 'Guest LAN' && nicType == 'HiperSockets') { + guestLanHipers.show(); + } else if (networkType == 'Virtual Switch') { + if (nicType == 'QDIO') { + vswitch.show(); + var switchname = $(this).parent().parent().find('select[name=nicVSwitchName]').val(); + var tokens = switchname.split(' '); + var switchkeyid = mynode + '_NIC_' + jQuery.trim(tokens[1]); + + if (typeof console == "object"){ + console.log("Entering nictypeselect.change. switchkey:<"+switchkeyid); + } + + // Is this a vlanaware switch, if so show the special fields + if (hashtable[switchkeyid]["vlan_awareness"] == "AWARE") { + showvlan.find('input[name=vswitchvlanid]').val(hashtable[switchkeyid]["vlan_id"]); + showvlan.find('select[name=vswitchVLANporttype]').val(hashtable[switchkeyid]["port_type"]); + showvlan.show(); + } else { + showvlan.hide(); + showvlan.find('input[name=vswitchvlanid]').val('default'); + showvlan.find('select[name=vswitchVLANporttype]').val('default'); + } + + } else { + // No such thing as HIPERS VSWITCH + var warn = createWarnBar('The selected choices are not valid.'); + warn.prependTo($(this).parent().parent()); + } + } + }); + + // + // Determine if vlanid fields need to be shown based on vswitch + // + vswitchSelect.change(function(){ + // Remove any warning messages + $(this).parent().parent().find('.ui-state-error').remove(); + + // Get vlan id division + var showvlan = $(this).parent().parent().find('select[name=vswitchVLANporttype]').parent(); + + // Get selected switch name and break it into tokens + var switchname = $(this).val(); + var tokens = switchname.split(' '); + + // Get the node we are doing this for and index for hash table + var mynode = $(this).parent().parent().find('input[name=nicNode]').val(); + + var tokens = switchname.split(' '); + var switchkeyid = mynode + '_NIC_' + jQuery.trim(tokens[1]); + var hashtable = getselectedNetworkHash(); + + if (typeof console == "object"){ + console.log("Entering vswitchselect.change. switchkey:<"+switchkeyid+">"); + } + // Is this a vlanaware switch, if so show the special fields + if (hashtable[switchkeyid]["vlan_awareness"] == "AWARE") { + $(this).find('').val(hashtable[switchkeyid]["vlan_id"]); + showvlan.find('input[name=vswitchvlanid]').val(hashtable[switchkeyid]["vlan_id"]); + showvlan.find('select[name=vswitchVLANporttype]').val(hashtable[switchkeyid]["port_type"]); + showvlan.show(); + } else { + showvlan.hide(); + showvlan.find('input[name=vswitchvlanid]').val('default'); + showvlan.find('select[name=vswitchVLANporttype]').val('default'); + } + }); + + + // Generate tooltips + addNicForm.find('div input[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 NIC + addNicForm.dialog({ + title:'Add NIC', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + var ready = true; + var errMsg = ''; + + // Get inputs + var node = $(this).find('input[name=nicNode]').val(); + var nicType = $(this).find('select[name=nicType]').val(); + var networkType = $(this).find('select[name=nicNetworkType]').val(); + var address = $(this).find('input[name=nicAddress]').val(); + + // If inputs are not complete, show warning message + if (!node || !nicType || !networkType || !address) { + errMsg = 'Please provide a value for each missing field.
                          '; + ready = false; + } + + // If a HIPERS VSWITCH is selected, show warning message + if (nicType == 'HiperSockets' && networkType == 'Virtual Switch') { + errMsg += 'The selected choices are not valid.'; + ready = false; + } + + // If there are errors + if (!ready) { + // Show warning message + var warn = createWarnBar(errMsg); + warn.prependTo($(this)); + } else { + // Add guest LAN + if (networkType == 'Guest LAN') { + var temp; + if (nicType == 'QDIO') { + temp = $(this).find('select[name=nicLanQdioName]').val().split(' '); + } else { + temp = $(this).find('select[name=nicLanHipersName]').val().split(' '); + } + + var lanOwner = temp[0]; + var lanName = temp[1]; + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--addnic;' + address + ';' + nicType + ';3', + msg : 'node=' + node + ';addr=' + address + ';lan=' + + lanName + ';owner=' + lanOwner + }, + success : function(data) { + data = decodeRsp(data); + connect2GuestLan(data); + } + }); + } + + // Add virtual switch + else if (networkType == 'Virtual Switch' && nicType == 'QDIO') { + var temp = $(this).find('select[name=nicVSwitchName]').val().split(' '); + var vswitchName = jQuery.trim(temp[1]); + var switchkeyid = node + '_NIC_' + vswitchName; + var hashtable = getselectedNetworkHash(); + var awareornot = hashtable[switchkeyid]["vlan_awareness"]; + var porttype = $(this).find('select[name=vswitchVLANporttype]').val(); + var lanid = $(this).find('input[name=vswitchvlanid]').val(); + + // Pass additional lanid data in msg for grant use by connect2VSwitch + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--addnic;' + address + ';' + nicType + ';3', + msg : 'node=' + node + ';addr=' + address + ';vsw=' + + vswitchName + ';vlanaware=' + awareornot + ';porttype=' + + porttype + ';lanid=' + lanid + }, + + success : function(data) { + data = decodeRsp(data); + connect2VSwitch(data); + } + }); + } + + // Increment node process + incrementNodeProcess(node); + + // Show loader + $('#' + node + 'StatusBarLoader').show(); + $('#' + node + 'StatusBar').show(); + + // Close dialog + $(this).dialog( "close" ); + } // End of else + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); + // Make sure ajax is done before putting up dialog + $(document).ajaxStop(function() { + //Remove loading vswitch gif status bar + statBar.hide(); + }); + if (ajaxrequest == 0) { + //Remove loading vswitch gif status bar + statBar.hide(); + } + +} + +/** + * Create add vSwitch/VLAN dialog + * + * @param hcp Hardware control point of node + */ +function openAddVswitchVlanDialog(hcp) { + var dialogId = 'zvmAddVswitchVlan'; + + // Create form to add disk + var addVswitchForm = $('
                          '); + + // Create info bar + var info = createInfoBar('Create a virtual switch or virtual network LAN.'); + + var netFS = $('
                          '); + var netLegend = $('Network'); + netFS.append(netLegend); + + var typeFS = $('
                          ').hide(); + var typeLegend = $('Network'); + typeFS.append(typeLegend); + addVswitchForm.append(info, netFS, typeFS); + + var netAttr = $('
                          '); + netFS.append($('
                          ')); + netFS.append(netAttr); + + var networkTypeDiv = $('
                          '); + var networkType = $('
                          '); + networkTypeDiv.append(networkType) + netAttr.append(networkTypeDiv); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + netAttr.append(system); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + //systemSelect.append($('')); + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + + var typeAttr = $('
                          '); + typeFS.append($('
                          ')); + typeFS.append(typeAttr); + + // Create vSwitch parameters + var vswitchOptions = $('
                          ').hide(); + vswitchOptions.append($('
                          ')); + vswitchOptions.append($('
                          ')); + vswitchOptions.append($('
                          ')); + + // Create an advanced link to configure optional network settings + var advancedLnk = $(''); + vswitchOptions.append(advancedLnk); + var advanced = $('
                          ').hide(); + vswitchOptions.append(advanced); + + // Show IP address and hostname inputs on-click + advancedLnk.click(function() { + advanced.toggle(); + }); + + advanced.append($('
                          ')); + advanced.append($('
                          ')); + advanced.append($('
                          ')); + advanced.append($('
                          ')); + advanced.append($('
                          ')); + advanced.append($('
                          ')); + advanced.append($('
                          ')); + advanced.append($('
                          ')); + advanced.append($('
                          ')); + + // Create VLAN parameters + var vlanOptions = $('
                          ').hide(); + vlanOptions.append($('
                          ')); + vlanOptions.append($('
                          ')); + vlanOptions.append($('
                          ')); + vlanOptions.append($('
                          ')); + + typeAttr.append(vswitchOptions, vlanOptions); + + networkType.change(function() { + typeFS.show(); + if ($(this).val() == "vswitch") { + typeFS.find("legend").text("vSwitch"); + vswitchOptions.show(); + vlanOptions.hide(); + } else if ($(this).val() == "vlan") { + typeFS.find("legend").text("VLAN"); + vswitchOptions.hide(); + vlanOptions.show(); + } else { + typeFS.find("legend").text(""); + vswitchOptions.hide(); + vlanOptions.hide(); + typeFS.hide(); + } + }); + + // Generate tooltips + addVswitchForm.find('div input[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 vSwitch or VLAN + addVswitchForm.dialog({ + title:'Add vSwitch or VLAN', + modal: true, + close: function() { + $(this).remove(); + }, + width: 750, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + var networkType = $(this).find('select[name=networkType]').val(); + if (networkType == "vswitch") { + var networkArgs = "--addvswitch;"; + var system = $(this).find('select[name=system]').val(); + var switchName = $(this).find('input[name=switchName]').val(); + var deviceAddress = $(this).find('input[name=deviceAddress]').val(); + var portName = switchName; + var controllerName = $(this).find('input[name=controllerName]').val(); + var connection = $(this).find('select[name=connection]').val(); + var queueMemoryLimit = $(this).find('input[name=queueMemoryLimit]').val(); + var routingValue = $(this).find('select[name=routingValue]').val(); + var transportType = $(this).find('select[name=transportType]').val(); + var vlanId = $(this).find('input[name=vlanId]').val(); + var portType = $(this).find('select[name=vswitchVLANporttype]').val(); + var updateSysConfig = $(this).find('select[name=updateSysConfig]').val(); + var gvrp = $(this).find('select[name=gvrp]').val(); + var nativeVlanId = $(this).find('input[name=nativeVlanId]').val(); + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'input[name=switchName]', 'input[name=deviceAddress]', 'input[name=controllerName]'); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + // Show warning message + if (!ready) { + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + if (switchName) + networkArgs += switchName + ";"; + if (deviceAddress) + networkArgs += deviceAddress + ";"; + if (portName) + networkArgs += portName + ";"; + if (controllerName) + networkArgs += controllerName + ";"; + + // Optional parameters + if (connection) + networkArgs += connection + ";"; + if (queueMemoryLimit) + networkArgs += queueMemoryLimit + ";"; + if (routingValue) + networkArgs += routingValue + ";"; + if (transportType) + networkArgs += transportType + ";"; + if (vlanId) + networkArgs += vlanId + ";"; + if (portType) + networkArgs += portType + ";"; + if (updateSysConfig) + networkArgs += updateSysConfig + ";"; + if (gvrp) + networkArgs += gvrp + ";"; + if (nativeVlanId) + networkArgs += nativeVlanId + ";"; + networkArgs = networkArgs.substring(0, networkArgs.length - 1); + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : system, + args : networkArgs, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + } else if (networkType == "vlan") { + var networkArgs = "--addvlan;"; + var system = $(this).find('select[name=system]').val(); + var vlanName = $(this).find('input[name=vlanName]').val(); + var vlanOwner = $(this).find('input[name=vlanOwner]').val(); + var vlanType = $(this).find('select[name=vlanType]').val(); + var vlanTransport = $(this).find('select[name=vlanTransport]').val(); + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'input[name=vlanName]', 'input[name=vlanOwner]', 'select[name=vlanType]', 'select[name=vlanTransport]'); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + // Show warning message + if (!ready) { + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Ethernet Hipersockets are not supported + if (vlanTransport == "2") { + var warn = createWarnBar('Ethernet Hipersockets are not supported'); + warn.prependTo($(this)); + return; + } + + networkArgs += vlanName + ";"; + networkArgs += vlanOwner + ";"; + networkArgs += vlanType + ";"; + networkArgs += vlanTransport; + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : system, + args : networkArgs, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + } // End of else if + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Open dialog to delete network + * + * @param node type name for removing network + */ +function openRemoveVswitchVlanDialog(networkList) { + var names = ''; + for (var i in networkList) { + var networkArgs = networkList[i].split(';'); + networkArgs[2] = jQuery.trim(networkArgs[2]); + names += networkArgs[2] + ', '; + } + names = names.substring(0, names.length - 2); // Delete last two characters + + var confirmDialog = $('

                          Are you sure you want to remove ' + names + '?

                          '); + confirmDialog.dialog({ + title: "Confirm", + modal: true, + width: 400, + buttons: { + "Ok": function() { + for (var i in networkList) { + var networkArgs = networkList[i].split(';'); + var node = networkArgs[0]; + var type = networkArgs[1]; + var name = jQuery.trim(networkArgs[2]); + var owner = networkArgs[3]; + + if (type.indexOf("VSWITCH") != -1) { + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : node, + args : '--removevswitch;' + name, + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + 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; + } + + openDialog("info", infoMsg); + } + }); + } else if (type.indexOf("LAN") != -1) { + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : node, + args : '--removevlan;' + name + ';' + owner, + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + 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; + } + + openDialog("info", infoMsg); + } + }); + } + } + $(this).dialog("close"); + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); +} + +/** + * Remove processor + * + * @param node Node where processor is attached + * @param address Virtual address of processor + */ +function removeProcessor(node, address) { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--removeprocessor;' + address, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + $('#' + node + 'StatusBarLoader').show(); + $('#' + node + 'StatusBar').show(); +} + +/** + * Remove disk + * + * @param node Node where disk is attached + * @param address Virtual address of disk + */ +function removeDisk(node, address) { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--removedisk;' + address, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + $('#' + node + 'StatusBarLoader').show(); + $('#' + node + 'StatusBar').show(); +} + +/** + * Remove zFCP device + * + * @param node Node where disk is attached + * @param address Virtual address of zFCP device + * @param wwpn World wide port name of zFCP device + * @param lun Logical unit number of zFCP device + */ +function removeZfcp(node, address, wwpn, lun) { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--removezfcp||' + address + '||' + wwpn + '||' + lun, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + $('#' + node + 'StatusBarLoader').show(); + $('#' + node + 'StatusBar').show(); +} + +/** + * Remove NIC + * + * @param node Node where NIC is attached + * @param address Virtual address of NIC + */ +function removeNic(node, nic) { + var args = nic.split('.'); + var address = args[0]; + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--removenic;' + address, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + + // Increment node process + incrementNodeProcess(node); + + // Show loader + $('#' + node + 'StatusBarLoader').show(); + $('#' + node + 'StatusBar').show(); +} + +/** + * Set a cookie for the network names of a given node + * + * @param data Data from HTTP request + */ +function setNetworkCookies(data) { + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1 ) { + var node = data.msg; + var networks = data.rsp[0].split(node + ': '); + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); + $.cookie('xcat_' + node + 'networks', networks, { expires: exDate, path: '/xcat', secure:true }); + } +} + +/** + * Get contents of each disk pool + * + * @param data HTTP request data + */ +function getDiskPool(data) { + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Invalid") == -1 && data.rsp[0].indexOf("Error") == -1 ) { + var hcp = data.msg; + var pools = data.rsp[0].split(hcp + ': '); + + // Get contents of each disk pool + for (var i in pools) { + if (pools[i]) { + pools[i] = jQuery.trim(pools[i]); + + // Get used space + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcp, + args : '--diskpool;' + pools[i] + ';used', + msg : 'hcp=' + hcp + ';pool=' + pools[i] + ';stat=used' + }, + + success : function(data) { + data = decodeRsp(data); + loadDiskPoolTable(data); + } + }); + + // Get free space + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcp, + args : '--diskpool;' + pools[i] + ';free', + msg : 'hcp=' + hcp + ';pool=' + pools[i] + ';stat=free' + }, + + success : function(data) { + data = decodeRsp(data); + loadDiskPoolTable(data); + } + }); + } // End of if + } // End of for + } else { + // Display any errors in info bar + if (data.rsp.length) { + var panelId = 'zvmDiskResource'; + var info = $('#' + panelId).find('.ui-state-highlight'); + // If there is no info bar, create info bar + if (!info.length) { + info = createInfoBar("Error: "+data.rsp[0]); + $('#' + panelId).append(info); + } else { + info.append("
                          Error: "+data.rsp[0]); + } + } + // Load empty table + loadDiskPoolTable(""); // Must pass something + } +} + +/** + * Get contents of each zFCP pool + * + * @param data HTTP request data + */ +function getZfcpPool(data) { + if (typeof console == "object"){ + console.log("Entering getZfcpPool."); + } + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Invalid") == -1 && data.rsp[0].indexOf("Error") == -1 ) { + var hcp = data.msg; + var pools = data.rsp[0].split(hcp + ': '); + zhcpQueryCountForZfcps = 0; + // Get contents of each disk pool + for (var i in pools) { + pools[i] = jQuery.trim(pools[i]); + if (pools[i]) { + + // Query used and free space + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcp, + args : '--zfcppool;' + pools[i] + ';all', + msg : 'hcp=' + hcp + ';pool=' + pools[i] + }, + success : function(data) { + data = decodeRsp(data); + loadZfcpPoolTable(data); + } + }); + } // End of if + } // End of for + } else { + // Display any errors in info bar + if (data.rsp.length) { + var panelId = 'zfcpResource'; + var info = $('#' + panelId).find('.ui-state-highlight'); + // If there is no info bar, create info bar + if (!info.length) { + info = createInfoBar("Error: "+data.rsp[0]); + $('#' + panelId).append(info); + } else { + info.append("
                          Error: "+data.rsp[0]); + } + } + // Load empty table + loadZfcpPoolTable(""); // Must pass something + } +} + +/** + * Get details of each network + * + * @param data HTTP request data + */ +function getNetwork(data) { + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Invalid") == -1 && data.rsp[0].indexOf("Error") == -1 ) { + var hcp = data.msg; + var networks = data.rsp[0].split(hcp + ': '); + if (typeof console == "object"){ + console.log("Entering getNetwork data:<"+networks+">"); + } + + // Loop through each network + for ( var i = 1; i < networks.length; i++) { + if( !networks[i] || 0 === networks[i].length) continue; + var args = networks[i].split(' '); + var type = args[0]; + var name = args[2]; + name = name.replace(/\n/g,''); + + // Get network details + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcp, + args : '--getnetwork;' + name + ';' + type, + msg : 'hcp=' + hcp + ';type=' + type + ';network=' + name + }, + + success : function(data) { + data = decodeRsp(data); + loadNetworkTable(data); + } + }); + } // End of for + } // End of if + else { + if (data.rsp.length) { + var panelId = 'zvmNetworkResource'; + var info = $('#' + panelId).find('.ui-state-highlight'); + // If there is no info bar, create info bar + if (!info.length) { + info = createInfoBar("Error: "+data.rsp[0]); + $('#' + panelId).append(info); + } else { + info.append("
                          Error: "+data.rsp[0]); + } + } + // Normally load empty table, but not for networks + } +} + +/** + * Load disk pool contents into a table + * + * @param data HTTP request data + */ +function loadDiskPoolTable(data) { + // Remove loader if all hcps queried + var panelId = 'zvmDiskResource'; + if (!zhcpQueryCountForDisks) { + $('#' + panelId).find('img[src="images/loader.gif"]').remove(); + } + + var hcp2zvm = new Object(); + var args, hcp, pool, stat, tmp; + if (data && typeof data.rsp != "undefined") { + // Do not continue if the call failed + if (!data.rsp.length && data.rsp[0].indexOf("Failed") > 0 && data.rsp[0].indexOf("Error") > 0) { + return; + } + + // Obtain mapping for zHCP to zVM system + hcp2zvm = getHcpZvmHash(); + + args = data.msg.split(';'); + hcp = args[0].replace('hcp=', ''); + pool = args[1].replace('pool=', ''); + stat = jQuery.trim(args[2].replace('stat=', '')); + tmp = data.rsp[0].split(hcp + ': '); + } else { + // Provide empty values so the table will be generated + hcp = ''; + pool = ''; + stat = ''; + tmp = new Array(); + } + + // Resource tab ID + var info = $('#' + panelId).find('.ui-state-highlight'); + // If there is no info bar + if (!info.length) { + // Create info bar + info = createInfoBar('Below are disks that are defined in the EXTENT CONTROL file.'); + $('#' + panelId).append(info); + } + + // Get datatable + var tableId = 'zDiskDataTable'; + var dTable = getDiskDataTable(); + if (!dTable) { + // Create a datatable + var table = new DataTable(tableId); + // Resource headers: volume ID, device type, start address, and size + table.init( [ '', 'z/VM', 'Pool', 'Status', 'Volume', 'Device type', 'Starting address', 'Size' ]); + + // Append datatable to panel + $('#' + panelId).append(table.object()); + + // Turn into datatable + dTable = $('#' + tableId).dataTable({ + 'iDisplayLength': 50, + "bScrollCollapse": true, + "sScrollY": "400px", + "sScrollX": "110%", + "bAutoWidth": true, + "oLanguage": { + "oPaginate": { + "sNext": "", + "sPrevious": "" + } + } + }); + setDiskDataTable(dTable); + } + + // Skip index 0 and 1 because it contains nothing + for (var i = 2; i < tmp.length; i++) { + tmp[i] = jQuery.trim(tmp[i]); + var diskAttrs = tmp[i].split(' '); + var key = hcp2zvm[hcp] + "-" + pool + "-" + diskAttrs[0]; + var type = diskAttrs[1]; + + // Calculate disk size + var size; + if (type.indexOf('3390') != -1) { + size = convertCylinders2Gb(parseInt(diskAttrs[3])); + } else if (type.indexOf('9336') != -1) { + size = convertBlocks2Gb(parseInt(diskAttrs[3])) + } else { + size = 0; + } + dTable.fnAddData( [ '', hcp2zvm[hcp], pool, stat, diskAttrs[0], type, diskAttrs[2], diskAttrs[3] + " (" + size + "G)" ]); + } + + // Create actions menu + if (!$('#zvmDiskResourceActions').length) { + // Empty filter area + $('#' + tableId + '_length').empty(); + + // Add disk to pool + var addLnk = $('Add'); + addLnk.bind('click', function(event){ + openAddDisk2PoolDialog(); + }); + + // Delete disk from pool + var removeLnk = $('Remove'); + removeLnk.bind('click', function(event){ + var disks = getNodesChecked(tableId); + openRemoveDiskFromPoolDialog(disks); + }); + + // Refresh table + var refreshLnk = $('Refresh'); + refreshLnk.bind('click', function(event){ + $('#zvmDiskResource').empty().append(createLoader('')); + setDiskDataTable(''); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('xcat_hcp').indexOf(',') > -1) + hcps = $.cookie('xcat_hcp').split(','); + else + hcps.push($.cookie('xcat_hcp')); + + zhcpQueryCountForDisks = hcps.length; + // Query the disk pools for each + for (var i in hcps) { + if( !hcps[i] || 0 === hcps[i].length) continue; + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcps[i], + args : '--diskpoolnames', + msg : hcps[i] + }, + + success : function(data) { + data = decodeRsp(data); + getDiskPool(data); + } + }); + zhcpQueryCountForDisks--; + } + }); + + // Add ECKD to system + var addEckdLnk = $('Add ECKD'); + addEckdLnk.bind('click', function(event){ + openAddEckd2SystemDialog(hcp); + }); + + // Add Page or Spool + var addPageSpoolLnk = $('Add page/spool') + addPageSpoolLnk.bind('click', function(event){ + openAddPageSpoolDialog(hcp); + }); + + // Add EDEV to system + var addEdevLnk = $('Add EDEV'); + addEdevLnk.bind('click', function(event){ + openAddScsi2SystemDialog(hcp); + }); + + // Remove EDEV + var removeEdevLnk = $('Remove EDEV'); + removeEdevLnk.bind('click', function(event){ + openRemoveScsiDialog(hcp); + }); + + // Indicate disk is to be shared with various users + var shareLnk = $('Share disk'); + shareLnk.bind('click', function(event){ + var disks = getNodesChecked(tableId); + openShareDiskDialog(disks); + }); + + // Add Volume to system + var addVolumeLnk = $('Add volume to system'); + addVolumeLnk.bind('click', function(event){ + openAddVolume2SystemDialog(hcp); + }); + + // Remove Volume from system + var removeVolumeLnk = $('Remove volume from system'); + removeVolumeLnk.bind('click', function(event){ + openRemoveVolumeFromSystemDialog(hcp); + }); + + // Advanced menu + var advancedLnk = 'Advanced'; + var advancedMenu = createMenu([addEckdLnk, addPageSpoolLnk, addEdevLnk, removeEdevLnk, addVolumeLnk, removeVolumeLnk, shareLnk]); + + // Create action bar + var actionBar = $('
                          ').css("width", "450px"); + + // Create an action menu + var actionsMenu = createMenu([refreshLnk, addLnk, removeLnk, [advancedLnk, advancedMenu]]); + 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 + '_length').prepend(menuDiv); + $('#' + tableId + '_length').css({ + 'padding': '0px', + 'width': '500px' + }); + $('#' + tableId + '_filter').css('padding', '10px'); + menuDiv.append(actionBar); + } + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); +} + +/** + * Load zFCP pool contents into a table + * + * @param data HTTP request data + */ +function loadZfcpPoolTable(data) { + if (typeof console == "object"){ + console.log("Entering loadZfcpPoolTable."); + } + // Delete loader if last one + var panelId = 'zfcpResource'; + if (zhcpQueryCountForZfcps <= 0) { + $('#' + panelId).find('img[src="images/loader.gif"]').remove(); + } + + var hcp2zvm = new Object(); + var args, hcp, pool, tmp; + + // Resource tab ID + var info = $('#' + panelId).find('.ui-state-highlight'); + + // Is there any data passed? Process if some + if (typeof data.rsp != "undefined") { + // Do not continue if no data to add + if (!data.rsp.length) { + if (typeof console == "object"){ + console.log("data.rsp.length is 0."); + } + // If there is no info bar, create info bar + var msgError = '
                          Unexpected, no data returned on the lsvm --zfcppool call.'; + if (!info.length) { + info = createInfoBar(msgError); + $('#' + panelId).append(info); + } else { + info.append(msgError); + } + return; + } + if (data.rsp[0].indexOf("Failed") > 0 || data.rsp[0].indexOf("Error") > 0) { + if (typeof console == "object"){ + console.log("Failed on lsvm call for --zfcppool"); + } + var msgError = '
                          Error: Error on call to check zfcp pools: '+ data.rsp[0]; + // If there is no info bar, create info bar + if (!info.length) { + info = createInfoBar(msgError); + $('#' + panelId).append(info); + } else { + info.append(msgError); + } + return; + } + + // Obtain mapping for zHCP to zVM system + hcp2zvm = getHcpZvmHash(); + + args = data.msg.split(';'); + hcp = args[0].replace('hcp=', ''); + pool = args[1].replace('pool=', ''); + tmp = data.rsp[0].split(hcp + ': '); + } else { + // Provide empty values so the table will be generated + if (typeof console == "object"){ + console.log("Creating empty zfcp pool table."); + } + hcp = ''; + pool = '' + tmp = new Array(); + } + + // If there is no info bar, create info bar + if (!info.length) { + info = createInfoBar('Below are devices that are defined internally in the zFCP pools.'); + $('#' + panelId).append(info); + } + + // Get datatable + var tableId = 'zFcpDataTable'; + var dTable = getZfcpDataTable(); + if (!dTable) { + // Create a datatable + var table = new DataTable(tableId); + // Resource headers: status, WWPN, LUN, size, owner, channel, tag + table.init( [ '', 'z/VM', 'Pool', 'Status', 'Port name', 'Unit number', 'Size', 'Range', 'Owner', 'Channel', 'Tag' ]); + + // Append datatable to panel + $('#' + panelId).append(table.object()); + + // Turn into datatable + dTable = $('#' + tableId).dataTable({ + 'iDisplayLength': 50, + "bScrollCollapse": true, + "sScrollY": "400px", + "sScrollX": "110%", + "bAutoWidth": true, + "oLanguage": { + "oPaginate": { + "sNext": "", + "sPrevious": "" + } + } + }); + setZfcpDataTable(dTable); + } + if ((typeof data.rsp != "undefined") && (data.rsp.length > 0)) { + // Skip index 0 and 1 because it contains nothing + var key = ""; + for (var i = 2; i < tmp.length; i++) { + tmp[i] = jQuery.trim(tmp[i]); + var diskAttrs = tmp[i].split(','); + diskAttrs[0] = diskAttrs[0].toLowerCase(); + // Key contains row data to be returned when the checkbox is selected + var key = hcp2zvm[hcp] + '-' + pool + '-' + diskAttrs[2] + '-' + diskAttrs[1]; + dTable.fnAddData( [ '', hcp2zvm[hcp], pool, diskAttrs[0], diskAttrs[1], diskAttrs[2], diskAttrs[3], diskAttrs[4], diskAttrs[5], diskAttrs[6], diskAttrs[7] ]); + } + } + // Create actions menu + if (!$('#zFcpResourceActions').length) { + // Empty filter area + $('#' + tableId + '_length').empty(); + + // Add disk to pool + var addLnk = $('Add'); + addLnk.bind('click', function(event){ + openAddZfcp2PoolDialog(); + }); + + // Delete disk from pool + var removeLnk = $('Remove'); + removeLnk.bind('click', function(event){ + if (typeof console == "object"){ + console.log("Remove button clicked for tableId:"+tableId); + } + var disks = getNodesChecked(tableId); + openRemoveZfcpFromPoolDialog(disks); + }); + + // Refresh table + var refreshLnk = $('Refresh'); + refreshLnk.bind('click', function(event){ + $('#zfcpResource').empty().append(createLoader('')); + setZfcpDataTable(''); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('xcat_hcp').indexOf(',') > -1) + hcps = $.cookie('xcat_hcp').split(','); + else + hcps.push($.cookie('xcat_hcp')); + + // Query the disk pools for each + zhcpQueryCountForZfcps = hcps.length; + for (var i in hcps) { + if( !hcps[i] || 0 === hcps[i].length) continue; + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcps[i], + args : '--zfcppoolnames', + msg : hcps[i] + }, + + success : function(data) { + data = decodeRsp(data); + getZfcpPool(data); + } + }); + zhcpQueryCountForZfcps--; + } + }); + // Create action bar + var actionBar = $('
                          ').css("width", "450px"); + + // Create an action menu + var actionsMenu = createMenu([addLnk, removeLnk, refreshLnk]); + 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 + '_length').prepend(menuDiv); + $('#' + tableId + '_length').css({ + 'padding': '0px', + 'width': '500px' + }); + $('#' + tableId + '_filter').css('padding', '10px'); + menuDiv.append(actionBar); + } + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); +} + +/** + * Open dialog to remove disk from pool + * + * @param disks2remove Disks selected in table + */ +function openRemoveDiskFromPoolDialog(disks2remove) { + // Create form to delete disk from pool + var dialogId = 'zvmDeleteDiskFromPool'; + var deleteDiskForm = $('
                          '); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + + var disks = new Array(); + if (disks2remove.indexOf(',') > -1) + disks = disks2remove.split(','); + else + disks.push(disks2remove); + + // Pick the last zHCP and pool it finds + var args, tgtHcp = "", tgtPool = "", tgtVol = ""; + for (var i in disks) { + if( !disks[i] || 0 === disks[i].length) continue; + args = disks[i].split('-'); + tgtHcp = args[0]; + tgtPool = args[1]; + tgtVol += args[2] + ','; + } + + // Strip out last comma + tgtVol = tgtVol.slice(0, -1); + + // Create info bar + var info = createInfoBar('Remove a disk from a disk pool defined in the EXTENT CONTROL.'); + deleteDiskForm.append(info); + var action = $('
                          '); + var actionSelect = $(''); + action.append(actionSelect); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + + // Set region input based on those selected on table (if any) + var region = $('
                          '); + var group = $('
                          '); + deleteDiskForm.append(action, system, region, group); + + // Append options for hardware control points + //systemSelect.append($('')); + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + systemSelect.val(tgtHcp); + + actionSelect.change(function() { + if ($(this).val() == '1' || $(this).val() == '3') { + region.show(); + group.hide(); + } else if ($(this).val() == '2') { + region.show(); + group.show(); + } else if ($(this).val() == '7') { + region.val('FOOBAR'); + region.hide(); + group.show(); + } + }); + + // Generate tooltips + deleteDiskForm.find('div input[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 delete disk + deleteDiskForm.dialog({ + title:'Delete disk from pool', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 500, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var action = $(this).find('select[name=action]').val(); + var system = $(this).find('select[name=system]').val(); + var region = $(this).find('input[name=region]').val(); + var group = $(this).find('input[name=group]').val(); + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'select[name=action]', 'input[name=region]', 'input[name=group]'); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + if (!ready) { + // Show warning message + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + var args; + if (action == '2' || action == '7') + args = region + ';' + group; + else + args = region; + + // Remove disk from pool + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : system, + args : '--removediskfrompool;' + action + ';' + args, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Open dialog to add disk to pool + */ +function openAddDisk2PoolDialog() { + // Create form to add disk to pool + var dialogId = 'zvmAddDisk2Pool'; + var addDiskForm = $('
                          '); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + + // Create info bar + var info = createInfoBar('Add a disk to a disk pool defined in the EXTENT CONTROL. The disk has to already be attached to SYSTEM.'); + addDiskForm.append(info); + var action = $('
                          '); + var actionSelect = $(''); + action.append(actionSelect); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + var volume = $('
                          '); + var group = $('
                          '); + addDiskForm.append(action, system, volume, group); + + // Append options for hardware control points + //systemSelect.append($('')); + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + + // Generate tooltips + addDiskForm.find('div input[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 disk + addDiskForm.dialog({ + title:'Add disk to pool', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 500, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get inputs + var action = $(this).find('select[name=action]').val(); + var system = $(this).find('select[name=system]').val(); + var volume = $(this).find('input[name=volume]').val(); + var group = $(this).find('input[name=group]').val(); + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'select[name=action]', 'input[name=volume]', 'input[name=group]'); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + if (!ready) { + // Show warning message + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + var args; + if (action == '4') + args = volume + ';' + volume + ';' + group; + else + args = volume + ';' + group; + + // Add disk to pool + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : system, + args : '--adddisk2pool;' + action + ';' + args, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Open dialog to remove zFCP from pool + * + * @param devices2remove Comman separated devices selected in table + */ +function openRemoveZfcpFromPoolDialog(devices2remove) { + // Create form to delete device from pool + var dialogId = 'zvmDeleteZfcpFromPool'; + var deleteDiskForm = $('
                          '); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + + // Verify disks are in the same zFCP pool + var devices = devices2remove.split(','); + if (typeof console == "object"){ + console.log("Entering openRemoveZfcpFromPoolDialog. Device to remove:<"+devices2remove+">"); + } + var tmp, tgtPool, tgtHcp; + var tgtPort = ""; + var tgtUnitNo = ""; + for (var i in devices) { + if( !devices[i] || 0 === devices[i].length) continue; + tmp = devices[i].split('-'); + + if (tgtPool && tmp[1] != tgtPool) { + openDialog("warn", "Please select devices in the same zFCP"); + return; + } else { + tgtPool = tmp[1]; + } + + tgtHcp = tmp[0]; // Assume it is just one zHCP. Otherwise, this cannot be done on multiple zHCPs. + tgtUnitNo += tmp[2] + ","; + tgtPort = tmp[3]; + } + + // Strip out last comma + tgtUnitNo = tgtUnitNo.slice(0, -1); + + // Create info bar + var info = createInfoBar('Remove a zFCP device that is defined in a zFCP pool.'); + deleteDiskForm.append(info); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + + var pool = $('
                          '); + var unitNo = $('
                          '); + var portName = $('
                          '); + deleteDiskForm.append(system, pool, unitNo, portName); + + // Append options for hardware control points + //systemSelect.append($('')); + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + systemSelect.val(tgtHcp); + + // Generate tooltips + deleteDiskForm.find('div input[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 delete device + deleteDiskForm.dialog({ + title:'Delete device from pool', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 500, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + var system = $(this).find('select[name=system]').val(); + var pool = $(this).find('input[name=zfcpPool]').val(); + var unitNo = $(this).find('input[name=zfcpUnitNo]').val(); + var portName = $(this).find('input[name=zfcpPortName]').val(); + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'input[name=zfcpPool]', 'input[name=zfcpUnitNo]'); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + if (!ready) { + // Show warning message + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + var args = '--removezfcpfrompool;' + pool + ';' + unitNo; + if (portName) { + args += ';' + portName; + } + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : system, + args : args, + msg : dialogId + }, + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Open dialog to add zFCP to pool + */ +function openAddZfcp2PoolDialog() { + // Create form to add disk to pool + var dialogId = 'zvmAddDisk2Pool'; + var addDiskForm = $('
                          '); + var info = createInfoBar('Add a device to a zFCP pool defined in xCAT.'); + addDiskForm.append(info); + + // Obtain mapping for zHCP to zVM system + var hcp2zvm = new Object(); + hcp2zvm = getHcpZvmHash(); + + var system = $('
                          '); + var systemSelect = $(''); + system.append(systemSelect); + + var pool = $('
                          '); + var status = $('
                          '); + var portName = $('
                          '); + var unitNo = $('
                          '); + var size = $('
                          '); + var range = $('
                          '); + var owner = $('
                          '); + addDiskForm.append(system, pool, status, portName, unitNo, size, range, owner); + + // Create a array for hardware control points + //systemSelect.append($('')); + // Append options for hardware control points + for (var hcp in hcp2zvm) { + systemSelect.append($('')); + } + + // Generate tooltips + addDiskForm.find('div input[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 disk + addDiskForm.dialog({ + title:'Add device to pool', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 500, + buttons: { + "Ok": function(){ + // Delete any warning messages + $(this).find('.ui-state-error').remove(); + + var tgtSystem = $(this).find('select[name=system]').val(); + var tgtPool = $(this).find('input[name=zfcpPool]').val(); + var tgtStatus = $(this).find('select[name=zfcpStatus]').val(); + var tgtPortName = $(this).find('input[name=zfcpPortName]').val(); + var tgtUnitNo = $(this).find('input[name=zfcpUnitNo]').val(); + var tgtSize = $(this).find('input[name=zfcpSize]').val(); + var tgtRange = $(this).find('input[name=zfcpRange]').val(); + + // Device owner is optional + var tgtOwner = ""; + if ($(this).find('input[name=zfcpOwner]').val()) { + tgtOwner = $(this).find('input[name=zfcpOwner]').val(); + } + + // If inputs are not complete, show warning message + var ready = true; + var args = new Array('select[name=system]', 'input[name=zfcpPool]', 'select[name=zfcpStatus]', 'input[name=zfcpPortName]', 'input[name=zfcpUnitNo]'); + for (var i in args) { + if (!$(this).find(args[i]).val()) { + $(this).find(args[i]).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + $(this).find(args[i]).css('border', 'solid #BDBDBD 1px'); + } + } + + if (!ready) { + // Show warning message + var warn = createWarnBar('Please provide a value for each required field.'); + warn.prependTo($(this)); + return; + } + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + // zFCP range and owner are optional + var args = '--addzfcp2pool||' + tgtPool + '||' + tgtStatus + '||"' + tgtPortName + '"||' + tgtUnitNo + '||' + tgtSize; + if (tgtRange) { + args += '||' + tgtRange; + } if (tgtOwner) { + args += '||' + tgtOwner; + } + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chhypervisor', + tgt : tgtSystem, + args : args, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateResourceDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Update resource dialog + * + * @param data HTTP request data + */ +function updateResourceDialog(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': '90%' + }); + + infoBar.append(icon, msg, close); + infoBar.prependTo($('#' + dialogId)); +} + +/** + * Select all checkboxes in the datatable + * + * @param event Event on element + * @param obj Object triggering event + */ +function selectAllDisk(event, obj) { + // This will ascend from + var tableObj = obj.parents('.datatable'); + var status = obj.attr('checked'); + tableObj.find(' :checkbox').attr('checked', status); + + // Handle datatable scroll + tableObj = obj.parents('.dataTables_scroll'); + if (tableObj.length) { + tableObj.find(' :checkbox').attr('checked', status); + } + + event.stopPropagation(); +} + +/** + * Load network details into a table + * + * @param data HTTP request data + */ +function loadNetworkTable(data) { + // Remove loader if last one + var panelId = 'zvmNetworkResource'; + if (!zhcpQueryCountForNetworks) { + $('#' + panelId).find('img[src="images/loader.gif"]').remove(); + } + + // Get zVM host names + if (!$.cookie('xcat_zvms')) { + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + async: false, + data : { + cmd : 'webportal', + tgt : '', + args : 'lszvm', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setzVMCookies(data); + } + }); + } + + var zvms = $.cookie('xcat_zvms').split(','); + var hcp2zvm = new Object(); + var args, zvm, iHcp, tmp; + for (var i in zvms) { + if( !zvms[i] || 0 === zvms[i].length) continue; + args = zvms[i].split(':'); + zvm = args[0].toLowerCase(); + + if (args[1].indexOf('.') != -1) { + tmp = args[1].split('.'); + iHcp = tmp[0]; + } else { + iHcp = args[1]; + } + + hcp2zvm[iHcp] = zvm; + } + + var args = data.msg.split(';'); + var hcp = args[0].replace('hcp=', ''); + var type = args[1].replace('type=', ''); + var name = jQuery.trim(args[2].replace('network=', '')); + tmp = data.rsp[0].split(hcp + ': '); + + // Resource tab ID + var info = $('#' + panelId).find('.ui-state-highlight'); + // If there is no info bar + if (!info.length) { + // Create info bar + info = createInfoBar('Below are LANs/VSWITCHes available to use.'); + $('#' + panelId).append(info); + } + + // Get datatable + var dTable = getNetworkDataTable(); + if (!dTable) { + // Create table + var tableId = 'zNetworkDataTable'; + var table = new DataTable(tableId); + table.init( [ '', 'z/VM', 'Type', 'Name', 'Layer', 'Owner', 'Controller', 'Details' ]); + + // Append datatable to tab + $('#' + panelId).append(table.object()); + + // Turn into datatable + dTable = $('#' + tableId).dataTable({ + 'iDisplayLength': 50, + "bScrollCollapse": true, + "sScrollY": "400px", + "sScrollX": "110%", + "bAutoWidth": true, + "oLanguage": { + "oPaginate": { + "sNext": "", + "sPrevious": "" + } + } + }); + setNetworkDataTable(dTable); + + // Set the column width + var cols = table.object().find('thead tr th'); + cols.eq(0).css('width', '20px'); // HCP column + cols.eq(1).css('width', '20px'); // Type column + cols.eq(2).css('width', '20px'); // Name column + cols.eq(3).css({'width': '600px'}); // Details column + } + + // Skip index 0 because it contains nothing + var details = '
                          ';
                          +    for ( var i = 1; i < tmp.length; i++) {
                          +        details += tmp[i];
                          +    }
                          +    details += '
                          '; + + // Determine the OSI layer + var layer = "3"; + if (details.indexOf("ETHERNET") != -1) { + layer = "2"; + } + + // Find the vSwitch/VLAN owner + var regex = /(LAN|VSWITCH) (.*?)(?:\s|$)/g; + var owner = ""; + var match = ""; + if (type == "VSWITCH") { + owner = "SYSTEM"; + } else { + owner = regex.exec(details)[2]; + } + + // Find the vSwitch controller + regex = /(?:^|\s)Controller: (.*?)(?:\s|$)/g; + var controllers = ""; + match = ""; + while (match = regex.exec(details)) { + controllers += match[1] + ","; + } + controllers = controllers.substring(0, controllers.length - 1); // Delete last two characters + + dTable.fnAddData(['', '
                          ' + hcp2zvm[hcp] + '
                          ', '
                          ' + type + '
                          ', '
                          ' + name + '
                          ', '
                          ' + layer + '
                          ', '
                          ' + owner + '
                          ', '
                          ' + controllers + '
                          ', details]); + + // Create actions menu + if (!$('#networkResourceActions').length) { + // Empty filter area + $('#' + tableId + '_length').empty(); + + // Add Vswitch/Vlan + var addLnk = $('Add'); + addLnk.bind('click', function(event){ + openAddVswitchVlanDialog(); + }); + + // Remove Vswitch/Vlan + var removeLnk = $('Remove'); + removeLnk.bind('click', function(event){ + var networkList = getNodesChecked(tableId).split(','); + if (networkList) { + openRemoveVswitchVlanDialog(networkList); + } + }); + + // Refresh table + var refreshLnk = $('Refresh'); + refreshLnk.bind('click', function(event){ + $('#zvmNetworkResource').empty().append(createLoader('')); + setNetworkDataTable(''); + + // Create a array for hardware control points + var hcps = new Array(); + if ($.cookie('xcat_hcp').indexOf(',') > -1) + hcps = $.cookie('xcat_hcp').split(','); + else + hcps.push($.cookie('xcat_hcp')); + + // Query networks + zhcpQueryCountForNetworks = hcps.length; + for (var i in hcps) { + if( !hcps[i] || 0 === hcps[i].length) continue; + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : hcps[i], + args : '--getnetworknames', + msg : hcps[i] + }, + + success : function(data) { + data = decodeRsp(data); + getNetwork(data); + } + }); + zhcpQueryCountForNetworks--; + } + }); + + // Create action bar + var actionBar = $('
                          ').css("width", "450px"); + + // Create an action menu + var actionsMenu = createMenu([addLnk, removeLnk, refreshLnk]); + 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 + '_length').prepend(menuDiv); + $('#' + tableId + '_length').css({ + 'padding': '0px', + 'width': '500px' + }); + $('#' + tableId + '_filter').css('padding', '10px'); + menuDiv.append(actionBar); + } + + // Resize accordion + $('#zvmResourceAccordion').accordion('resize'); +} + +/** + * Connect a NIC to a Guest LAN + * + * @param data Data from HTTP request + */ +function connect2GuestLan(data) { + var rsp = data.rsp; + var args = data.msg.split(';'); + var node = args[0].replace('node=', ''); + var address = args[1].replace('addr=', ''); + var lanName = args[2].replace('lan=', ''); + var lanOwner = args[3].replace('owner=', ''); + + // Write ajax response to status bar + var prg = writeRsp(rsp, node + ': '); + $('#' + node + 'StatusBar').find('div').append(prg); + + // Continue if no errors found + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1 ) { + // Connect NIC to Guest LAN + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--connectnic2guestlan;' + address + ';' + lanName + ';' + + lanOwner, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + } else { + // Hide loader when error + var statusBarLoaderId = node + 'StatusBarLoader'; + $('#' + statusBarLoaderId).hide(); + } +} + +/** + * Connect a NIC to a VSwitch + * + * @param data Data from HTTP request + */ +function connect2VSwitch(data) { + var rsp = data.rsp; + var args = data.msg.split(';'); + var node = args[0].replace('node=', ''); + var address = args[1].replace('addr=', ''); + var vswitchName = args[2].replace('vsw=', ''); + var vswitchAware = args[3].replace('vlanaware=', ''); + var vswitchPortType = args[4].replace('porttype=', ''); + var vswitchLanId = args[5].replace('lanid=', ''); + + // Set variables to empty string if notaware or they contain "default" + if (vswitchAware.toLowerCase() == 'notaware' ) { + vswitchPortType = ''; + vswitchLanId = ''; + } else { + if (vswitchPortType.toLowerCase() == 'default' ) { + vswitchPortType = ''; + } + if (vswitchLanId.toLowerCase() == 'default' ) { + vswitchLanId = ''; + } + } + + // Write ajax response to status bar + var prg = writeRsp(rsp, node + ': '); + $('#' + node + 'StatusBar').find('div').append(prg); + + // Continue if no errors found + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1 ) { + // Connect NIC to VSwitch + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chvm', + tgt : node, + args : '--connectnic2vswitch;' + address + ';' + vswitchName + ';' + + vswitchPortType + ';' + vswitchLanId, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + updateZNodeStatus(data); + } + }); + } else { + // Hide loader when error + var statusBarLoaderId = node + 'StatusBarLoader'; + $('#' + statusBarLoaderId).hide(); + } +} + +/** + * Create provision existing node division + * + * @param inst Provision tab instance + * @return Provision existing node division + */ +function createZProvisionExisting(inst) { + // Create provision existing and hide it + var provExisting = $('
                          ').hide(); + + var vmFS = $('
                          '); + var vmLegend = $('Virtual Machine'); + vmFS.append(vmLegend); + provExisting.append(vmFS); + + var vmAttr = $('
                          '); + vmFS.append($('
                          ')); + vmFS.append(vmAttr); + + var osFS = $('
                          '); + var osLegend = $('Operating System'); + osFS.append(osLegend); + provExisting.append(osFS); + + var osAttr = $('
                          '); + osFS.append($('
                          ')); + osFS.append(osAttr); + + // Create group input + var group = $('
                          '); + var groupLabel = $(''); + group.append(groupLabel); + + // Turn on auto complete for group + 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) { + if( !tmp[i] || 0 === tmp[i].length) continue; + // 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, 'zNodesDatatableDIV' + inst); + } + }); + } else { + // If no groups are cookied + var groupInput = $(''); + group.append(groupInput); + } + vmAttr.append(group); + + // Create node input + var node = $('
                          '); + var nodeLabel = $(''); + var nodeDatatable = $('

                          Select a group to view its nodes

                          '); + node.append(nodeLabel); + node.append(nodeDatatable); + vmAttr.append(node); + + // Create operating system image input + var os = $('
                          '); + var osLabel = $(''); + var osSelect = $(''); + osSelect.append($('')); + + var imageNames = $.cookie('xcat_imagenames').split(','); + if (imageNames) { + imageNames.sort(); + for (var i in imageNames) { + if( !imageNames[i] || 0 === imageNames[i].length) continue; + osSelect.append($('')); + } + } + os.append(osLabel); + os.append(osSelect); + osAttr.append(os); + + // Create boot method drop down + var bootMethod = $('
                          '); + var methoddLabel = $(''); + var methodSelect = $(''); + methodSelect.append('' + + '' + + '' + + '' + + '' + ); + bootMethod.append(methoddLabel); + bootMethod.append(methodSelect); + osAttr.append(bootMethod); + + // Generate tooltips + provExisting.find('div input[title],select[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events: { + def: "mouseover,mouseout", + input: "mouseover,mouseout", + widget: "focus mouseover,blur mouseout", + tooltip: "mouseover,mouseout" + } + }); + + /** + * Provision existing + */ + var provisionBtn = createButton('Provision'); + provisionBtn.bind('click', function(event) { + // Remove any warning messages + $(this).parent().parent().find('.ui-state-error').remove(); + + var ready = true; + var errMsg = ''; + + // Get provision tab ID + var thisTabId = $(this).parent().parent().parent().attr('id'); + // Get provision tab instance + var inst = thisTabId.replace('zvmProvisionTab', ''); + + // Get nodes that were checked + var dTableId = 'zNodesDatatable' + inst; + var tgts = getNodesChecked(dTableId); + if (!tgts) { + errMsg += 'You need to select a node.
                          '; + ready = false; + } + + // Check operating system image + var os = $('#' + thisTabId + ' select[name=os]:visible'); + if (!os.val()) { + errMsg += 'You need to select a operating system image.'; + os.css('border', 'solid #FF0000 1px'); + ready = false; + } else { + os.css('border', 'solid #BDBDBD 1px'); + } + + // If all inputs are valid, ready to provision + if (ready) { + // Disable provision button + $(this).attr('disabled', 'true'); + + // Show loader + $('#zProvisionStatBar' + inst).show(); + $('#zProvisionLoader' + inst).show(); + + // Disable all inputs + var inputs = $('#' + thisTabId + ' input:visible'); + inputs.attr('disabled', 'disabled'); + + // Disable all selects + var selects = $('#' + thisTabId + ' select'); + selects.attr('disabled', 'disabled'); + + // Get operating system image + var osImage = $('#' + thisTabId + ' select[name=os]:visible').val(); + var tmp = osImage.split('-'); + var os = tmp[0]; + var arch = tmp[1]; + var profile = tmp[3]; + + /** + * (1) Set operating system + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeadd', + tgt : '', + args : tgts + ';noderes.netboot=zvm;nodetype.os=' + os + ';nodetype.arch=' + arch + ';nodetype.profile=' + profile, + msg : 'cmd=nodeadd;out=' + inst + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionExistingStatus(data); + } + }); + } else { + // Show warning message + var warn = createWarnBar(errMsg); + warn.prependTo($(this).parent().parent()); + } + }); + provExisting.append(provisionBtn); + + return provExisting; +} + +/** + * Create provision new node division + * + * @param inst Provision tab instance + * @return Provision new node division + */ +function createZProvisionNew(inst) { + if (typeof console == "object"){ + console.log("Entering createZProvisionNew. Inst value:"+inst); + } + // Create provision new node division + var provNew = $('
                          '); + + // Create VM fieldset + var vmFS = $('
                          '); + var vmLegend = $('Virtual Machine'); + vmFS.append(vmLegend); + provNew.append(vmFS); + + var vmAttr = $('
                          '); + vmFS.append($('
                          ')); + vmFS.append(vmAttr); + + // Create OS fieldset + var osFS = $('
                          '); + var osLegend = $('Operating System'); + osFS.append(osLegend); + provNew.append(osFS); + + // Create hardware fieldset + var hwFS = $('
                          '); + var hwLegend = $('Hardware'); + hwFS.append(hwLegend); + provNew.append(hwFS); + + var hwAttr = $('
                          '); + hwFS.append($('
                          ')); + hwFS.append(hwAttr); + + // Create tabs for basic and advanced hardware configuration + var hwTab = new Tab('hwConfig' + inst); + hwTab.init(); + hwAttr.append(hwTab.object()); + + var osAttr = $('
                          '); + osFS.append($('
                          ')); + osFS.append(osAttr); + + // Create group input + var group = $('
                          '); + var groupLabel = $(''); + var groupInput = $(''); + // Get groups on-focus + 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); + vmAttr.append(group); + + // Create node input + var nodeName = $('
                          '); + var nodeLabel = $(''); + var nodeInput = $(''); + nodeName.append(nodeLabel); + nodeName.append(nodeInput); + vmAttr.append(nodeName); + + // Create user ID input + var userId = $('
                          '); + vmAttr.append(userId); + + // Create hardware control point input + var hcpDiv = $('
                          '); + var hcpNodeLabel = $(''); + var hcpNodeInput = $(''); + var hcpHiddenInput = $(''); + hcpNodeInput.blur(function() { + + if (typeof console == "object") { + console.log("Display loading bar "); + } + // Show the status bar with a message and loading gif + $('#'+'zProvisionStatBar'+inst).find('div').append("Loading zhcp information..."); + $('#'+'zProvisionStatBar'+inst).find('div').append(""); + $('#'+'zProvisionStatBar'+inst).show(); + + // list of calls after the zhcp is verified. Used to determine when in progress gif is to be removed. + var ajaxCalls = {"diskpoolnames":1, "zfcppoolnames":1, "userprofilenames":1}; + var zhcpToCheck = $(this).val(); + var zhcpField = $(this); + var provisionStatusBar = $('#'+'zProvisionStatBar'+inst); + + // Make sure border is set back to black + zhcpField.css('border', 'solid #BDBDBD 1px'); + + if ($(this).val()) { + // Check if this is a valid node by making network names call. + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : zhcpToCheck, + args : '--getnetworknames', + msg : zhcpToCheck + }, + + success : function(data) { + data = decodeRsp(data); + if (data.rsp.length && (data.rsp[0].indexOf("Failed") > -1 || data.rsp[0].indexOf("Invalid") > -1 || data.rsp[0].indexOf("Error") > -1 ) ) { + // Remove the progress gif, since bailing out + removeProvisionLoadingGif(provisionStatusBar); + + // Create warning dialog + var warning = createWarnBar('Failure getting network data for hardware control point ' + zhcpToCheck + '
                          The hcp field must be a xCAT node name.'); + var warnDialog = $('
                          ').append(warning); + + // highlight the hcp field + zhcpField.css('border', 'solid #FF0000 1px'); + + // Open warning dialog + warnDialog.dialog({ + title:'Warning', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function() { + $(this).dialog("close"); + } + } + }); + + } else { + // Node is good, now set some cookies from network, then check/set other cookies + setNetworkCookies(data); + + // Get the HCP name from the hcp node name + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsdef', + tgt : '', + args : zhcpToCheck, + msg : 'zhcpFullName' + }, + + success : function(data) { + data = decodeRsp(data); + if (data.rsp.length && (data.rsp[0].indexOf("Failed") > -1 || data.rsp[0].indexOf("Invalid") > -1) ) { + // Remove the progress gif, since bailing out + removeProvisionLoadingGif(provisionStatusBar); + + // Create warning dialog + var warning = createWarnBar('Failure getting hcp data from hardware control point ' + zhcpToCheck + '
                          The hcp field must be a valid xCAT node name.'); + var warnDialog = $('
                          ').append(warning); + + // highlight the hcp field + zhcpField.css('border', 'solid #FF0000 1px'); + + // Open warning dialog + warnDialog.dialog({ + title:'Warning', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function() { + $(this).dialog("close"); + } + } + }); + } else { + // Now set the hidden hcp field with the full name + // Clear hash table containing definable node attributes + nodeAttrs = new Array(); + + // Get definable attributes + // Data returned + var rsp = data.rsp; + // Group name + var group = data.msg; + // Hash of node attributes + var attrs = new Object(); + + // Go through each attribute + var node, args; + for (var i in rsp) { + // Get node name, skip processing + if (rsp[i].indexOf('Object name:') > -1) { + i++; + } + + // Get key and value + args = rsp[i].split('=', 2); + var key = jQuery.trim(args[0]); + var val = jQuery.trim(rsp[i].substring(rsp[i].indexOf('=') + 1, rsp[i].length)); + + // If this is zhcp key then save full name in hidden field + if (key == "hcp") { + hcpHiddenInput.val(val); + } + + } + + } + } + }); + + if (typeof console == "object"){ + console.log("Looking for cookies from <" + zhcpToCheck + ">"); + } + + if (!$.cookie('xcat_' + zhcpToCheck + 'diskpools')) { + // Get disk pools + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : zhcpToCheck, + args : '--diskpoolnames', + msg : zhcpToCheck + }, + + success : function(data) { + data = decodeRsp(data); + setDiskPoolCookies(data); + }, + complete : function() { + checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "diskpoolnames"); + } + }); + } else { + checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "diskpoolnames"); + } + + if (!$.cookie('xcat_' + zhcpToCheck + 'zfcppools')) { + // Get zFCP pools + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : zhcpToCheck, + args : '--zfcppoolnames', + msg : zhcpToCheck + }, + + success : function(data) { + data = decodeRsp(data); + setZfcpPoolCookies(data); + }, + complete : function() { + checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "zfcppoolnames"); + } + }); + } else { + checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "zfcppoolnames"); + } + + if (!$.cookie('xcat_' + zhcpToCheck + 'userprofiles')) { + // Get zFCP pools + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + async: false, + data : { + cmd : 'lsvm', + tgt : zhcpToCheck, + args : '--userprofilenames', + msg : zhcpToCheck + }, + + success : function(data) { + data = decodeRsp(data); + setUserProfilesCookies(data); + }, + complete : function() { + checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "userprofilenames"); + } + }); + } else { + checkProvisionCallsDone(provisionStatusBar, ajaxCalls, "userprofilenames"); + } + + // Reset user profile and network drop down box + var thisTabId = zhcpField.parents('.tab').attr('id'); + var thisUserProfile = $('#' + thisTabId + ' select[name=userProfile]'); + thisUserProfile.children().remove(); + + var definedUserProfiles = $.cookie('xcat_' + zhcpToCheck + 'userprofiles').split(','); + for (var i in definedUserProfiles) { + if( !definedUserProfiles[i] || 0 === definedUserProfiles[i].length) continue; + thisUserProfile.append(''); + } + + var thisNetwork = $('#' + thisTabId + ' select[name=network]'); + thisNetwork.children().remove(); + thisNetwork.append(''); // No profile option + var definedNetworks = $.cookie('xcat_' + zhcpToCheck + 'networks').split(','); + for (var i in definedNetworks) { + if( !definedNetworks[i] || 0 === definedNetworks[i].length) continue; + if (!jQuery.trim(definedNetworks[i])) + continue; + + var directoryEntry, interfaceName; + + // Generate directory entry statement for vSwitch, hipersocket, and guest LAN + if (definedNetworks[i].indexOf('VSWITCH ') != -1) { + interfaceName = jQuery.trim(definedNetworks[i].replace('VSWITCH ', '')); + directoryEntry = "TYPE QDIO LAN " + interfaceName; + } else if (definedNetworks[i].indexOf('LAN:HIPERS ') != -1) { + interfaceName = jQuery.trim(definedNetworks[i].replace('LAN:HIPERS ', '')); + directoryEntry = "TYPE HIPERSOCKETS LAN " + interfaceName; + } else { + interfaceName = jQuery.trim(definedNetworks[i].replace('LAN:QDIO ', '')); + directoryEntry = "TYPE QDIO LAN " + interfaceName; + } + + thisNetwork.append(''); + } + + // Update user entry on change + thisNetwork.change(function() { + updateUserEntry(thisTabId); + }); + + thisUserProfile.change(function() { + updateUserEntry(thisTabId); + }); + } + } + }); + } + }); + hcpDiv.append(hcpNodeLabel); + hcpDiv.append(hcpNodeInput); + hcpDiv.append(hcpHiddenInput); + vmAttr.append(hcpDiv); + + // Create an advanced link to set IP address and hostname + var advancedLnk = $(''); + vmAttr.append(advancedLnk); + var advanced = $('
                          ').hide(); + vmAttr.append(advanced); + + var ip = $('
                          '); + advanced.append(ip); + var hostname = $('
                          '); + advanced.append(hostname); + + // Show IP address and hostname inputs on-click + advancedLnk.click(function() { + advanced.toggle(); + }); + + // Create operating system image input + var os = $('
                          '); + var osLabel = $(''); + var osSelect = $(''); + osSelect.append($('')); + + var imageNames = $.cookie('xcat_imagenames').split(','); + if (imageNames) { + imageNames.sort(); + for (var i in imageNames) { + if( !imageNames[i] || 0 === imageNames[i].length) continue; + osSelect.append($('')); + } + } + os.append(osLabel); + os.append(osSelect); + osAttr.append(os); + + // Create user entry input + var defaultChkbox = $('').click(function() { + // Remove any warning messages + $(this).parents('.form').find('.ui-state-error').remove(); + + // Get tab Id + var thisTabId = $(this).parents('.ui-tabs-panel').parents('.ui-tabs-panel').attr('id'); + + // Get objects for HCP, user ID, and OS + var userId = $('#' + thisTabId + ' input[name=userId]'); + var os = $('#' + thisTabId + ' select[name=os]'); + + // Get default user entry when clicked + if ($(this).attr('checked')) { + if (!os.val() || !userId.val()) { + // Show warning message + var warn = createWarnBar('Please specify the operating system and user ID before checking this box'); + warn.prependTo($(this).parents('.form')); + + // Highlight empty fields + jQuery.each([os, userId], function() { + if (!$(this).val()) { + $(this).css('border', 'solid #FF0000 1px'); + } + }); + } else { + // Un-highlight empty fields + jQuery.each([os, userId], function() { + $(this).css('border', 'solid #BDBDBD 1px'); + }); + + // Get profile name + var tmp = os.val().split('-'); + var profile = tmp[3]; + + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'getdefaultuserentry;' + profile, + msg : thisTabId + }, + + success :function(data) { + data = decodeRsp(data); + // Populate user entry + var tabId = data.msg; + var entry = new String(data.rsp); + var userId = $('#' + tabId + ' input[name=userId]').val(); + entry = entry.replace(new RegExp('LXUSR', 'g'), userId); + $('#' + tabId + ' textarea:visible').val(entry); + } + }); + } + } else { + $('#' + thisTabId + ' textarea:visible').val(''); + + // Un-highlight empty fields + jQuery.each([os, userId], function() { + $(this).css('border', 'solid #BDBDBD 1px'); + }); + } + }); + var userEntry = $('
                          '); + userEntry.append($('').append(defaultChkbox, 'Use default')); + + // Add division on basic tab for specifying: memory, # of CPUs, privilege, user profile, and network. + var basicConfig = $('
                          '); + var userProfile = $('
                          '); + var cpuSelect = $('').change(function() { + updateUserEntry('zvmProvisionTab' + inst); + }); + var cpuCount = $('
                          ').append(cpuSelect); + var memorySlider = $('
                          '); + var memorySize = $(''); + var memory = $('
                          ').append(memorySlider, memorySize); + var acceptableMemorySize = ['512M', '1024M', '2G', '3G', '4G', '5G', '6G', '7G', '8G']; + memorySlider.slider({ + value: 0, + min: 0, + max: 8, + step: 1, + slide: function(event, ui) { + $('#basicConfig' + inst + ' input[name=memory]').val(acceptableMemorySize[ui.value]); + + // Update user entry on change + updateUserEntry('zvmProvisionTab' + inst); + } + }); + + // Initialize storage size + memorySize.val(acceptableMemorySize[0]); + + var privilege = $('
                          ' + + '
                          ' + + ' A - Primary system operator
                          ' + + ' B - System resource operator
                          ' + + ' C - System programmer
                          ' + + ' D - Spooling operator
                          ' + + ' E - System analyst
                          ' + + ' F - IBM service representative
                          ' + + ' G - General user
                          ' + + '
                          ' + + '
                          '); + privilege.find('input').change(function() { + updateUserEntry('zvmProvisionTab' + inst); + }); + + var network = $('
                          '); + + var vswitchvlan = $('

                          ' + + '
                          ' + + '
                          '); + vswitchvlan.find('input').change(function() { + updateUserEntry('zvmProvisionTab' + inst); + }); + vswitchvlan.find('select').change(function() { + updateUserEntry('zvmProvisionTab' + inst); + }); + + vswitchvlan.hide(); + basicConfig.append(userProfile, cpuCount, memory, privilege, network, vswitchvlan); + hwTab.add('basicConfig' + inst, 'Basic', basicConfig, false); + + // Add division on advanced tab for specifying user directory entry + hwTab.add('advancedConfig' + inst, 'Advanced', userEntry, false); + + // Create disk table + var diskDiv = $('
                          '); + var diskLabel = $(''); + var diskTable = $('
                          '); + var diskHeader = $(' Type Address Size Mode Pool Password IPLNone
                          '); + // Adjust header width + diskHeader.find('th').css( { + 'width' : '80px' + }); + diskHeader.find('th').eq(0).css( { + 'width' : '20px' + }); + var diskBody = $(''); + var diskFooter = $(''); + + /** + * Add disks + */ + var addDiskLink = $('Add disk'); + addDiskLink.bind('click', function(event) { + // Get list of disk pools + var thisTabId = $(this).parents('.tab').attr('id'); + var thisHcp = $('#' + thisTabId + ' input[name=hcp]').val(); + var definedPools = null; + if (thisHcp) { + // Get node without domain name + var temp = thisHcp.split('.'); + definedPools = $.cookie('xcat_' + temp[0] + 'diskpools').split(','); + } else { + var warning = createWarnBar('You must fill in a hardware control point before adding a disk.'); + var warnDialog = $('
                          ').append(warning); + + // Open dialog + warnDialog.dialog({ + title:'Warning', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function() { + $(this).dialog("close"); + } + } + }); + return false; + } + + // Create a row + var diskRow = $(''); + + // Add remove button + var removeBtn = $(''); + var col = $('').append(removeBtn); + removeBtn.bind('click', function(event) { + diskRow.remove(); + }); + diskRow.append(col); + + // Create disk type drop down + var diskType = $(''); + var diskTypeSelect = $(''); + diskTypeSelect.append('' + + '' + ); + diskType.append(diskTypeSelect); + diskRow.append(diskType); + + // Create disk address input + var diskAddr = $(''); + diskRow.append(diskAddr); + + // Create disk size input + var diskSize = $(''); + diskRow.append(diskSize); + + // Create disk mode input + var diskMode = $(''); + var diskModeSelect = $(''); + diskModeSelect.append('' + + '' + + '' + + '' + + '' + + '' + + '' + ); + diskMode.append(diskModeSelect); + diskRow.append(diskMode); + + // Create disk pool drop down + var diskPool = $(''); + var diskPoolSelect = $(''); + for (var i in definedPools) { + diskPoolSelect.append(''); + } + diskPool.append(diskPoolSelect); + diskRow.append(diskPool); + + // Create disk password input + var diskPw = $(''); + diskRow.append(diskPw); + + // Create IPL checkbox + //var diskIpl = $(''); + var diskIpl = $(''); + diskRow.append(diskIpl); + diskIpl.find('input').change(function() { + updateUserEntry(thisTabId); + }); + + diskBody.append(diskRow); + + // Generate tooltips + diskBody.find('td input[title],select[title]').tooltip({ + position: "top right", + offset: [-4, 4], + effect: "fade", + opacity: 0.7, + predelay: 800, + events: { + def: "mouseover,mouseout", + input: "mouseover,mouseout", + widget: "focus mouseover,blur mouseout", + tooltip: "mouseover,mouseout" + } + }); + }); + + // Create disk table + diskFooter.append(addDiskLink); + diskTable.append(diskHeader); + diskTable.append(diskBody); + diskTable.append(diskFooter); + + diskDiv.append(diskLabel); + diskDiv.append(diskTable); + hwAttr.append(diskDiv); + + // Create zFCP table + var zfcpDiv = $('
                          '); + var zfcpLabel = $(''); + var zfcpTable = $('
                          '); + var zfcpHeader = $(' Address Size Pool Tag Port Name Unit # LOADDEV'); + // Adjust header width + zfcpHeader.find('th').css({ + 'width' : '80px' + }); + zfcpHeader.find('th').eq(0).css({ + 'width' : '20px' + }); + var zfcpBody = $(''); + var zfcpFooter = $(''); + + /** + * Add zFCP devices + */ + var addZfcpLink = $('Add zFCP'); + addZfcpLink.bind('click', function(event) { + // Get list of disk pools + var thisTabId = $(this).parents('.tab').attr('id'); + var thisHcp = $('#' + thisTabId + ' input[name=hcp]').val(); + var definedPools = null; + if (thisHcp) { + // Get node without domain name + var temp = thisHcp.split('.'); + definedPools = $.cookie('xcat_' + temp[0] + 'zfcppools').split(','); + } else { + var warning = createWarnBar('You must fill in a hardware control point before adding a zFCP.'); + var warnDialog = $('
                          ').append(warning); + + // Open dialog + warnDialog.dialog({ + title:'Warning', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function() { + $(this).dialog("close"); + } + } + }); + + } + + // Create a row + var zfcpRow = $(''); + + // Add remove button + var removeBtn = $(''); + var col = $('').append(removeBtn); + removeBtn.bind('click', function(event) { + zfcpRow.remove(); + }); + zfcpRow.append(col); + + // Create disk address input + var zfcpAddr = $(''); + zfcpRow.append(zfcpAddr); + + // Create disk size input + var zfcpSize = $(''); + zfcpRow.append(zfcpSize); + + // Create zFCP pool drop down + var zfcpPool = $(''); + var zfcpPoolSelect = $(''); + for (var i in definedPools) { + zfcpPoolSelect.append(''); + } + zfcpPool.append(zfcpPoolSelect); + zfcpRow.append(zfcpPool); + + // Create disk tag + var zfcpTag = $(''); + zfcpRow.append(zfcpTag); + + // Create device port name + var zfcpPortName = $(''); + zfcpRow.append(zfcpPortName); + + // Create device unit number + var zfcpUnitNo = $(''); + zfcpRow.append(zfcpUnitNo); + + // Create LOADDEV radio button + var zfcpLoaddev = $(''); + zfcpRow.append(zfcpLoaddev); + + zfcpBody.append(zfcpRow); + + // Generate tooltips + zfcpBody.find('td input[title],select[title]').tooltip({ + position: "top right", + offset: [-4, 4], + effect: "fade", + opacity: 0.7, + predelay: 800, + events: { + def: "mouseover,mouseout", + input: "mouseover,mouseout", + widget: "focus mouseover,blur mouseout", + tooltip: "mouseover,mouseout" + } + }); + }); + + zfcpFooter.append(addZfcpLink); + zfcpTable.append(zfcpHeader); + zfcpTable.append(zfcpBody); + zfcpTable.append(zfcpFooter); + + zfcpDiv.append(zfcpLabel); + zfcpDiv.append(zfcpTable); + hwAttr.append(zfcpDiv); + + // Generate tooltips + provNew.find('div input[title],select[title],textarea[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events: { + def: "mouseover,mouseout", + input: "mouseover,mouseout", + widget: "focus mouseover,blur mouseout", + tooltip: "mouseover,mouseout" + } + }); + + // Disable IPL column if advanced tab is selected + hwTab.object().tabs({ + select: function(event, ui) { + // Get provision tab instance + var thisTabId = $(this).parents('.ui-tabs-panel').attr('id'); + var inst = thisTabId.replace('zvmProvisionTab', ''); + + // Disable and de-select IPL device + if (ui.index == 1) { + $('#' + thisTabId + ' table:eq(0):visible tbody tr td:nth-child(8) input').attr('disabled','disabled'); + } else { + $('#' + thisTabId + ' table:eq(0):visible tbody tr td:nth-child(8) input').removeAttr('disabled'); + } + + $('#' + thisTabId + ' table:eq(0):visible tbody tr td:nth-child(8) input').removeAttr('checked'); + } + }); + + /** + * Provision new + */ + var provisionBtn = createButton('Provision'); + provisionBtn.bind('click', function(event) { + // Remove any warning messages + $(this).parent().parent().find('.ui-state-error').remove(); + + var ready = true; + var errMsg = ''; + + // Get tab ID + var thisTabId = $(this).parents('.ui-tabs-panel').attr('id'); + // Get provision tab instance + var inst = thisTabId.replace('zvmProvisionTab', ''); + + // Get the selected hardware configuration tab + // Basic tab index = 0 & advanced tab index = 1 + var hwTabIndex = $("#hwConfig" + inst).tabs('option', 'selected'); + + // Check node name, userId, hardware control point, and group + // Check disks and zFCP devices + var inputs = $('#' + thisTabId + ' input:visible'); + for (var i = 0; i < inputs.length; i++) { + // Do not check some inputs + if (inputs.eq(i).attr('name') == 'memory') { + // There should always be a value for memory + // Do not change the border + continue; + } else if (!inputs.eq(i).val() + && inputs.eq(i).attr('type') != 'password' + && inputs.eq(i).attr('name') != 'zfcpTag' + && inputs.eq(i).attr('name') != 'zfcpPortName' + && inputs.eq(i).attr('name') != 'zfcpUnitNo') { + inputs.eq(i).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + inputs.eq(i).css('border', 'solid #BDBDBD 1px'); + } + } + + var selects = $('#' + thisTabId + ' select:visible'); + for (var i = 0; i < selects.length; i++) { + if (!selects.eq(i).val() && selects.eq(i).attr('name') != 'os' && selects.eq(i).attr('name') != 'userProfile' && selects.eq(i).attr('name') != 'network') { + selects.eq(i).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + selects.eq(i).css('border', 'solid #BDBDBD 1px'); + } + } + + if (hwTabIndex == 1) { + // Check user entry + var thisUserEntry = $('#' + thisTabId + ' textarea:visible'); + thisUserEntry.val(thisUserEntry.val().toUpperCase()); + if (!thisUserEntry.val()) { + thisUserEntry.css('border', 'solid #FF0000 1px'); + ready = false; + } else { + thisUserEntry.css('border', 'solid #BDBDBD 1px'); + } + + // Check if user entry contains user ID + var thisUserId = $('#' + thisTabId + ' input[name=userId]:visible'); + var pos = thisUserEntry.val().indexOf('USER ' + thisUserId.val().toUpperCase()); + if (pos < 0) { + + pos = thisUserEntry.val().indexOf('IDENTITY ' + thisUserId.val().toUpperCase()); + if (pos < 0) { + errMsg = errMsg + 'The directory entry does not contain the correct user/identity ID.
                          '; + ready = false; + } + } + } + var hostnameCheck = $('#' + thisTabId + ' input[name=hostname]').val(); + if (hostnameCheck.length > 70) { + errMsg = errMsg + 'The host name cannot be longer than 70 characters.
                          '; + $('#' + thisTabId + ' input[name=hostname]').css('border', 'solid #FF0000 1px'); + ready = false; + } + + // Show error message for missing inputs + if (!ready) { + errMsg = errMsg + 'Please provide a value for each missing field.
                          '; + } + + // If no operating system is specified, create only user entry + os = $('#' + thisTabId + ' select[name=os]:visible'); + + // Check number of disks + var diskRows = $('#' + thisTabId + ' table tr'); + // If an OS is given, disks are needed + if (os.val() && (diskRows.length < 1)) { + errMsg = errMsg + 'You need to add at some disks.
                          '; + ready = false; + } + + // If this is basic mode, check for a disk with IPL radio button and zFCP with LOADDEV button + // Cannot have both. (In advanced mode they create the directory entries.) + if (hwTabIndex == 0) { + // Find a device to be IPLed? + var ECKD_FBA_diskRows = $('#' + thisTabId + ' table:eq(0):visible tbody tr'); + var iplSet = 0; + for (var i = 0; i < ECKD_FBA_diskRows.length; i++) { + var diskArgs = ECKD_FBA_diskRows.eq(i).find('td'); + if (diskArgs.eq(7).find('input').attr("checked") === true) { + iplSet = 1; + break; + } + } + + // Check if zFCP loaddev checked + var zfcpRows = $('#' + thisTabId + ' table:eq(1):visible tbody tr'); + if (zfcpRows.length > 0) { + for ( var i = 0; i < zfcpRows.length; i++) { + var diskArgs = zfcpRows.eq(i).find('td'); + // This is either true or false + var loaddev = diskArgs.eq(7).find('input').attr('checked'); + if (loaddev && iplSet) { + errMsg = errMsg + 'You cannot have both disk IPL and zFCP LOADDEV, can only IPL one device.
                          '; + ready = false; + } + } + } + } + + // If inputs are valid, ready to provision + if (ready) { + // Generate user directory entry if basic tab is selected + if (hwTabIndex == 0) { + updateUserEntry(thisTabId); + } + + if (!os.val()) { + // If no OS is given, create a virtual server + var msg = ''; + if (diskRows.length > 0) { + msg = 'Do you want to create a virtual server without an operating system?'; + } else { + // If no disks are given, create a virtual server (no disk) + msg = 'Do you want to create a virtual server without an operating system or disks?'; + } + + // Open dialog to confirm + var confirmDialog = $('

                          ' + msg + '

                          '); + confirmDialog.dialog({ + title:'Confirm', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function(){ + // Disable provision button + provisionBtn.attr('disabled', 'true'); + + // Show loader + $('#zProvisionStatBar' + inst).show(); + $('#zProvisionLoader' + inst).show(); + + // Disable add disk button + addDiskLink.attr('disabled', 'true'); + + // Disable close button on disk table + $('#' + thisTabId + ' table span').unbind('click'); + + // Disable all inputs + var inputs = $('#' + thisTabId + ' input'); + inputs.attr('disabled', 'disabled'); + + // Disable all selects + var selects = $('#' + thisTabId + ' select'); + selects.attr('disabled', 'disabled'); + + // Add a new line at the end of the user entry + var textarea = $('#' + thisTabId + ' textarea'); + var tmp = jQuery.trim(textarea.val()); + textarea.val(tmp + '\n'); + textarea.attr('readonly', 'readonly'); + textarea.css( { + 'background-color' : '#F2F2F2' + }); + + // Get node name + var node = $('#' + thisTabId + ' input[name=nodeName]').val(); + // Get userId + var userId = $('#' + thisTabId + ' input[name=userId]').val(); + // Get hardware control point + var hcp = $('#' + thisTabId + ' input[name=hcp]').val(); + // Get group + var group = $('#' + thisTabId + ' input[name=group]').val(); + // Get IP address and hostname + var ip = $('#' + thisTabId + ' input[name=ip]').val(); + var hostname = $('#' + thisTabId + ' input[name=hostname]').val(); + + // Generate arguments to sent + var args = node + ';zvm.hcp=' + hcp + + ';zvm.userid=' + userId + + ';nodehm.mgt=zvm' + + ';groups=' + group; + if (ip) + args += ';hosts.ip=' + ip; + + if (hostname) + args += ';hosts.hostnames=' + hostname; + + /** + * (1) Define node + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeadd', + tgt : '', + args : args, + msg : 'cmd=nodeadd;out=' + inst + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + + $(this).dialog("close"); + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); + } else { + /** + * Create a virtual server and install OS + */ + + // Disable provision button + $(this).attr('disabled', 'true'); + + // Show loader + $('#zProvisionStatBar' + inst).show(); + $('#zProvisionLoader' + inst).show(); + + // Disable add disk button + addDiskLink.attr('disabled', 'true'); + + // Disable close button on disk table + $('#' + thisTabId + ' table span').unbind('click'); + + // Disable all inputs + var inputs = $('#' + thisTabId + ' input'); + inputs.attr('disabled', 'disabled'); + inputs.css( { + 'background-color' : '#F2F2F2' + }); + + // Disable all selects + var selects = $('#' + thisTabId + ' select'); + selects.attr('disabled', 'disabled'); + selects.css( { + 'background-color' : '#F2F2F2' + }); + + // Add a new line at the end of the user entry + var textarea = $('#' + thisTabId + ' textarea'); + var tmp = jQuery.trim(textarea.val()); + textarea.val(tmp + '\n'); + textarea.attr('readonly', 'readonly'); + textarea.css( { + 'background-color' : '#F2F2F2' + }); + + // Get node name + var node = $('#' + thisTabId + ' input[name=nodeName]').val(); + // Get userId + var userId = $('#' + thisTabId + ' input[name=userId]').val(); + // Get hardware control point + var hcp = $('#' + thisTabId + ' input[name=hcp]').val(); + // Get group + var group = $('#' + thisTabId + ' input[name=group]').val(); + // Get IP address and hostname + var ip = $('#' + thisTabId + ' input[name=ip]').val(); + var hostname = $('#' + thisTabId + ' input[name=hostname]').val(); + + // Generate arguments to sent + var args = node + ';zvm.hcp=' + hcp + + ';zvm.userid=' + userId + + ';nodehm.mgt=zvm' + + ';groups=' + group; + if (ip) + args += ';hosts.ip=' + ip; + + if (hostname) + args += ';hosts.hostnames=' + hostname; + + /** + * (1) Define node + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeadd', + tgt : '', + args : args, + msg : 'cmd=nodeadd;out=' + inst + }, + + success : function(data) { + data = decodeRsp(data); + updateZProvisionNewStatus(data); + } + }); + } + } else { + // Show warning message + var warn = createWarnBar(errMsg); + warn.prependTo($(this).parent().parent()); + } + }); + provNew.append(provisionBtn); + + return provNew; +} +/** + * Remove zprovision loading gif for zhcp and message + * + * @param division holding the gif and message + */ +function removeProvisionLoadingGif(provisionStatBar) { + + // Only remove the status bar message and gif we added, then hide the status bar + var items = provisionStatBar.find('div').children(); + for (var i = 0; i< items.length; i++) { + var nname = items[i].nodeName; + var myid = items[i].id; + if (nname == "B" && myid == "loadzhcp") { + items[i].remove() + } else if (nname == "IMG" && myid == "loadingpic") { + items[i].remove(); + } + } + provisionStatBar.hide(); +} + +/** + * Set hash entry to 0 and check if all are 0. If so call + * removeProvisionLoadingGif + * + * @param division holding the gif and message, and hash, and + * key + */ +function checkProvisionCallsDone(provisionStatBar, table, finishedKey) { + + table[finishedKey] = 0; + + for (var key in table) { + if (table[key] == 1) { + return; // More to do + } + } + + removeProvisionLoadingGif(provisionStatBar); +} + +/** + * Load zVMs into column (service page) + * + * @param col Table column where OS images will be placed + */ +function loadzVMs(col) { + // Get group names and description and append to group column + if (!$.cookie('xcat_zvms')) { + var infoBar = createInfoBar('No selectable z/VM available'); + col.append(infoBar); + return; + } + + var zNames = $.cookie('xcat_zvms').split(','); + + var radio, zBlock, args, zvm, hcp; + for (var i in zNames) { + if( !zNames[i] || 0 === zNames[i].length) continue; + args = zNames[i].split(':'); + zvm = args[0]; + hcp = args[1]; + + // Create block for each group + zBlock = $('
                          ').css({ + 'border': '1px solid', + 'max-width': '200px', + 'margin': '5px auto', + 'padding': '5px', + 'display': 'block', + 'vertical-align': 'middle', + 'cursor': 'pointer', + 'white-space': 'normal' + }).click(function(){ + $(this).children('input:radio').attr('checked', 'checked'); + $(this).parents('td').find('div').attr('class', 'ui-state-default'); + $(this).attr('class', 'ui-state-active'); + }); + radio = $('').css('display', 'none'); + zBlock.append(radio, $('' + zvm + ' managed by ' + hcp + '')); + zBlock.children('span').css({ + 'display': 'block', + 'margin': '5px', + 'text-align': 'left' + }); + col.append(zBlock); + } +} + +/** + * Load groups into column + * + * @param col Table column where OS images will be placed + */ +function loadSrvGroups(col) { + // Get group names and description and append to group column + if (!$.cookie('xcat_srv_groups')) { + var infoBar = createInfoBar('No selectable group available'); + col.append(infoBar); + return; + } + + var groupNames = $.cookie('xcat_srv_groups').split(','); + + var groupBlock, radio, args, name, ip, hostname, desc; + for (var i in groupNames) { + if( !groupNames[i] || 0 === groupNames[i].length) continue; + args = groupNames[i].split(':'); + name = args[0]; + ip = args[1]; + hostname = args[2]; + desc = args[3]; + + // Create block for each group + groupBlock = $('
                          ').css({ + 'border': '1px solid', + 'max-width': '200px', + 'margin': '5px auto', + 'padding': '5px', + 'display': 'block', + 'vertical-align': 'middle', + 'cursor': 'pointer', + 'white-space': 'normal' + }).click(function(){ + $(this).children('input:radio').attr('checked', 'checked'); + $(this).parents('td').find('div').attr('class', 'ui-state-default'); + $(this).attr('class', 'ui-state-active'); + }); + radio = $('').css('display', 'none'); + groupBlock.append(radio, $('' + name + ': ' + desc + '')); + groupBlock.children('span').css({ + 'display': 'block', + 'margin': '5px', + 'text-align': 'left' + }); + col.append(groupBlock); + } +} + +/** + * Load OS images into column + * + * @param col Table column where OS images will be placed + */ +function loadOSImages(col) { + // Get group names and description and append to group column + if (!$.cookie('xcat_srv_imagenames')) { + var infoBar = createInfoBar('No selectable image available'); + col.append(infoBar); + return; + } + + var imgNames = $.cookie('xcat_srv_imagenames').split(','); + + var imgBlock, radio, args, name, desc; + for (var i in imgNames) { + if( !imgNames[i] || 0 === imgNames[i].length) continue; + args = imgNames[i].split(':'); + name = args[0]; + desc = args[1]; + + // Create block for each image + imgBlock = $('
                          ').css({ + 'border': '1px solid', + 'max-width': '200px', + 'margin': '5px auto', + 'padding': '5px', + 'display': 'block', + 'vertical-align': 'middle', + 'cursor': 'pointer', + 'white-space': 'normal' + }).click(function(){ + $(this).children('input:radio').attr('checked', 'checked'); + $(this).parents('td').find('div').attr('class', 'ui-state-default'); + $(this).attr('class', 'ui-state-active'); + + $('#select-table tbody tr:eq(0) td:eq(3) input[name="master"]').attr('checked', ''); + $('#select-table tbody tr:eq(0) td:eq(3) input[name="master"]').parents('td').find('div').attr('class', 'ui-state-default'); + }); + radio = $('').css('display', 'none'); + imgBlock.append(radio, $('' + name + ': ' + desc + '')); + imgBlock.children('span').css({ + 'display': 'block', + 'margin': '5px', + 'text-align': 'left' + }); + col.append(imgBlock); + } +} + +/** + * Load golden images into column + * + * @param col Table column where master copies will be placed + */ +function loadGoldenImages(col) { + // Get group names and description and append to group column + if (!$.cookie('xcat_srv_goldenimages')) { + var infoBar = createInfoBar('No selectable master copies available'); + col.append(infoBar); + return; + } + + var imgNames = $.cookie('xcat_srv_goldenimages').split(','); + + var imgBlock, radio, args, name, desc; + for (var i in imgNames) { + if( !imgNames[i] || 0 === imgNames[i].length) continue; + args = imgNames[i].split(':'); + name = args[0]; + desc = args[1]; + + // Create block for each image + imgBlock = $('
                          ').css({ + 'border': '1px solid', + 'max-width': '200px', + 'margin': '5px auto', + 'padding': '5px', + 'display': 'block', + 'vertical-align': 'middle', + 'cursor': 'pointer', + 'white-space': 'normal' + }).click(function(){ + $(this).children('input:radio').attr('checked', 'checked'); + $(this).parents('td').find('div').attr('class', 'ui-state-default'); + $(this).attr('class', 'ui-state-active'); + + // Un-select zVM and image + $('#select-table tbody tr:eq(0) td:eq(2) input[name="image"]').attr('checked', ''); + $('#select-table tbody tr:eq(0) td:eq(2) input[name="image"]').parents('td').find('div').attr('class', 'ui-state-default'); + + $('#select-table tbody tr:eq(0) td:eq(0) input[name="hcp"]').attr('checked', ''); + $('#select-table tbody tr:eq(0) td:eq(0) input[name="hcp"]').parents('td').find('div').attr('class', 'ui-state-default'); + }); + radio = $('').css('display', 'none'); + imgBlock.append(radio, $('' + name + ': ' + desc + '')); + imgBlock.children('span').css({ + 'display': 'block', + 'margin': '5px', + 'text-align': 'left' + }); + col.append(imgBlock); + } +} + +/** + * Set a cookie for zVM host names (service page) + * + * @param data Data from HTTP request + */ +function setzVMCookies(data) { + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1 ) { + var zvms = new Array(); + var hosts = data.rsp[0].split("\n"); + for ( var i = 0; i < hosts.length; i++) { + if (hosts[i] != null && hosts[i] != "") { + zvms.push(hosts[i]); + if (typeof console == "object"){ + console.log("Setting a zVM cookie:<"+hosts[i]+">"); + } + } + } + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); + $.cookie('xcat_zvms', zvms, { expires: exDate, path: '/xcat', secure:true }); + } +} + +/** + * Set a cookie for master copies (service page) + * + * @param data Data from HTTP request + */ +function setGoldenImagesCookies(data) { + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1) { + var copies = new Array(); + var tmp = data.rsp[0].split(","); + for ( var i = 0; i < tmp.length; i++) { + if (tmp[i] != null && tmp[i] != "") { + copies.push(tmp[i]); + } + } + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); + $.cookie('xcat_srv_goldenimages', copies, { expires: exDate, path: '/xcat', secure:true }); + } +} + +/** + * Set a cookie for disk pool names of a given node + * + * @param data Data from HTTP request + */ +function setDiskPoolCookies(data) { + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1 ) { + var node = data.msg; + var pools = data.rsp[0].split(node + ": "); + var pools2 = []; + for (var j in pools) { + if (pools[j] != "") { + pools2.push(jQuery.trim(pools[j])); + } + } + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); + $.cookie('xcat_' + node + 'diskpools', pools2, { expires: exDate, path: '/xcat', secure:true }); + } +} + +/** + * Set a cookie for zFCP pool names of a given node + * + * @param data Data from HTTP request + */ +function setZfcpPoolCookies(data) { + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1 ) { + var node = data.msg; + var pools = data.rsp[0].split(node + ': '); + var pools2 = []; + for (var j in pools) { + if (pools[j] != "") { + pools2.push(jQuery.trim(pools[j])); + } + } + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); + $.cookie('xcat_' + node + 'zfcppools', pools2, { expires: exDate, path: '/xcat', secure:true }); + } +} + +/** + * Set a cookie for zHCP host names + * + * @param zhcps List of zHCPs known + */ +function setzHcpCookies(zhcps) { + if (zhcps.length) { + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); + $.cookie('xcat_zhcps', zhcps, { expires: exDate, path: '/xcat', secure:true }); + } +} + +/** + * Set a cookie for z/VM user profile names of a given node + * + * @param data Data from HTTP request + */ +function setUserProfilesCookies(data) { + if (data.rsp.length && data.rsp[0].indexOf("Failed") == -1 && data.rsp[0].indexOf("Error") == -1 ) { + var node = data.msg; + var profiles = data.rsp[0].split(node + ': '); + var profiles2 = []; + for (var j in profiles) { + if (profiles[j] != "") { + profiles2.push(jQuery.trim(profiles[j])); + } + } + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (60 * 60 * 1000)); + $.cookie('xcat_' + node + 'userprofiles', profiles2, { expires: exDate, path: '/xcat', secure:true }); + } +} + +/** + * Create virtual machine (service page) + * + * @param tabId Tab ID + * @param group Group + * @param hcp Hardware control point + * @param img OS image + */ +function createzVM(tabId, group, hcp, img, owner) { + // Submit request to create VM + // webportal provzlinux [group] [hcp] [image] [owner] + var iframe = createIFrame('lib/srv_cmd.php?cmd=webportal&tgt=&args=provzlinux;' + group + ';' + hcp + ';' + img + ';' + owner + '&msg=&opts=flush'); + iframe.prependTo($('#' + tabId)); +} + +/** + * Query the profiles that exists + * + * @param panelId Panel ID + */ +function queryProfiles(panelId) { + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'osimage', + msg : panelId + }, + + success : function(data) { + data = decodeRsp(data); + var panelId = data.msg; + setOSImageCookies(data); + configProfilePanel(panelId); + } + }); +} + +/** + * Panel to configure directory entries and disks for a profile + * + * @param panelId Panel ID + */ +function configProfilePanel(panelId) { + // Wipe panel clean + $('#' + panelId).empty(); + + // Add info bar + $('#' + panelId).append(createInfoBar('Create, edit, and delete profiles for the self-service portal. It is important to note the default z/VM user ID for any profile should be LXUSR.')); + + // Create table + var tableId = 'zvmProfileTable'; + var table = new DataTable(tableId); + table.init(['', 'Profile', 'Disk pool', 'Disk size', 'Directory entry']); + + // Insert profiles into table + var profiles = $.cookie('xcat_profiles').split(','); + profiles.push('default'); // Add default profile + for (var i in profiles) { + if (profiles[i]) { + // Columns are: profile, selectable, description, disk pool, disk size, and directory entry + var cols = new Array(profiles[i], '', '', ''); + + // 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", "450px"); + + // Create a profile + var createLnk = $('Create'); + createLnk.click(function() { + profileDialog(); + }); + + // Edit a profile + var editLnk = $('Edit'); + editLnk.click(function() { + var profiles = $('#' + tableId + ' input[type=checkbox]:checked'); + for (var i in profiles) { + var profile = profiles.eq(i).attr('name'); + if (profile) { + // Column order is: profile, selectable, disk pool, disk size, and directory entry + var cols = profiles.eq(i).parents('tr').find('td'); + var pool = cols.eq(2).text(); + var size = cols.eq(3).text(); + var entry = cols.eq(4).html().replace(new RegExp('
                          ', 'g'), '\n'); + + editProfileDialog(profile, pool, size, entry); + } + } + }); + + // Delete a profile + var deleteLnk = $('Delete'); + deleteLnk.click(function() { + var profiles = getNodesChecked(tableId); + if (profiles) { + deleteProfileDialog(profiles); + } + }); + + // Refresh profiles table + var refreshLnk = $('Refresh'); + refreshLnk.click(function() { + queryProfiles(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'); + + // Query directory entries and disk pool/size for each profile + for (var i in profiles) { + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'getdefaultuserentry;' + profiles[i], + msg : 'out=' + panelId + ';profile=' + profiles[i] + }, + + success : function(data) { + data = decodeRsp(data); + insertDirectoryEntry(data); + } + }); + + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'getzdiskinfo;' + profiles[i], + msg : 'out=' + panelId + ';profile=' + profiles[i] + }, + + success : function(data) { + data = decodeRsp(data); + insertDiskInfo(data); + } + }); + } +} + +/** + * Insert the directory entry into the profile table + * + * @param data Data from HTTP request + */ +function insertDirectoryEntry(data) { + var tableId = 'zvmProfileTable'; + var args = data.msg.split(';'); + + var profile = args[1].replace('profile=', ''); + + // Do not continue if there is nothing + if (!data.rsp.length) + return; + + var entry = data.rsp[0].replace(new RegExp('\n', 'g'), '
                          '); + + // Get the row containing the profile + var rowPos = findRow(profile, '#' + tableId, 1); + if (rowPos < 0) + return; + + // Update the directory entry column + var dTable = $('#' + tableId).dataTable(); + dTable.fnUpdate(entry, rowPos, 4, false); + + // Adjust table styling + $('#' + tableId + ' td:nth-child(5)').css({ + 'text-align': 'left' + }); + adjustColumnSize(tableId); +} + +/** + * Insert the disk info into the profile table + * + * @param data Data from HTTP request + */ +function insertDiskInfo(data) { + var tableId = 'zvmProfileTable'; + var args = data.msg.split(';'); + + var profile = args[1].replace('profile=', ''); + + // Do not continue if there is nothing + if (!data.rsp.length) + return; + + // Get the row containing the profile + var rowPos = findRow(profile, '#' + tableId, 1); + if (rowPos < 0) + return; + + // Update the disk info columns + var dTable = $('#' + tableId).dataTable(); + + var tmp = ""; + var pool = ""; + var eckdSize = 0; + var info = data.rsp[0].split('\n'); + for (var i in info) { + if (info[i].indexOf('diskpool') > -1) { + tmp = info[i].split('='); + pool = jQuery.trim(tmp[1]); + + dTable.fnUpdate(pool, rowPos, 2, false); + } if (info[i].indexOf('eckd_size') > -1) { + tmp = info[i].split('='); + eckdSize = jQuery.trim(tmp[1]); + + dTable.fnUpdate(eckdSize, rowPos, 3, false); + } + } + + // Adjust table styling + adjustColumnSize(tableId); +} + +/** + * Open profile dialog + */ +function profileDialog() { + // Create form to add profile + var dialogId = 'zvmCreateProfile'; + var profileForm = $('
                          '); + + // Create info bar + var info = createInfoBar('Configure the default settings for a profile'); + profileForm.append(info); + + // Insert profiles into select + var profileSelect = $(''); + var profiles = $.cookie('xcat_profiles').split(','); + profiles.push('default'); // Add default profile + for (var i in profiles) { + if (profiles[i]) { + profileSelect.append($('')); + } + } + + profileForm.append($('
                          ').append(profileSelect)); + profileForm.append('
                          '); + profileForm.append('
                          '); + profileForm.append('
                          ').css({ - 'font-size': '10px', - 'height': '50px', - 'width': '200px', - 'background-color': '#000', - 'color': '#fff', - 'border': '0px', - 'display': 'block' - }); - - // Create links to save and cancel changes - var lnkStyle = { - 'color': '#58ACFA', - 'font-size': '10px', - 'display': 'inline-block', - 'padding': '5px', - 'float': 'right' - }; - - var saveLnk = $('Save').css(lnkStyle).hide(); - var cancelLnk = $('Cancel').css(lnkStyle).hide(); - var infoSpan = $('Click to edit').css(lnkStyle); - - // Save changes onclick - saveLnk.bind('click', function(){ - // Get node and comment - var node = $(this).parent().parent().find('img').attr('id').replace('Tip', ''); - var comments = $(this).parent().find('textarea').val(); - - // Save comment - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chdef', - tgt : '', - args : '-t;node;-o;' + node + ';usercomment=' + comments, - msg : 'out=nodesTab;tgt=' + node - }, - - success: showChdefOutput - }); - - // Hide cancel and save links - $(this).hide(); - cancelLnk.hide(); - }); - - // Cancel changes onclick - cancelLnk.bind('click', function(){ - // Get original comment and put it back - var orignComments = $(this).parent().find('textarea').text(); - $(this).parent().find('textarea').val(orignComments); - - // Hide cancel and save links - $(this).hide(); - saveLnk.hide(); - infoSpan.show(); - }); - - // Show save link when comment is edited - txtArea.bind('click', function(){ - saveLnk.show(); - cancelLnk.show(); - infoSpan.hide(); - }); - - toolTip.append(txtArea); - toolTip.append(cancelLnk); - toolTip.append(saveLnk); - toolTip.append(infoSpan); - - return toolTip; -} - -/** - * Create a tool tip for node status - * - * @return Tool tip - */ -function createStatusToolTip() { - // Create tooltip container - var toolTip = $('
                          ').css({ - 'width': '150px', - 'font-weight': 'normal' - }); - - // Create info text - var info = $('

                          ').css({ - 'white-space': 'normal' - }); - info.append('Click here to refresh the node status. To configure the xCAT monitor, '); - - // Create link to turn on xCAT monitoring - var monitorLnk = $('click here').css({ - 'color': '#58ACFA', - 'font-size': '10px' - }); - - // Open dialog to configure xCAT monitor - monitorLnk.bind('click', function(){ - // Check if xCAT monitor is enabled - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'monls', - tgt : '', - args : 'xcatmon', - msg : '' - }, - - success : openConfXcatMon - }); - }); - - info.append(monitorLnk); - toolTip.append(info); - - return toolTip; -} - -/** - * Create a tool tip for power status - * - * @return Tool tip - */ -function createPowerToolTip() { - // Create tooltip container - var toolTip = $('
                          Click here to refresh the power status
                          ').css({ - 'width': '150px', - 'white-space': 'normal', - 'font-weight': 'normal' - }); - return toolTip; -} - -/** - * Create a tool tip for monitoring status - * - * @return Tool tip - */ -function createMonitorToolTip() { - // Create tooltip container - var toolTip = $('
                          Click here to refresh the monitoring status
                          ').css({ - 'width': '150px', - 'white-space': 'normal', - 'font-weight': 'normal' - }); - return toolTip; -} - -/** - * Open dialog to configure xCAT monitor - * - * @param data Data returned from HTTP request - */ -function openConfXcatMon(data) { - // Create info bar - var info = createInfoBar('Configure the xCAT monitor. Select to enable or disable the monitor below.'); - var dialog = $('
                          '); - dialog.append(info); - - // Create status area - var statusArea = $('
                          ').css('padding-top', '10px'); - var label = $(''); - statusArea.append(label); - - // Get xCAT monitor status - var status = data.rsp[0]; - var buttons; - // If xCAT monitor is disabled - if (status.indexOf('not-monitored') > -1) { - status = $('Disabled').css('padding', '0px 5px'); - statusArea.append(status); - - // Create enable and cancel buttons - buttons = { - "Enable": function(){ - // Enable xCAT monitor - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'monstart', - tgt : '', - args : 'xcatmon', - msg : '' - }, - - success : function(data){ - openDialog('info', data.rsp[0]); - } - }); - $(this).dialog("close"); - }, - "Cancel": function(){ - $(this).dialog("close"); - } - }; - } else { - status = $('Enabled').css('padding', '0px 5px'); - statusArea.append(status); - - // Create disable and cancel buttons - buttons = { - "Disable": function(){ - // Disable xCAT monitor - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'monstop', - tgt : '', - args : 'xcatmon', - msg : '' - }, - - success : function(data){ - openDialog('info', data.rsp[0]); - } - }); - $(this).dialog("close"); - }, - "Cancel": function(){ - $(this).dialog("close"); - } - }; - } - - dialog.append(statusArea); - - // Open dialog - dialog.dialog({ - modal: true, - width: 500, - buttons: buttons - }); -} - -/** - * Show chdef output - * - * @param data Data returned from HTTP request - */ -function showChdefOutput(data) { - // Get output - var out = data.rsp; - var args = data.msg.split(';'); - var tabID = args[0].replace('out=', ''); - var tgt = args[1].replace('tgt=', ''); - - // Find info bar on nodes tab, if any - var info = $('#' + tabID).find('.ui-state-highlight'); - if (!info.length) { - // Create info bar if one does not exist - info = createInfoBar(''); - $('#' + tabID).append(info); - } - - // Go through output and append to paragraph - var prg = $('

                          '); - for (var i in out) { - prg.append(tgt + ': ' + out[i] + '
                          '); - } - - info.append(prg); -} - -/** - * Set node attributes - * - * @param data Data returned from HTTP request - */ -function setNodeAttrs(data) { - // Clear hash table containing definable node attributes - nodeAttrs = new Array(); - - // Get definable attributes - var attrs = data.rsp[2].split(/\n/); - - // Go through each line - var attr, key, descr; - for (var i in attrs) { - attr = attrs[i]; - - // If the line is not empty - if (attr) { - // If the line has the attribute name - if (attr.indexOf(':') && attr.indexOf(' ')) { - // Get attribute name and description - key = jQuery.trim(attr.substring(0, attr.indexOf(':'))); - descr = jQuery.trim(attr.substring(attr.indexOf(':') + 1)); - - // Remove arrow brackets - descr = descr.replace(new RegExp('<|>', 'g'), ''); - - // Set hash table where key = attribute name and value = description - nodeAttrs[key] = descr; - } else { - // Remove arrow brackets - attr = attr.replace(new RegExp('<|>', 'g'), ''); - - // Append description to hash table - nodeAttrs[key] = nodeAttrs[key] + '\n' + attr; - } - } // End of if - } // End of for -} - - -/** - * Load the discover z/VM virtual systems page - * - * @param tgtNode Target node to set properties - */ -function discoverVMNodes(tgtNodes) { - var fs, legend, htmlLine; - - // Get nodes tab - var tab = getNodesTab(); - - // Generate new tab ID - var inst = 0; - var newTabId = 'discoverVMNodesTab' + inst; - while ($('#' + newTabId).length) { - // If one already exists, generate another one - inst = inst + 1; - newTabId = 'discoverVMNodesTab' + inst; - } - - // Open new tab - // Create set properties form - var discoverVMNodesForm = $('
                          '); - - // Create info bar - var infoBar = createInfoBar( 'Initiate, stop or query the status of z/VM node discovery. ' + - 'To initiate discovery, specify discovery parameters and click on the Discover button. ' + - 'To stop an on-going discovery related to a z/VM host, specify the host node name and '+ - 'click on the Stop button. ' + - 'To obtain the status of discovery for a particular host, specify the host node name and '+ - 'click on the Stop button.' - ); - discoverVMNodesForm.append(infoBar); - - // Create the status bar and hide it. - var statBarId = 'statusBar_' + newTabId; - //var statBar = $( '
                          ' ); - //discoverVMNodesForm.append( statBar ); - statBar = createStatusBar( statBarId ); - statBar.hide(); - discoverVMNodesForm.append( statBar ); - - // Create Host fieldset - fs = $('
                          '); - legend = $('z/VM Host'); - fs.append(legend); - discoverVMNodesForm.append(fs); - - // Target node or group - htmlLine = $('
                          '); - discoverVMNodesForm.append( htmlLine ); - - // Create Discovery Parameters fieldset - fs = $('
                          '); - legend = $('Discovery Parameters'); - fs.append( legend ); - discoverVMNodesForm.append( fs ); - - // Create an input for each definable attribute - var div, label, input, descr, value; - - // Define DefineTo radio buttons - div = $('
                          ').css( 'display', 'inline-block' ).css( 'vertical-align', 'top' ); - div.append( '' ); - div.append( '
                        • xCAT and OpenStack
                        • ' ); - div.append( '
                        • xCAT only
                        • ' ); - div.append( '
                        • OpenStack only (only already discovered xCAT nodes)
                        • ' ); - discoverVMNodesForm.append( div ); - discoverVMNodesForm.append( '
                          ' ); - - // Userid filter - divUserid = newTabId + "_divUserid"; - div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ); - div.append( '' ); - div.append( '' ).css( 'margin-top', '5px' ); - discoverVMNodesForm.append( div ); - discoverVMNodesForm.append( '
                          ' ); - - // IP address filter - divIP = newTabId + "_divIP"; - div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ); - div.append( '' ); - div.append( '' ).css( 'margin-top', '5px' ); - discoverVMNodesForm.append( div ); - discoverVMNodesForm.append( '
                          ' ); - - // Group name input - divGroup = newTabId + '_divGroup'; - div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ); - div.append( '' ); - div.append( '' ).css( 'margin-top', '5px' ); - discoverVMNodesForm.append( div ); - discoverVMNodesForm.append( '
                          ' ); - - // Node Name Format input - divNodename = newTabId + '_divNodename'; - div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ); - div.append( '' ); - div.append( '' ).css( 'margin-top', '5px' ); - discoverVMNodesForm.append( div ); - discoverVMNodesForm.append( '
                          ' ); - discoverVMNodesForm.find('#' + divNodename).hide(); - - // OpenStack operand input - divOpenStackOps = newTabId + '_divOpenStackOps'; - div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ); - div.append( '' ); - div.append( '' ).css( 'margin-top', '5px' ); - div.append( '
                          ' ); - div.append( '' ); - div.append( '' ).css( 'margin-top', '5px' ); - discoverVMNodesForm.append( div ); - discoverVMNodesForm.append( '
                          ' ); - - // Define Verbose radio buttons - div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ).css( 'text-align', 'top' ); - div.append( '' ); - div.append( '
                        • Normal response, showing only important information
                        • ' ); - div.append( '
                        • Verbose response, normal response plus additional information (e.g. reason a system is ignored)
                        • ' ); - discoverVMNodesForm.append( div ); - discoverVMNodesForm.append( '
                          ' ); - - // Generate tooltips - discoverVMNodesForm.find('div input[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" - } - }); - - // Show appropriate input fields for defineto choices. - discoverVMNodesForm.change(function(){ - var defineTo = $(this).parent().find('input[name="defineTo"]:checked').val(); - if ( defineTo == 'both' ) { - discoverVMNodesForm.find('#' + divUserid).show(); - discoverVMNodesForm.find('#' + divIP).show(); - discoverVMNodesForm.find('#' + divGroup).show(); - discoverVMNodesForm.find('#' + divOpenStackOps).show(); - discoverVMNodesForm.find('#' + divNodename).hide(); - } else if ( defineTo == 'xcatonly' ) { - discoverVMNodesForm.find('#' + divUserid).show(); - discoverVMNodesForm.find('#' + divIP).show(); - discoverVMNodesForm.find('#' + divGroup).show(); - discoverVMNodesForm.find('#' + divOpenStackOps).hide(); - discoverVMNodesForm.find('#' + divNodename).show(); - } else if ( defineTo == 'openstackonly' ) { - discoverVMNodesForm.find('#' + divUserid).hide(); - discoverVMNodesForm.find('#' + divIP).hide(); - discoverVMNodesForm.find('#' + divGroup).hide(); - discoverVMNodesForm.find('#' + divOpenStackOps).show(); - discoverVMNodesForm.find('#' + divNodename).hide(); - } - }); - - - // Discover nodes button action - var discoverBtn = createButton('Discover'); - discoverBtn.click(function() { - var argList = ''; - var filter = ''; - - var hosts = $(this).parent().find('input[name=hosts]').val(); - if ( hosts != '' ) { - argList = 'zvmhost=' + hosts; - } - - var defineTo = $(this).parent().find('input[name="defineTo"]:checked').val(); - argList = argList + '||defineto=' + defineTo; - - var verbose = $(this).parent().find('input[name="verbose"]:checked').val(); - if ( verbose == 'yes' ) { - argList = argList + '||--verbose'; - } - - var useridFilter = $(this).parent().find('input[name=useridFilter]').val(); - if (( defineTo == 'both' || defineTo == 'xcatonly' ) && ( useridFilter != '' )) { - argList = argList + '||useridfilter=' + useridFilter; - } - - var ipFilter = $(this).parent().find('input[name=ipFilter]').val(); - if (( defineTo == 'both' || defineTo == 'xcatonly' ) && ( ipFilter != '' )) { - argList = argList + '||ipfilter=' + ipFilter; - } - - var group = $(this).parent().find('input[name=group]').val(); - if (( defineTo == 'both' || defineTo == 'xcatonly' ) && ( group != '' )) { - argList = argList + '||groups=' + group; - } - - var nodeNameFmt = $(this).parent().find('input[name=nodeNameFmt]').val(); - if ( defineTo == 'xcatonly' && nodeNameFmt != '' ) { - argList = argList + '||nodenameformat=' + nodeNameFmt; - } - - var openStackProj = $(this).parent().find('input[name=openStackProj]').val(); - var openStackUser = $(this).parent().find('input[name=openStackUser]').val(); - if ((( defineTo == 'both' ) || ( defineTo == 'openstackonly' )) && - (( openStackProj != '' ) || ( openStackUser != '' ))) { - if ( openStackProj != '' ) { - osArgs = '--project ' + openStackProj; - } else { - osArgs = ''; - } - if ( openStackUser != '' ) { - if ( osArgs != '' ) { - osArgs = osArgs + ' --user ' + openStackUser; - } else { - osArgs = '--user ' + openStackUser; - } - } - argList = argList + "||openstackoperands='" + osArgs + "'"; - } - - var out = $('

                          '); - out.append( 'Starting node discovery...' ); - out.append( '
                          ' ); - out.append( 'If node discovery is a short running task then its response will follow. If, however, the time it takes to complete discovery exceeds the http request timeout of a few minutes then the discovery response will not be returned to the browser. The status and list buttons can be used to obtained status on the discovery and see what systems have been discovered.' ); - $( '#' + statBarId ).find( 'div' ).append( out ); - statBar.show(); - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodediscoverstart', - tgt : '', - args : argList, - att : '', - msg : statBarId - }, - success: function(data) { - updateDiscoverStatusBar( data, 1 ); - } - }); - - }); - discoverVMNodesForm.append(discoverBtn); - - // Status button - var statusBtn = createButton('Status'); - statusBtn.click( function() { - var hosts = $(this).parent().find('input[name=hosts]').val(); - var out = $('

                          '); - out.append( 'Querying status for discovery on ' + hosts + '...' ); - out.append( '
                          ' ); - $( '#' + statBarId ).find( 'div' ).append( out ); - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodediscoverstatus', - tgt : '', - args : '--zvmhost||' + hosts, - att : '', - msg : statBarId - }, - success: function(data) { - updateDiscoverStatusBar( data, 1 ); - } - }); - - }); - discoverVMNodesForm.append( statusBtn ); - - // List button - var listBtn = createButton('List'); - listBtn.click( function() { - var hosts = $(this).parent().find('input[name=hosts]').val(); - var out = $('

                          '); - out.append( 'Listing systems discovered by the latest discovery on ' + hosts + '...' ); - out.append( '
                          ' ); - $( '#' + statBarId ).find( 'div' ).append( out ); - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodediscoverls', - tgt : '', - args : '-t||zvm||--zvmhost||' + hosts, - att : '', - msg : statBarId - }, - success: function(data) { - updateDiscoverStatusBar( data, 1 ); - } - }); - }); - discoverVMNodesForm.append( listBtn ); - - // Stop button - var stopBtn = createButton('Stop'); - stopBtn.click(function() { - var hosts = $(this).parent().find('input[name=hosts]').val(); - var out = $('

                          '); - out.append( 'Stopping discovery on ' + hosts + '...' ); - out.append( '
                          ' ); - $( '#' + statBarId ).find( 'div' ).append( out ); - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodediscoverstop', - tgt : '', - args : '--zvmhost||' + hosts, - att : '', - msg : statBarId - }, - success: function(data) { - updateDiscoverStatusBar( data, 1 ); - } - }); - }); - discoverVMNodesForm.append( stopBtn ); - - // Append to discover tab - tab.add(newTabId, 'Discover', discoverVMNodesForm, true); - - // Select new tab - tab.select(newTabId); -} - - -/** - * Update discovery status bar - * - * @param data Data returned from HTTP request - */ -function updateDiscoverStatusBar( data, preformatted ) { - var statBarId = data.msg; - var rsp = data.rsp; - var statBar = $( '#' + statBarId ); - - // Go through response to make it readable in the status bar. - var out = $('

                          '); - for ( var i in rsp ) { - if ( preformatted == 1 ) { - out.append( '
                          ' + rsp[i] + '
                          ' ); - } else { - out.append( rsp[i] + '
                          ' ); - } - } - - // Write response to status bar and show the bar. - $( '#' + statBarId ).find( 'div' ).append( out ); - statBar.show(); -} - -/** - * Load set node properties page - * - * @param tgtNode Target node to set properties - */ -function editNodeProps(tgtNode) { - // Get nodes tab - var tab = getNodesTab(); - - // Generate new tab ID - var inst = 0; - var newTabId = 'editPropsTab' + inst; - while ($('#' + newTabId).length) { - // If one already exists, generate another one - inst = inst + 1; - newTabId = 'editPropsTab' + inst; - } - - // Open new tab - // Create set properties form - var editPropsForm = $('
                          '); - - // Create info bar - var infoBar = createInfoBar('Choose the properties you wish to change on the node. When you are finished, click Save.'); - editPropsForm.append(infoBar); - - // Create an input for each definable attribute - var div, label, input, descr, value; - // Set node attribute - origAttrs[tgtNode]['node'] = tgtNode; - for (var key in nodeAttrs) { - // If an attribute value exists - if (origAttrs[tgtNode][key]) { - // Set the value - value = origAttrs[tgtNode][key]; - } else { - value = ''; - } - - // Create label and input for attribute - div = $('
                          ').css('display', 'inline-table'); - label = $('').css('vertical-align', 'middle'); - input = $('').css('margin-top', '5px'); - - // Change border to blue onchange - input.bind('change', function(event) { - $(this).css('border-color', 'blue'); - }); - - div.append(label); - div.append(input); - editPropsForm.append(div); - } - - // Change style for last division - div.css({ - 'display': 'block', - 'margin': '0px 0px 10px 0px' - }); - - // Generate tooltips - editPropsForm.find('div input[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" - } - }); - - // Save changes - var saveBtn = createButton('Save'); - saveBtn.click(function() { - // Get all inputs - var inputs = $('#' + newTabId + ' input'); - - // Go through each input - var args = ''; - var attrName, attrVal; - inputs.each(function(){ - // If the border color is blue - if ($(this).css('border-left-color') == 'rgb(0, 0, 255)') { - // Change border color back to normal - $(this).css('border-color', ''); - - // Get attribute name and value - attrName = $(this).parent().find('label').text().replace(':', ''); - attrVal = $(this).val(); - - // Build argument string - if (args) { - // Handle subsequent arguments - args += ';' + attrName + '=' + attrVal; - } else { - // Handle the 1st argument - args += attrName + '=' + attrVal; - } - } - }); - - // Send command to change node attributes - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chdef', - tgt : '', - args : '-t;node;-o;' + tgtNode + ';' + args, - msg : 'out=' + newTabId + ';tgt=' + tgtNode - }, - - success: showChdefOutput - }); - }); - editPropsForm.append(saveBtn); - - // Cancel changes - var cancelBtn = createButton('Cancel'); - cancelBtn.click(function() { - // Close the tab - tab.remove($(this).parent().parent().attr('id')); - }); - editPropsForm.append(cancelBtn); - - // Append to discover tab - tab.add(newTabId, 'Edit', editPropsForm, true); - - // Select new tab - tab.select(newTabId); -} - -/** - * Open set node attributes dialog - */ -function openSetAttrsDialog() { - // Open new tab - // Create set properties form - var setPropsForm = $('
                          '); - - // Create info bar - var infoBar = createInfoBar('Choose the properties you wish to change on the node. When you are finished, click Save.'); - setPropsForm.append(infoBar); - - // Create an input for each definable attribute - var div, label, input, descr, value; - for (var key in nodeAttrs) { - value = ''; - - // Create label and input for attribute - div = $('
                          ').css('display', 'inline'); - label = $('').css('vertical-align', 'middle'); - input = $('').css('margin-top', '5px'); - - // Change border to blue onchange - input.bind('change', function(event) { - $(this).css('border-color', 'blue'); - }); - - div.append(label); - div.append(input); - setPropsForm.append(div); - } - - // Change style for last division - div.css({ - 'display': 'block', - 'margin': '0px 0px 10px 0px' - }); - - // Generate tooltips - setPropsForm.find('div input[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()); - } - }); - - // Enable vertical scroll - setPropsForm.css('overflow', 'auto'); - - // Open form as a dialog - setPropsForm.dialog({ - title: 'Set attributes', - modal: true, - close: function(){ - $(this).remove(); - }, - height: 400, - width: 800, - buttons: { - "Save": function() { - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - // Get all inputs - var inputs = $(this).find('input'); - - // Go through each input - var args = ''; - var tgtNode, attrName, attrVal; - inputs.each(function(){ - // If the border color is blue - if ($(this).css('border-left-color') == 'rgb(0, 0, 255)') { - // Change border color back to normal - $(this).css('border-color', ''); - - // Get attribute name and value - attrName = $(this).parent().find('label').text().replace(':', ''); - attrVal = $(this).val(); - - // Get node name - if (attrName == 'node') { - tgtNode = attrVal; - } else { - // Build argument string - if (args) { - // Handle subsequent arguments - args += ';' + attrName + '=' + attrVal; - } else { - // Handle the 1st argument - args += attrName + '=' + attrVal; - } - } - } - }); - - // Send command to change node attributes - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chdef', - tgt : '', - args : '-t;node;-o;' + tgtNode + ';' + args, - msg : 'node=' + tgtNode - }, - - /** - * Show results - * - * @param data - * Data returned from HTTP request - * @return Nothing - */ - success: function(data) { - // Get output - var out = data.rsp; - var node = data.msg.replace('node=', ''); - - // Go through output and append to paragraph - var msg = ''; - for (var i in out) { - if (!msg) { - msg = node + ': ' + out[i]; - } else { - msg += '
                          ' + node + ': ' + out[i]; - } - } - - openDialog('info', msg); - } - }); - - // Close dialog - $(this).dialog( "close" ); - }, - "Cancel": function(){ - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Turn on monitoring for a given node - * - * @param node Node to monitor on or off - * @param monitor Monitor state, on or off - */ -function monitorNode(node, monitor) { - // Show ganglia loader - var gangliaCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); - gangliaCol.find('img').show(); - - if (monitor == 'on') { - // Append loader to warning bar - var warningBar = $('#nodesTab').find('.ui-state-error p'); - if (warningBar.length) { - warningBar.append(createLoader('')); - } - - if (node) { - // Check if ganglia RPMs are installed - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'gangliacheck;' + node, - msg : node // Node range will be passed along in data.msg - }, - - /** - * Start ganglia on a given node range - * - * @param data Data returned from HTTP request - */ - success : function(data) { - // Get response - var out = data.rsp[0].split(/\n/); - - // Go through each line - var warn = false; - var warningMsg = ''; - for (var i in out) { - // If an RPM is not installed - if (out[i].indexOf('not installed') > -1) { - warn = true; - - if (warningMsg) { - warningMsg += '
                          ' + out[i]; - } else { - warningMsg = out[i]; - } - } - } - - // If there are warnings - if (warn) { - // Create warning bar - var warningBar = createWarnBar(warningMsg); - warningBar.css('margin-bottom', '10px'); - warningBar.prependTo($('#nodesTab')); - } else { - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'gangliastart;' + data.msg + ';-r', - msg : data.msg - }, - - success : function(data) { - // Remove any warnings - $('#nodesTab').find('.ui-state-error').remove(); - - // Update datatable - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'gangliastatus;' + data.msg, - msg : '' - }, - - success : loadGangliaStatus - }); - } - }); - } // End of if (warn) - } // End of function(data) - }); - } else { - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'gangliastart', - msg : '' - }, - - success : function(data) { - // Remove any warnings - $('#nodesTab').find('.ui-state-error').remove(); - } - }); - } // End of if (node) - } else { - var args; - if (node) { - args = 'gangliastop;' + node + ';-r'; - } else { - args = 'gangliastop'; - } - - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : args, - msg : '' - }, - - success : function(data) { - // Hide ganglia loader - var gangliaCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); - gangliaCol.find('img').hide(); - } - }); - } -} - -/** - * Install Ganglia on a given node - * - * @param node Node to install Ganglia on - */ -function installGanglia(node) { - var iframe = createIFrame('lib/cmd.php?cmd=webrun&tgt=&args=installganglia;' + node + '&msg=' + node + '&opts=flush'); - iframe.prependTo($('#nodesTab')); - - // Turn on Ganglia for node - monitorNode(node, 'on'); -} - -/** - * After nodes are loaded, load more information based on different hardware architectures - * - * @param group Group name - */ -function advancedLoad(group){ - var tempIndex = 0; - var tableHeaders = $('#' + nodesTableId).parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr:eq(0) th'); - var colNameHash = new Object(); - var colName = ''; - var archCol = 0, hcpCol = 0; - - // Find out the column name and their index - for (tempIndex = 0; tempIndex < tableHeaders.size(); tempIndex++){ - var header = tableHeaders.eq(tempIndex); - // Skip headers that are links, e.g. status, power, and monitor - if (header.find('a').size() > 0){ - continue; - } - - colName = header.text(); - - if (colName) { - colNameHash[colName] = tempIndex; - } - } - - // If there is no arch column, exit because you cannot distinguish hardware type - if (!colNameHash['arch']) { - return; - } - - if (!colNameHash['hcp']) { - return; - } - archCol = colNameHash['arch']; - hcpCol = colNameHash['hcp']; - - // Get hardware control point - var rows = $('#' + nodesTableId + ' tbody tr'); - var hcps = new Object(); - var rowsNum = rows.size(); - for (var j = 0; j < rowsNum; j++) { - var val = rows.eq(j).find('td').eq(hcpCol).html(); - var archval = rows.eq(j).find('td').eq(archCol).html(); - if (-1 == archval.indexOf('390')){ - continue; - } - hcps[val] = 1; - } - - if (Object.keys(hcps).length == 0) { - openDialog('warn', "No node found with hcp column filled in and 390 arch!"); - return; - } - // Get Nodes info bar - //var nodeInfoBar = getNodesTabInfoBar(); - //nodeInfoBar.append("\nEntering Advanced Load...\n") - - var args; - var shortzHcps = new Array(); - var zhcpHash = new Object(); - for (var h in hcps) { - // Get node without domain name - args = h.split('.'); - - if (!zhcpHash[args[0]]) { - - shortzHcps.push(args[0]); - zhcpHash[args[0]] = 1; - - // If there are no disk pools or network names cookie for this hcp - if (!$.cookie('xcat_' + args[0] + 'diskpools') || !$.cookie('xcat_' + args[0] + 'networks')) { - // Check if SMAPI is online - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsvm', - tgt : args[0], - args : '', - msg : 'group=' + group + ';hcp=' + args[0] - }, - - // Load hardware control point specific info - // Get disk pools and network names - success : loadHcpInfo - }); - } - } - } // End of for - - // Save zHCPs as a cookie - setzHcpCookies(shortzHcps); - - // Retrieve z/VM hypervisors and their zHCPs - if (!$.cookie('xcat_zvms')) { - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webportal', - tgt : '', - args : 'lszvm', - msg : '' - }, - - success : function(data) { - setzVMCookies(data); - } - }); - } -} - -/** - * Jump to provision page on-click - * - * @param tgtNodes Target nodes - */ -function jump2Provision(tgtNodes){ - var nodeArray = tgtNodes.split(','); - var nodeName = ''; - var index = 0; - var archType = ''; - var errorMsg = ''; - var master = ''; - var tftpserver = ''; - var nfsserver = ''; - var diaDiv = $('
                          '); - - // Check the first node's arch type - for (index in nodeArray){ - nodeName = nodeArray[index]; - - // Skip if node does not have arch - if (!origAttrs[nodeName]['arch']){ - errorMsg = 'Nodes should have arch defined! '; - break; - } - - if (index == 0) { - archType = origAttrs[nodeName]['arch']; - } - - // Skip if nodes do not have same arch - if (archType != origAttrs[nodeName]['arch']){ - errorMsg = 'Nodes should belong to the same arch!
                          '; - break; - } - } - - // Skip if nodes do not have MAC address - for (index in nodeArray){ - if (!origAttrs[nodeName]['mac'] || !origAttrs[nodeName]['ip']){ - errorMsg += 'Nodes should have the IP and MAC addresses defined!
                          '; - break; - } - } - - if (archType.indexOf('390') != -1) { - errorMsg += 'Please use the provision page'; - } - - // Open dialog to show error message - if (errorMsg){ - diaDiv.append(createWarnBar(errorMsg)); - diaDiv.dialog({ - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - 'Close': function(){ - $(this).dialog('destroy'); - } - } - }); - - return; - } - - if (origAttrs[nodeName]['xcatmaster']) { - master = origAttrs[nodeName]['xcatmaster']; - } - - if (origAttrs[nodeName]['tftpserver']) { - tftpserver = origAttrs[nodeName]['tftpserver']; - } - - if (origAttrs[nodeName]['nfsserver']) { - nfsserver = origAttrs[nodeName]['nfsserver']; - } - - window.location.href = 'provision.php?nodes=' + tgtNodes + '&arch=' + archType + '&master=' + master + - '&tftpserver=' + tftpserver + '&nfsserver=' + nfsserver; -} \ No newline at end of file +/** + * Global variables + *Test Git update in MCP_DEV branch */ +var nodesTab; // Nodes tabs +var origAttrs = new Object(); // Original node attributes +var nodeAttrs; // Node attributes +var nodesList; // Node list +var nodesTableId = 'nodesDatatable'; // Nodes datatable ID +var nodesTabInfoBar; +var builtInXCAT = 1; // 1 means xCAT shipped with zVM + +/** + * Set node tab + * + * @param tab + * Tab object + * @return Nothing + */ +function setNodesTab(tab) { + nodesTab = tab; +} + +/** + * Get node tab + * + * @return Tab object + */ +function getNodesTab() { + return nodesTab; +} + +/** + * Set node tab info bar. Used by zvmUtils.js + * + * @param tab + * infobar object + * @return Nothing + */ +function setNodesTabInfoBar(tabinfo) { + nodesTabInfoBar = tabinfo; +} + +/** + * Get node tab info bar + * + * @return Tab info bar object + */ +function getNodesTabInfoBar() { + return nodesTabInfoBar; +} + +/** + * Get node list + * + * @return Node list + */ +function getNodesList() { + return nodesList; +} + +/** + * Get nodes table ID + * + * @return Nodes table ID + */ +function getNodesTableId() { + return nodesTableId; +} + +/** + * Load nodes page + */ +function loadNodesPage() { + // If groups are not already loaded + if (!$('#groups').length) { + // Create a groups division + var groups = $('
                          '); + var nodes = $('
                          '); + $('#content').append(groups); + $('#content').append(nodes); + + // Create loader and info bar + groups.append(createLoader()); + + // Get groups + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'extnoderange', + tgt : '/.*', + args : 'subgroups', + msg : '' + }, + + // Load groups + success : function(data){ + data = decodeRsp(data); + loadGroups(data); + + var cookieGroup = $.cookie('xcat_selectgrouponnodes'); + if (cookieGroup) { + $('#groups .groupdiv div').each(function(){ + if ($(this).text() == cookieGroup){ + $(this).trigger('click'); + return false; + } + }); + } else { + // Trigger the first group click event + $('#groups .groupdiv div').eq(0).trigger('click'); + } + } + }); + } +} + +/** + * Show cluster summary in pie charts + * + * @param groupName Group name + */ +function loadPieSummary(groupName){ + var summaryTable = '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
                          '; + $('#summaryTab').append(summaryTable); + $('#summaryTab .summarypie').append(createLoader()); + + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'summary;' + groupName, + msg : '' + }, + + success:function(data) { + data = decodeRsp(data); + for (var i in data.rsp) { + drawPieSummary(i, data.rsp[i]); + } + } + }); +} + +/** + * Get nodes information and draw pie chart + * + * @param index Node index + * @param valuePair Node information key value pairing + */ +function drawPieSummary(index, valuePair){ + var position = 0; + var key = ''; + var val = ''; + var chartTitle = ''; + var dataArray = []; + var tempArray = []; + var container = $('#summaryTab .summarypie').eq(index); + + position = valuePair.indexOf('='); + chartTitle = valuePair.substr(0, position); + tempArray = valuePair.substr(position + 1).split(';'); + + for (var i in tempArray) { + position = tempArray[i].indexOf(':'); + key = tempArray[i].substr(0, position); + val = Number(tempArray[i].substr(position + 1)); + dataArray.push([key,val]); + } + + container.empty(); + + var plot = $.jqplot(container.attr('id'), [dataArray], { + title: chartTitle, + seriesDefaults: { + renderer: $.jqplot.PieRenderer, + rendererOptions: { + padding: 5, + fill: true, + shadow: true, + shadowOffset: 2, + shadowDepth: 5, + shadowAlpha: 0.07, + dataLabels : 'value', + showDataLabels: true + } + }, + legend: { + show:true, + location: 'e' + } + }); +} + +/** + * Load groups + * + * @param data Data returned from HTTP request + */ +function loadGroups(data) { + // Remove loader + $('#groups').find('img').remove(); + + // Save group in cookie + var groups = data.rsp; + setGroupsCookies(data); + + // Create a list of groups + $('#groups').append('
                          Groups
                          '); + var grouplist= $('
                          '); + // Create a link for each group + for (var i = 0; i < groups.length; i++) { + grouplist.append('
                          ' + groups[i] + '
                          '); + } + + $('#groups').append(grouplist); + + // Bind the click event + $('#groups .groupdiv div').bind('click', function(){ + var thisGroup = $(this).text(); + $('#groups .groupdiv div').removeClass('selectgroup'); + $(this).addClass('selectgroup'); + + // Save selected group into cookie + $.cookie('xcat_selectgrouponnodes', thisGroup, { expires: 7, path: '/xcat', secure:true }); + + drawNodesArea(thisGroup,'',thisGroup); + }); + + // Make a link to add nodes + $('#groups').append('
                          '); + $('#groups #adddiv').append(mkAddNodeLink()); +} + +/** + * Empty the nodes area and add three tabs for nodes result + * + * @param targetgroup The name range for nodels command + * @param cmdargs Filter arguments for nodels command + * @param message The useful information from the HTTP request + */ +function drawNodesArea(targetgroup, cmdargs, message){ + // Clear nodes division + $('#nodes').empty(); + + // Create a tab for this group + var tab = new Tab('nodesPageTabs'); + setNodesTab(tab); + tab.init(); + $('#nodes').append(tab.object()); + tab.add('summaryTab', 'Summary', '', false); + tab.add('nodesTab', 'Nodes', '', false); + if (builtInXCAT == 0) { + tab.add('graphTab', 'Graphic', '', false); + } + + // Load nodes table when tab is selected + $('#nodesPageTabs').bind('tabsselect', function(event, ui) { + // Load summary when tab is selected + if (!$('#summaryTab').children().length && ui.index == 0) { + loadPieSummary(targetgroup); + } + + // Load nodes table when tab is selected + else if (!$('#nodesTab').children().length && ui.index == 1) { + // Create loader + $('#nodesTab').append($('
                          ').append(createLoader())); + + // To improve performance, get all nodes within selected group + // Get node definitions only for first 50 nodes + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodels', + tgt : targetgroup, + args : cmdargs, + msg : message + }, + + /** + * Get node definitions for first 50 nodes + * + * @param data Data returned from HTTP request + */ + success : function(data) { + data = decodeRsp(data); + var rsp = data.rsp; + var group = data.msg; + + // Save nodes in a list so it can be accessed later + nodesList = new Array(); + for (var i in rsp) { + if (rsp[i][0]) { + nodesList.push(rsp[i][0]); + } + } + + // Sort nodes list + nodesList.sort(); + + // Get first 50 nodes + var nodes = ''; + for (var i = 0; i < nodesList.length; i++) { + if (i > 49) { + break; + } + + nodes += nodesList[i] + ','; + } + + // Remove last comma + nodes = nodes.substring(0, nodes.length-1); + + // Get nodes definitions + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsdef', + tgt : '', + args : nodes, + msg : targetgroup + }, + + success : function(data) { + data = decodeRsp(data); + loadNodes(data); + } + }); + + } + }); + } + + // Load graphical layout when tab is selected + else if ((builtInXCAT == 0) && (!$('#graphTab').children().length && ui.index == 2)) { + // For the graphical tab, check the graphical data first + createPhysicalLayout(nodesList); + } + + }); + + // Get last view (if any) + // This can be summary, nodes, or graphic + if ($.cookie('xcat_tabindex_history')) { + var order = $.cookie('xcat_tabindex_history').split(','); + order[0] = parseInt(order[0]); + order[1] = parseInt(order[1]); + if (order[0] == 0 || order[1] == 0) { + // For some reason, you cannot trigger a select of index 0 + loadPieSummary(targetgroup); + } else if (order[0] == 1 || order[0] == 2) { + $('#nodesPageTabs').tabs('select', order[0]); + } else if (order[1] == 1 || order[1] == 2) { + $('#nodesPageTabs').tabs('select', order[1]); + } else { + loadPieSummary(targetgroup); + } + } else { + loadPieSummary(targetgroup); + } +} + +/** + * Make a link to add nodes + * + * @returns Link to add nodes + */ +function mkAddNodeLink() { + // Create link to add nodes + var addNodeLink = $('+ Add node'); + addNodeLink.click(function() { + // Create info bar + var info = createInfoBar('Select the hardware management for the new node range'); + + // Create form to add node + var addNodeForm = $('
                          '); + addNodeForm.append(info); + if (builtInXCAT == 0) { + addNodeForm.append('
                          ' + + '' + + '
                          '); + } else { + addNodeForm.append('
                          ' + + '' + + '
                          '); + } + + // Create advanced link to set advanced node properties + var advanced = $('
                          '); + var advancedLnk = $('Advanced').css({ + 'cursor': 'pointer', + 'color': '#0000FF' + }); + advancedLnk.click(function() { + // Get node attributes + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsdef', + tgt : '', + args : '-t;node;-h', + msg : '' + }, + + /** + * Set node attributes and open dialog + * + * @param data Data returned from HTTP request + */ + success : function(data) { + data = decodeRsp(data); + // Save node attributes + setNodeAttrs(data); + // Open a dialog to set node attributes + openSetAttrsDialog(); + } + }); + + // Close dialog + addNodeForm.dialog('destroy').remove(); + }); + advanced.append(advancedLnk); + addNodeForm.append(advanced); + + // Open dialog to add node + addNodeForm.dialog({ + modal: true, + width: 400, + title:'Add node', + close: function() {$(this).remove();}, + buttons: { + 'Ok': function() { + // Get hardware management + var mgt = $(this).find('select[name=mgt]').val(); + + var plugin; + switch(mgt) { + case "kvm": + plugin = new kvmPlugin(); + break; + case "esx": + plugin = new esxPlugin(); + break; + case "blade": + plugin = new bladePlugin(); + break; + case "hmc": + plugin = new hmcPlugin(); + break; + case "ipmi": + plugin = new ipmiPlugin(); + break; + case "zvm": + plugin = new zvmPlugin(); + break; + } + + $(this).dialog('destroy').remove(); + plugin.addNode(); + }, + 'Cancel': function(){ + $(this).dialog('destroy').remove(); + } + } + }); + + }); + + // Generate tooltips + addNodeLink.tooltip({ + position: 'center right', + offset: [-2, 10], + effect: 'fade', + opacity: 0.7, + predelay: 800 + }); + + return addNodeLink; +} + +/** + * Load nodes belonging to a given group + * + * @param data Data returned from HTTP request + */ +function loadNodes(data) { + // Clear the tab before inserting the table + $('#nodesTab').children().remove(); + + // Data returned + var rsp = data.rsp; + // Group name + var group = data.msg; + // Hash of Node attributes + var attrs = new Object(); + // Node attributes + var headers = new Object(); + + // Variable to send command and request node status + var getNodeStatus = true; + + // Clear hash table containing node attributes + origAttrs = ''; + + var node, args; + for (var i in rsp) { + // Get node name + if (rsp[i].indexOf('Object name:') > -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('=', 2); + var key = jQuery.trim(args[0]); + var val = jQuery.trim(rsp[i].substring(rsp[i].indexOf('=') + 1)); + + // Create a hash table + attrs[node][key] = val; + headers[key] = 1; + + // If node status is available + if (key == 'status') { + // Do not request node status + getNodeStatus = false; + } + } + + // Add nodes that are not in data returned + for (var i in nodesList) { + if (!attrs[nodesList[i]]) { + // Create attributes list and save node name + attrs[nodesList[i]] = new Object(); + attrs[nodesList[i]]['node'] = nodesList[i]; + } + } + + // Save attributes in hash table + origAttrs = attrs; + + // Sort headers + var sorted = new Array(); + for (var key in headers) { + // Do not put comments and status in twice + if (key != 'usercomment' && key != 'status' && key.indexOf('status') < 0) { + sorted.push(key); + } + } + sorted.sort(); + + // Add column for check box, node, ping, power, monitor, and comments + sorted.unshift('', + 'node', + 'status', + 'power', + 'monitor', + 'comments'); + + // Create a datatable + var nodesTable = new DataTable(nodesTableId); + nodesTable.init(sorted); + + // Go through each node + for (var node in attrs) { + // Create a row + var row = new Array(); + + // Create a check box, node link, and get node status + var checkBx = ''; + var nodeLink = $('' + node + '').bind('click', loadNode); + + // If there is no status attribute for the node, do not try to access hash table + // else the code will break + var status = ''; + if (attrs[node]['status']) { + status = attrs[node]['status'].replace('sshd', 'ping'); + } + + // Push in checkbox, node, status, monitor, and power + row.push(checkBx, nodeLink, status, '', ''); + + // If the node attributes are known (i.e the group is known) + if (attrs[node]['groups']) { + // Put in comments + var comments = attrs[node]['usercomment']; + // If no comments exists, show 'No comments' and set icon image source + var iconSrc; + if (!comments) { + comments = 'No comments'; + iconSrc = 'images/nodes/ui-icon-no-comment.png'; + } else { + iconSrc = 'images/nodes/ui-icon-comment.png'; + } + + // Create comments icon + var tipID = node + 'Tip'; + var icon = $('').css({ + 'width': '18px', + 'height': '18px' + }); + + // Create tooltip + var tip = createCommentsToolTip(comments); + var col = $('').append(icon); + col.append(tip); + row.push(col); + + // Generate tooltips + icon.tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.8, + relative: true, + delay: 500 + }); + } else { + // Do not put in comments if attributes are not known + row.push(''); + } + + // Go through each header + for (var i = 6; i < sorted.length; i++) { + // Add the node attributes to the row + var key = sorted[i]; + + // Do not put comments and status in twice + if (key != 'usercomment' && key != 'status' && key.indexOf('status') < 0) { + var val = attrs[node][key]; + if (val) { + row.push(val); + } else { + row.push(''); + } + } + } + + // Add the row to the table + nodesTable.add(row); + } + + // Clear the tab before inserting the table + $('#nodesTab').children().remove(); + + // Create info bar for nodes tab + var info = createInfoBar('Double-click on a cell to edit a node\'s properties. Click outside the table to save changes. Hit the Escape key to ignore changes.'); + $('#nodesTab').append(info); + info.id = 'NodesInfoBar'; + setNodesTabInfoBar(info); + + // Create action bar + var actionBar = $('
                          ').css("width", "400px"); + + /** + * Create menu for actions to perform against a given node + */ + + // Power on + var powerOnLnk = $('Power on'); + powerOnLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + powerNode(tgtNodes, 'on'); + } + }); + + // Power off + var powerOffLnk = $('Power off'); + powerOffLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + + var msg = 'Do you want to power off: ' + tgtNodes + '?'; + // Open dialog to confirm + var confirmDialog = $('

                          ' + msg + '

                          '); + confirmDialog.dialog({ + title:'Confirm', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function(){ + powerNode(tgtNodes, 'off'); + $(this).dialog("close"); + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); + } + }); + + // Power softoff + var powerSoftoffLnk = $('Shutdown'); + powerSoftoffLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + var msg = 'Do you want to shutdown: ' + tgtNodes + '?'; + // Open dialog to confirm + var confirmDialog = $('

                          ' + msg + '

                          '); + confirmDialog.dialog({ + title:'Confirm', + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Ok": function(){ + powerNode(tgtNodes, 'softoff'); + $(this).dialog("close"); + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); + } + }); + if (builtInXCAT == 0) { + // Turn monitoring on + var monitorOnLnk = $('Monitor on'); + monitorOnLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + monitorNode(tgtNodes, 'on'); + } + }); + + // Turn monitoring off + var monitorOffLnk = $('Monitor off'); + monitorOffLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + monitorNode(tgtNodes, 'off'); + } + }); + } + + // Clone + var cloneLnk = $('Clone'); + cloneLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId).split(','); + for (var i in tgtNodes) { + var mgt = getNodeAttr(tgtNodes[i], 'mgt'); + + // Create an instance of the plugin + var plugin; + switch(mgt) { + case "kvm": + plugin = new kvmPlugin(); + break; + case "esx": + plugin = new esxPlugin(); + break; + case "zvm": + plugin = new zvmPlugin(); + break; + } + if (mgt == "zvm") { + var nodeOS = getNodeAttr(tgtNodes[i], 'os'); + var nodeArch = getNodeAttr(tgtNodes[i], 'arch'); + plugin.loadClonePage(tgtNodes[i], nodeOS, nodeArch); + } else { + plugin.loadClonePage(tgtNodes[i]); + } + + } + }); + + // Delete + var deleteLnk = $('Delete'); + deleteLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + loadDeletePage(tgtNodes); + } + }); + + // Unlock Function + var unlockLnk = $('Unlock'); + unlockLnk.click(function() { + + // Get the "master" value from the site table. + var siteMaster; + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'site', + msg : 'cmd=tabdump site;' + }, + + success : function(data) { + data = decodeRsp(data); + var outId = $(data.msg); + var props = data.rsp; + if ( jQuery.isArray(data.rsp) ) { + for (var i in data.rsp) { + if ( data.rsp[i].indexOf('"master"') == 0 ) { + siteMaster = data.rsp[i].slice( 10, -3 ); + } + } + } else { + if ( data.rsp.indexOf('"master"') == 0 ) { + siteMaster = data.rsp.slice( 10, -3 ); + } + } + + // Process the nodes that were checked. + var tgtNodes = getNodesChecked(nodesTableId).split(','); + var normalNodes = ''; + var mnNode = ''; + for (var i in tgtNodes) { + var nodeIP = getNodeAttr( tgtNodes[i], 'ip' ); + if ( nodeIP == siteMaster ) { + if ( mnNode == '' ) { + // Only one xCAT node will have the same address as + // the site master IP address and this is the + // xCAT MN. + mnNode = tgtNodes[i]; + } + } else { + if ( normalNodes == '' ) { + normalNodes = tgtNodes[i]; + } else { + normalNodes = normalNodes + "," + tgtNodes[i]; + } + } + } + + if ( normalNodes != '' ) { + loadUnlockPage( normalNodes ); + } + if ( mnNode != '' ) { + loadUnlockNonNodesPage( mnNode ); + } + } + }); + }); + + // Run script + var scriptLnk = $('Run script'); + scriptLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + loadScriptPage(tgtNodes); + } else { + openDialog('warn', "No nodes checked!"); + } + }); + + // Migrate VM + var migrateLnk = $('Migrate'); + migrateLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId).split(','); + var mgt = "", tmp = ""; + var fromhcp = ""; + for (var i in tgtNodes) { + tmp = getNodeAttr(tgtNodes[i], 'mgt'); + fromhcp += getNodeAttr(tgtNodes[i], 'hcp') + ','; + if (!mgt) { + mgt = tmp + } else { + if (tmp != mgt) { + openDialog('warn', "You can pick only one type (mgt) of node to migrate!"); + return; + } + } + } + + // Create an instance of the plugin + var plugin; + switch(mgt) { + // Only hypervisors support migration + case "kvm": + plugin = new kvmPlugin(); + break; + case "esx": + plugin = new esxPlugin(); + break; + case "zvm": + plugin = new zvmPlugin(); + break; + } + if (mgt == "zvm") { + plugin.loadMigratePage(tgtNodes, fromhcp); + } else { + plugin.loadMigratePage(tgtNodes); + } + }); + + // Update + var updateLnk = $('Update'); + updateLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + loadUpdatenodePage(tgtNodes); + } + }); + + // Set boot state + var setBootStateLnk = $('Set boot state'); + setBootStateLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + loadNodesetPage(tgtNodes); + } + }); + + // Boot to network + var boot2NetworkLnk = $('Boot to network'); + boot2NetworkLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + loadNetbootPage(tgtNodes); + } + }); + + // Provision node + var provisionLnk = $('Provision'); + provisionLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes){ + // Jump directly to the provision page + jump2Provision(tgtNodes); + } + }); + + // Remote console + var rcons = $('Open console'); + rcons.bind('click', function(event){ + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + loadRconsPage(tgtNodes); + } + }); + + // Discovery + var discoverLnk = $('Discover systems'); + discoverLnk.bind( 'click', function(event) { + var tgtNodes = getNodesChecked(nodesTableId).split(','); + if ( tgtNodes ) { + var hosts; + for (var i in tgtNodes) { + var hostType = getNodeAttr( tgtNodes[i], 'hosttype' ); + if ( hostType == 'zvm' ) { + if ( hosts ) { + hosts += "," + tgtNodes[i]; + } else { + hosts = tgtNodes[i]; + } + + } else { + openDialog('warn', tgtNodes[i] + " does not have a hosttype of 'zvm': " + hostType ); + } + } + if ( hosts ) { + discoverVMNodes( hosts ); + } + } else { + openDialog('warn', "No nodes checked!"); + } + }); + + // Edit properties + var editProps = $('Edit properties'); + editProps.bind('click', function(event){ + var tgtNodes = getNodesChecked(nodesTableId).split(','); + for (var i in tgtNodes) { + editNodeProps(tgtNodes[i]); + } + }); + + // Install Ganglia + var installMonLnk = $('Install monitoring'); + installMonLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + installGanglia(tgtNodes); + } + }); + + // Scan + var rscanLnk = $('Scan'); + rscanLnk.bind('click', function(event){ + var tgtNodes = getNodesChecked(nodesTableId); + if (tgtNodes) { + loadRscanPage(tgtNodes); + } + }); + + // Event log + var logLnk = $('Event log'); + logLnk.click(function() { + var tgtNodes = getNodesChecked(nodesTableId).split(','); + for (var i in tgtNodes) { + var mgt = getNodeAttr(tgtNodes[i], 'mgt'); + + // Create an instance of the plugin + var plugin; + switch(mgt) { + case "kvm": + plugin = new kvmPlugin(); + break; + case "esx": + plugin = new esxPlugin(); + break; + case "blade": + plugin = new bladePlugin(); + break; + case "hmc": + plugin = new hmcPlugin(); + break; + case "ipmi": + plugin = new ipmiPlugin(); + break; + case "zvm": + plugin = new zvmPlugin(); + break; + } + + plugin.loadLogPage(tgtNodes[i]); + } + }); + + // Actions + var actionsLnk = 'Actions'; + if (builtInXCAT == 0) { + if (group == 'hosts') { + var actsMenu = createMenu([deleteLnk]); + } else { + var actsMenu = createMenu([cloneLnk, deleteLnk, migrateLnk, monitorOnLnk, monitorOffLnk, powerOnLnk, powerOffLnk, scriptLnk, powerSoftoffLnk]); + } + } else { + if (group == 'hosts') { + var actsMenu = createMenu([deleteLnk]); + } else { + var actsMenu = createMenu([cloneLnk, deleteLnk, migrateLnk, powerOnLnk, powerOffLnk, scriptLnk, powerSoftoffLnk]); + } + } + + // Configurations + var configLnk = 'Configuration'; + if (builtInXCAT == 0) { + if (group == 'hosts') { + var configMenu = createMenu([editProps]); + } else { + var configMenu = createMenu([editProps, logLnk, installMonLnk, rscanLnk, unlockLnk, updateLnk]); + } + } else { + if (group == 'hosts') { + var configMenu = createMenu([ discoverLnk, editProps ]); + } else { + var configMenu = createMenu([editProps, logLnk, rscanLnk, unlockLnk, updateLnk]); + } + } + + // Provision + var provLnk = 'Provision'; + if (builtInXCAT == 0) { + var provMenu = createMenu([boot2NetworkLnk, rcons, setBootStateLnk, provisionLnk]); + } else { + var provMenu = createMenu([boot2NetworkLnk, setBootStateLnk]); + } + + /** + * Refresh button + */ + var refreshBtn = createButton('Refresh'); + refreshBtn.click(function() { + // Remove any warning messages + $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); + + var zhcpsCheck = $.cookie('xcat_zhcps').split(','); + var zhcpHash = new Object(); + for (var h in zhcpsCheck) { + if (!zhcpHash[zhcpsCheck[h]]) { + + zhcpHash[zhcpsCheck[h]] = 1; + if (typeof console == "object"){ + console.log("zhcp check for <"+zhcpsCheck[h]+">"); + } + + // Check if SMAPI is online + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : zhcpsCheck[h], + args : '', + msg : 'group=refreshgroups' + ';hcp=' + zhcpsCheck[h] + }, + + // Load hardware control point specific info + // Get disk pools and network names + success : function(data) { + data = decodeRsp(data); + loadHcpInfo(data); + } + }); + } + } + + window.location.reload(); + }); + refreshBtn.css({'width': '80px'}); + refreshBtn.css({'height': '27px'}); + //refreshBtn.css('vertical-align', 'top'); + refreshBtn.css({'align': 'top'}); + + // Create an action menu + var actionsMenu; + if (group == 'hosts') { + actionsMenu = createMenu([ [ actionsLnk, actsMenu ], [ configLnk, configMenu ] ]); + } else { + actionsMenu = createMenu([ [ actionsLnk, actsMenu ], [ configLnk, configMenu ], [ provLnk, provMenu ] ]); + } + actionsMenu.superfish(); + actionsMenu.css('display', 'inline-block'); + actionBar.append(actionsMenu); + actionBar.append(refreshBtn); + + // Set correct theme for action menu + actionsMenu.find('li').hover(function() { + setMenu2Theme($(this)); + }, function() { + setMenu2Normal($(this)); + }); + + // Insert action bar and nodes datatable + $('#nodesTab').append(nodesTable.object()); + + // Turn table into a datatable + var nodesDatatable = $('#' + nodesTableId).dataTable({ + 'iDisplayLength': 50, + 'bLengthChange': false, + "bScrollCollapse": true, + "sScrollY": "400px", + "sScrollX": "110%", + "bAutoWidth": true, + "oLanguage": { + "oPaginate": { + "sNext": "", + "sPrevious": "" + } + } + }); + + // Filter table when enter key is pressed + $('#' + nodesTableId + '_filter input').unbind(); + $('#' + nodesTableId + '_filter input').bind('keyup', function(e){ + if (e.keyCode == 13) { + var table = $('#' + nodesTableId).dataTable(); + table.fnFilter($(this).val()); + + // If there are nodes found, get the node attributes + if (!$('#' + nodesTableId + ' .dataTables_empty').length) { + getNodeAttrs(group); + } + } + }); + + // Load node definitions when next or previous buttons are clicked + $('#' + nodesTableId + '_next, #' + nodesTableId + '_previous').click(function() { + getNodeAttrs(group); + }); + + /** + * Change how datatable behaves + */ + + // Do not sort ping, power, and comment column + var cols = $('#' + nodesTableId + ' thead tr th').click(function() { + getNodeAttrs(group); + }); + var checkboxCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(0)'); + var pingCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); + var powerCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + var monitorCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + var commentCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(5)'); + checkboxCol.unbind('click'); + pingCol.unbind('click'); + powerCol.unbind('click'); + monitorCol.unbind('click'); + commentCol.unbind('click'); + + // Create enough space for loader to be displayed + // Center align power, ping, and comments + $('#' + nodesTableId + ' td:nth-child(3),td:nth-child(4),td:nth-child(5)').css({'text-align': 'center'}); + + // No minimum width for comments column + $('#' + nodesTableId + ' tbody tr td:nth-child(6)').css('text-align', 'center'); + + // Instead refresh the node, power, and monitor status + pingCol.find('span a').click(function() { + refreshNodeStatus(group, nodesTableId); + }); + powerCol.find('span a').click(function() { + refreshPowerStatus(group, nodesTableId); + }); + monitorCol.find('span a').click(function() { + refreshGangliaStatus(group, nodesTableId); + }); + + // Create a division to hold actions menu + var menuDiv = $(''); // #
                          '); + update.append(createInfoBar('Updating table ')); + + update.dialog({ + title: 'Updating', + modal: true, + width: 300, + position: 'center' + }); + } +} + +/** + * Add nodes to datatable + * + * @param data Data returned from HTTP request + */ +function addNodes2Table(data) { + // Data returned + var rsp = data.rsp; + // Group name + var group = data.msg; + // Hash of node attributes + var attrs = new Object(); + // Node attributes + var headers = $('#' + nodesTableId).parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr th'); + + // Variable to send command and request node status + var getNodeStatus = true; + + // Go through each attribute + var node, args; + for (var i in rsp) { + // Get node name + if (rsp[i].indexOf('Object name:') > -1) { + var temp = rsp[i].split(': '); + node = jQuery.trim(temp[1]); + + // Create a hash for node attributes + attrs[node] = new Object(); + i++; + } + + // Get key and value + args = rsp[i].split('=', 2); + var key = jQuery.trim(args[0]); + var val = jQuery.trim(rsp[i].substring(rsp[i].indexOf('=') + 1, rsp[i].length)); + + // Create a hash table + attrs[node][key] = val; + // Save attributes in original hash table + origAttrs[node][key] = val; + + // If node status is available + if (key == 'status') { + // Do not request node status + getNodeStatus = false; + } + } + + // Set the first five headers + var headersCol = new Object(); + headersCol['node'] = 1; + headersCol['status'] = 2; + headersCol['power'] = 3; + headersCol['monitor'] = 4; + headersCol['comments'] = 5; + + // Go through each header + for (var i = 6; i < headers.length; i++) { + // Get the column index + headersCol[headers.eq(i).html()] = i; + } + + // Go through each node + var datatable = $('#' + nodesTableId).dataTable(); + var rows = datatable.fnGetData(); + for (var node in attrs) { + // Get row containing node + var nodeRowPos = 0; + for (var i in rows) { + // If column contains node + if (rows[i][1].indexOf('>' + node + '<') > -1) { + nodeRowPos = i; + break; + } + } + + // Get node status + var status = ''; + if (attrs[node]['status']){ + status = attrs[node]['status'].replace('sshd', 'ping'); + } + + rows[nodeRowPos][headersCol['status']] = status; + + // Go through each header + for (var key in headersCol) { + // Do not put comments and status in twice + if (key != 'usercomment' && key != 'status' && key.indexOf('status') < 0) { + var val = attrs[node][key]; + if (val) { + rows[nodeRowPos][headersCol[key]] = val; + } + } + } + + // Update row + datatable.fnUpdate(rows[nodeRowPos], parseInt(nodeRowPos), undefined, false); + + // Insert node comments + // This is done after datatable is updated because + // you cannot insert an object using fnUpdate() + var comments = attrs[node]['usercomment']; + + // If no comments exists, show 'No comments' and + // set icon image source + var iconSrc; + if (!comments) { + comments = 'No comments'; + iconSrc = 'images/nodes/ui-icon-no-comment.png'; + } else { + iconSrc = 'images/nodes/ui-icon-comment.png'; + } + + // Create icon for node comments + var tipID = node + 'Tip'; + var commentsCol = $('#' + node).parent().parent().find('td').eq(5); + + // Create tooltip + var icon = $('').css({ + 'width': '18px', + 'height': '18px' + }); + + var tip = createCommentsToolTip(comments); + var span = $('').append(icon); + span.append(tip); + commentsCol.append(span); + + // Generate tooltips + icon.tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.8, + relative: true, + delay: 500 + }); + } + + // Enable node link + $('.node').bind('click', loadNode); + + // Close dialog for updating table + $('.ui-dialog-content').dialog('destroy').remove(); + + /** + * Enable editable columns + */ + // Do not make 1st, 2nd, 3rd, 4th, 5th, or 6th column editable + $('#' + nodesTableId + ' td:not(td:nth-child(1),td:nth-child(2),td:nth-child(3),td:nth-child(4),td:nth-child(5),td:nth-child(6))').editable( + function(value, settings) { + // If users did not do changes, return the value directly + // jeditable save the old value in this.revert + if ($(this).attr('revert') == value){ + return value; + } + // Get column index + var colPos = this.cellIndex; + + // Get row index + var dTable = $('#' + nodesTableId).dataTable(); + var rowPos = dTable.fnGetPosition(this.parentNode); + + // Update datatable + dTable.fnUpdate(value, rowPos, colPos, false); + + // Get table headers + var headers = $('#' + nodesTableId + ' thead tr th'); + + // Get node name + var node = $(this).parent().find('td a.node').text(); + // Get attribute name + var attrName = jQuery.trim(headers.eq(colPos).text()); + // Get column value + var value = $(this).text(); + + // Build argument + var args = attrName + '=' + value; + + // Send command to change node attributes + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chdef', + tgt : '', + args : '-t;node;-o;' + node + ';' + args, + msg : 'out=nodesTab;tgt=' + node + }, + + success: function(data) { + data = decodeRsp(data); + showChdefOutput(data); + } + }); + + return value; + }, { + onblur : 'submit', // Clicking outside editable area submits changes + type : 'textarea', + placeholder: ' ', + event : 'dblclick', + height : '30px' // The height of the text area + }); + + // If request to get node status is made + if (getNodeStatus) { + // Get node status + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodestat', + tgt : group, + args : '-u', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadNodeStatus(data); + } + }); + } else { + // Hide status loader + var statCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); + statCol.find('img').hide(); + } + + /** + * Additional ajax requests need to be made for zVM + */ + advancedLoad(group); + adjustColumnSize(nodesTableId); +} + +/** + * Load the status of Ganglia for a given group + * + * @param data Data returned from HTTP request + */ +function loadGangliaStatus(data) { + // Get datatable + var datatable = $('#' + nodesTableId).dataTable(); + var ganglia = data.rsp; + var rowNum, node, status; + + for ( var i in ganglia) { + // ganglia[0] = nodeName and ganglia[1] = state + node = jQuery.trim(ganglia[i][0]); + status = jQuery.trim(ganglia[i][1]); + + if (node) { + // Get the row containing the node + rowNum = findRow(node, '#' + nodesTableId, 1); + + // Update the power status column + datatable.fnUpdate(status, rowNum, 4); + } + } + + // Hide Ganglia loader + var gangliaCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + gangliaCol.find('img').hide(); + adjustColumnSize(nodesTableId); +} + +/** + * Refresh the status of Ganglia for each node + * + * @param group Group name + */ +function refreshGangliaStatus(group) { + // Show ganglia loader + var gangliaCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + gangliaCol.find('img').show(); + + // Get power status for nodes shown + var nodes = getNodesShown(nodesTableId); + + // Get the status of Ganglia + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliastatus;' + nodes, + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadGangliaStatus(data); + } + }); +} + +/** + * Load power status for each node + * + * @param data Data returned from HTTP request + */ +function loadPowerStatus(data) { + var dTable = $('#' + nodesTableId).dataTable(); + var power = data.rsp; + var rowPos, node, status, args; + + for (var i in power) { + // power[0] = nodeName and power[1] = state + args = power[i].split(':'); + node = jQuery.trim(args[0]); + status = jQuery.trim(args[1]); + + // Get the row containing the node + rowPos = findRow(node, '#' + nodesTableId, 1); + + // Update the power status column + dTable.fnUpdate(status, rowPos, 3); + } + + // Hide power loader + var powerCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + powerCol.find('img').hide(); + adjustColumnSize(nodesTableId); +} + +/** + * Refresh power status for each node + * + * @param group Group name + * @param tableId Table to update node status + */ +function refreshPowerStatus(group, tableId) { + // Show power loader + var powerCol = $('#' + tableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + powerCol.find('img').show(); + + // Get power status for nodes shown + var nodes = getNodesShown(tableId); + + // Get power status + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rpower', + tgt : nodes, + args : 'stat', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadPowerStatus(data); + } + }); +} + +/** + * Load node status for each node + * + * @param data Data returned from HTTP request + */ +function loadNodeStatus(data) { + var dTable = $('#' + nodesTableId).dataTable(); + var rsp = data.rsp; + var args, rowPos, node, status; + + // Get all nodes within datatable + for (var i in rsp) { + args = rsp[i].split(':'); + + // args[0] = node and args[1] = status + node = jQuery.trim(args[0]); + status = jQuery.trim(args[1]).replace('sshd', 'ping'); + + // Get row containing node + rowPos = findRow(node, '#' + nodesTableId, 1); + + // Update ping status column + dTable.fnUpdate(status, rowPos, 2, false); + } + + // Hide status loader + var statCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); + statCol.find('img').hide(); + adjustColumnSize(nodesTableId); +} + +/** + * Refresh ping status for each node + * + * @param group Group name + * @param tableId Table to update node status + */ +function refreshNodeStatus(group, tableId) { + // Show ping loader + var pingCol = $('#' + tableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); + pingCol.find('img').show(); + + // Get power status for nodes shown + var nodes = getNodesShown(tableId); + + // Get the node status + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodestat', + tgt : nodes, + args : '-u', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadNodeStatus(data); + } + }); +} + +/** + * Load inventory for given node + * + * @param e Windows event + */ +function loadNode(e) { + if (!e) { + e = window.event; + } + + // Get node that was clicked + var node = (e.target) ? e.target.id : e.srcElement.id; + var mgt = getNodeAttr(node, 'mgt'); + + // Create an instance of the plugin + var plugin; + switch(mgt) { + case "kvm": + plugin = new kvmPlugin(); + break; + case "esx": + plugin = new esxPlugin(); + break; + case "blade": + plugin = new bladePlugin(); + break; + case "hmc": + plugin = new hmcPlugin(); + break; + case "ipmi": + plugin = new ipmiPlugin(); + break; + case "zvm": + plugin = new zvmPlugin(); + break; + } + + // Get tab area where a new tab will be inserted + var myTab = getNodesTab(); + var inst = 0; + var newTabId = 'nodeTab' + inst; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + inst = inst + 1; + newTabId = 'nodeTab' + inst; + } + // Reset node process + $.cookie('xcat_' + node + 'Processes', 0, { path: '/xcat', secure:true }); + + // Add new tab, only if one does not exist + var loader = createLoader(newTabId + 'TabLoader'); + loader = $('
                          ').append(loader); + myTab.add(newTabId, node, loader, true); + + // Get node inventory + var msg = 'out=' + newTabId + ',node=' + node; + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rinv', + tgt : node, + args : 'all', + msg : msg + }, + + success : function(data) { + data = decodeRsp(data); + plugin.loadInventory(data); + } + }); + + // Select new tab + myTab.select(newTabId); +} + +/** + * Unlock a node by setting the ssh keys + * + * @param tgtNodes Nodes to unlock + */ +function loadUnlockPage(tgtNodes) { + // Get nodes tab + var tab = getNodesTab(); + + // Generate new tab ID + var instance = 0; + var newTabId = 'unlockTab' + instance; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + instance = instance + 1; + newTabId = 'unlockTab' + instance; + } + + // Create status bar, hide on load + var statBarId = 'unlockStatusBar' + instance; + var statBar = createStatusBar(statBarId).hide(); + + // Create loader + var loader = createLoader(''); + statBar.find('div').append(loader); + + // Create info bar + var infoBar = createInfoBar('Give the root password for this node range to setup its SSH keys.'); + + // Create unlock form + var unlockForm = $('
                          '); + unlockForm.append(statBar, infoBar); + + // Create VM fieldset + var vmFS = $('
                          '); + var vmLegend = $('Virtual Machine'); + vmFS.append(vmLegend); + unlockForm.append(vmFS); + + var vmAttr = $('
                          '); + vmFS.append($('
                          ')); + vmFS.append(vmAttr); + + vmAttr.append('
                          '); + vmAttr.append('
                          '); + + // Generate tooltips + unlockForm.find('div input[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + /** + * Ok + */ + var unlockBtn = createButton('Unlock'); + unlockBtn.css({ + 'width': '80px', + 'display': 'block' + }); + unlockBtn.click(function() { + // Remove any warning messages + $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); + + // If a password is given + var password = $('#' + newTabId + ' input[name=password]').css('border', 'solid #BDBDBD 1px'); + if (password.val()) { + // Setup SSH keys + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'unlock;' + tgtNodes + ';' + password.val(), + msg : 'out=' + statBarId + ';cmd=unlock;tgt=' + tgtNodes + }, + + success : function(data) { + data = decodeRsp(data); + updateStatusBar(data); + } + }); + + // Show status bar + statBar.show(); + + // Disable all inputs and Ok button + $('#' + newTabId + ' input').attr('disabled', 'disabled'); + $(this).attr('disabled', 'true'); + } else { + // Show warning message + var warn = createWarnBar('You are missing some values!'); + warn.prependTo($(this).parents('.ui-tabs-panel')); + password.css('border', 'solid #FF0000 1px'); + } + }); + + unlockForm.append(unlockBtn); + tab.add(newTabId, 'Unlock', unlockForm, true); + tab.select(newTabId); +} + +function loadUnlockNonNodesPage( tgtNodes ) { + + // Get nodes tab + var tab = getNodesTab(); + var fs, legend; + + // Generate new tab ID + var instance = 0; + var newTabId = 'unlockNonNodesTab' + instance; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + instance = instance + 1; + newTabId = 'unlockNonNodesTab' + instance; + } + + // Create info bar and status bar + var infoBar = createInfoBar( 'Unlock systems that have not been defined to xCAT. Either:
                          ' + + '-Create a script to install the xCAT Management Node\'s public key on the target systems, or
                          ' + + '-Unlock system(s) directly using their IP address(es) ' + + '(Specify multiple systems by separating the addresses with a comma),
                          ' + + '-Show the xCAT Management Node\'s public key to use to unlock the system.' ); + + var statBarId = 'unlockNonNodesStatusBar' + instance; + var statBar = createStatusBar(statBarId).hide(); + var loader = createLoader( '' ); + statBar.find('div').append( loader ); + + // Create unlock form and put info and status bars on the form + var unlockNonNodesForm = $( '
                          ' ); + unlockNonNodesForm.append( infoBar, statBar ); + + // Create 'Create an Unlock Script' fieldset + fs = $( '
                          ' ); + legend = $( 'Create an Unlock Script' ); + fs.append( legend ); + unlockNonNodesForm.append( fs ); + + // Create Script bar + var scriptBarId = 'unlockNonNodesScriptBar' + instance; + var scriptBar = createStatusBar(scriptBarId).hide(); + unlockNonNodesForm.append( scriptBar ); + + var createBtn = createButton( 'Create Script' ); + createBtn.css({ + 'width': '200px', + 'display': 'block' + }); + + createBtn.click(function() { + // Remove any warning messages + $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); + + // Get the SSH keys for a non-node + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'unlockshow;' + tgtNodes + ';script;', + msg : 'out=' + statBarId + ';scriptBar=' + scriptBarId +';cmd=unlock;tgt=' + tgtNodes + }, + + success : function(data) { + data = decodeRsp(data); + updateScriptBar(data); + } + }); + + // Show status bar + statBar.show(); + }); + + unlockNonNodesForm.append( createBtn ); + + // Create 'Unlock a system using the root password' Script fieldset + fs = $( '
                          ' ); + legend = $( 'Unlock a system using the root password' ); + fs.append( legend ); + unlockNonNodesForm.append( fs ); + + var vmAttr = $('
                          ' ); + fs.append($('
                          ')); + fs.append( vmAttr ); + + vmAttr.append( '
                          ' ); + vmAttr.append( '
                          ' ); + + /** + * Unlock button for non-nodes + */ + var unlockBtn = createButton('Unlock'); + unlockBtn.css({ + 'width': '80px', + 'display': 'block' + }); + + unlockBtn.click(function() { + // Remove any warning messages + $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); + + // If an ip and password is given + var ip = $('#' + newTabId + ' input[name=ip]').css('border', 'solid #BDBDBD 1px'); + var password = $( '#' + newTabId + ' input[name=password]').css('border', 'solid #BDBDBD 1px' ); + if ( password.val() && ip.val() ) { + $('#' + statBarId).find('img').show(); + // Setup SSH keys for a non-node + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'unlockbyip;' + tgtNodes + ';' + password.val() + ";" + ip.val(), + msg : 'out=' + statBarId + ';cmd=unlock;tgt=' + tgtNodes + }, + + success : function(data) { + data = decodeRsp(data); + updateStatusBar(data); + } + }); + + // Show status bar + statBar.show(); + } else { + // Show warning message + var warn = createWarnBar('Both ip address and password must be specified.'); + warn.prependTo($(this).parents('.ui-tabs-panel')); + password.css('border', 'solid #FF0000 1px'); + } + }); + + unlockNonNodesForm.append(unlockBtn); + + // Create 'SSH Key' fieldset + var sshKey = ''; + fs = $( '
                          ' ); + legend = $( 'xCAT Management Node Public Key' ); + fs.append( legend ); + unlockNonNodesForm.append( fs ); + + // Create key bar, hide on load + var keyBarId = 'unlockNonNodesKeyBar' + instance; + var keyBar = createStatusBar(keyBarId).hide(); + unlockNonNodesForm.append( keyBar ); + + // Generate tooltips + unlockNonNodesForm.find('div input[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + /** + * "Get Key" button + */ + var getBtn = createButton('Get Key'); + getBtn.css({ + 'width': '80px', + 'display': 'block' + }); + + getBtn.click(function() { + // Remove any warning messages + $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); + + // Get the SSH keys for a non-node + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'unlockshow;' + tgtNodes + ';key;', + msg : 'out=' + statBarId + ';keyBar=' + keyBarId +';cmd=unlock;tgt=' + tgtNodes + }, + + success : function(data) { + data = decodeRsp(data); + updateKeyBar(data); + } + }); + + // Show status bar + statBar.show(); + }); + + unlockNonNodesForm.append(getBtn); + + tab.add(newTabId, 'Unlock System', unlockNonNodesForm, true); + tab.select(newTabId); +} + + +/** + * Update key and status bar of a given tab + * + * @param data Data returned from HTTP request + */ +function updateKeyBar(data) { + // Get ajax response + var rsp = data.rsp; + var args = data.msg.split(';'); + var statBarId = args[0].replace('out=', ''); + var keyBarId = args[1].replace('keyBar=', ''); + var cmd = args[2].replace('cmd=', ''); + var tgts = args[3].replace('tgt=', '').split(','); + + $('#' + statBarId).find('img').hide(); + + // Extract the key portion and status portions from the response + var keyRespStart = rsp[0].indexOf(""); + var keyRespEnd = rsp[0].indexOf("");; + var keyOnly = rsp[0].substring( keyRespStart+9, keyRespEnd ); + var statLines = rsp[0].substring( 0, keyRespStart-1 ); + + if ( keyOnly.length > 0 ) { + // Expected response was returned, show it in the key bar. + var keyLines = keyOnly.split(/\n/); + for ( var i in keyLines ) { + $('#' + keyBarId).find( 'div' ).append( keyLines[i] ); + $('#' + keyBarId).find( 'div' ).append( '
                          ' ); + } + $('#' + keyBarId).show(); + + // Other lines from the response are shown in the Status bar. + if ( statLines.length > 0 ) { + prg = statLines.split(/\n/); + prg = writeRsp( prg, '' ); + $('#' + statBarId).find( 'div' ).append( prg ); + } + } else { + // Did not find the expected response, write the ajax response to status bar. + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + } + +} + + +/** + * Update the script and status bar of a given tab + * + * @param data Data returned from HTTP request + */ +function updateScriptBar(data) { + // Get ajax response + var rsp = data.rsp; + var args = data.msg.split(';'); + var statBarId = args[0].replace('out=', ''); + var scriptBarId = args[1].replace('scriptBar=', ''); + var cmd = args[2].replace('cmd=', ''); + var tgts = args[3].replace('tgt=', '').split(','); + + $('#' + statBarId).find('img').hide(); + + // Extract the key portion and status portions from the response + var scriptRespStart = rsp[0].indexOf(""); + var scriptRespEnd = rsp[0].indexOf("");; + var scriptOnly = rsp[0].substring( scriptRespStart+12, scriptRespEnd ); + var statLines = rsp[0].substring( 0, scriptRespStart-1 ); + + if ( scriptOnly.length > 0 ) { + // Expected response was returned, show it in the script bar along with the rest of the code. + var scriptLines = scriptOnly.split(/\n/); + for ( var i in scriptLines ) { + scriptLines[i] = scriptLines[i].replace(/^\s\s\s\s\s\s\s\s+/gm, '        '); + scriptLines[i] = scriptLines[i].replace(/^\s\s\s\s\s\s+/gm, '      '); + scriptLines[i] = scriptLines[i].replace(/^\s\s\s\s+/gm, '    '); + scriptLines[i] = scriptLines[i].replace(/^\s\s+/gm, '  '); + $('#' + scriptBarId).find( 'div' ).append( scriptLines[i] + '
                          ' ); + } + $('#' + scriptBarId).show(); + + // Other lines from the response are shown in the Status bar. + if ( statLines.length > 0 ) { + prg = statLines.split(/\n/); + prg = writeRsp( prg, '' ); + $('#' + statBarId).find( 'div' ).append( prg ); + } + } else { + // Did not find the expected response, write the ajax response to status bar. + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + } + +} + + +/** + * Load script page + * + * @param tgtNodes Targets to run script against + */ +function loadScriptPage(tgtNodes) { + // Get nodes tab + var tab = getNodesTab(); + + // Generate new tab ID + var inst = 0; + var newTabId = 'scriptTab' + inst; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + inst = inst + 1; + newTabId = 'scriptTab' + inst; + } + + // Create remote script form + var scriptForm = $('
                          '); + + // Create status bar + var barId = 'scriptStatusBar' + inst; + var statBar = createStatusBar(barId); + statBar.hide(); + var loader = createLoader('scriptLoader' + inst); + statBar.find('div').append(loader); + + // Create info bar + var infoBar = createInfoBar('Load a script to run against this node range.'); + scriptForm.append(infoBar, statBar); + + // Create VM fieldset + var vmFS = $('
                          '); + var vmLegend = $('Virtual Machine'); + vmFS.append(vmLegend); + scriptForm.append(vmFS); + + var vmAttr = $('
                          '); + vmFS.append($('
                          ')); + vmFS.append(vmAttr); + + // Create logs fieldset + var scriptFS = $('
                          '); + var scriptLegend = $('Script'); + scriptFS.append(scriptLegend); + scriptForm.append(scriptFS); + + var scriptAttr = $('
                          '); + scriptFS.append($('
                          ')); + scriptFS.append(scriptAttr); + + // Target node or group + var tgt = $('
                          '); + vmAttr.append(tgt); + + // Upload file + var upload = $('
                          '); + var label = $(''); + var file = $(''); + var subBtn = createButton('Load'); + upload.append(label, file, subBtn); + scriptAttr.append(upload); + + // Script + var script = $('
                          ').css({ + 'font-size': '10px', + 'height': '50px', + 'width': '200px', + 'background-color': '#000', + 'color': '#fff', + 'border': '0px', + 'display': 'block' + }); + + // Create links to save and cancel changes + var lnkStyle = { + 'color': '#58ACFA', + 'font-size': '10px', + 'display': 'inline-block', + 'padding': '5px', + 'float': 'right' + }; + + var saveLnk = $('Save').css(lnkStyle).hide(); + var cancelLnk = $('Cancel').css(lnkStyle).hide(); + var infoSpan = $('Click to edit').css(lnkStyle); + + // Save changes onclick + saveLnk.bind('click', function(){ + // Get node and comment + var node = $(this).parent().parent().find('img').attr('id').replace('Tip', ''); + var comments = $(this).parent().find('textarea').val(); + + // Save comment + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chdef', + tgt : '', + args : '-t;node;-o;' + node + ';usercomment=' + comments, + msg : 'out=nodesTab;tgt=' + node + }, + + success: function(data) { + data = decodeRsp(data); + showChdefOutput(data); + } + }); + + // Hide cancel and save links + $(this).hide(); + cancelLnk.hide(); + }); + + // Cancel changes onclick + cancelLnk.bind('click', function(){ + // Get original comment and put it back + var orignComments = $(this).parent().find('textarea').text(); + $(this).parent().find('textarea').val(orignComments); + + // Hide cancel and save links + $(this).hide(); + saveLnk.hide(); + infoSpan.show(); + }); + + // Show save link when comment is edited + txtArea.bind('click', function(){ + saveLnk.show(); + cancelLnk.show(); + infoSpan.hide(); + }); + + toolTip.append(txtArea); + toolTip.append(cancelLnk); + toolTip.append(saveLnk); + toolTip.append(infoSpan); + + return toolTip; +} + +/** + * Create a tool tip for node status + * + * @return Tool tip + */ +function createStatusToolTip() { + // Create tooltip container + var toolTip = $('
                          ').css({ + 'width': '150px', + 'font-weight': 'normal' + }); + + // Create info text + var info = $('

                          ').css({ + 'white-space': 'normal' + }); + info.append('Click here to refresh the node status. To configure the xCAT monitor, '); + + // Create link to turn on xCAT monitoring + var monitorLnk = $('click here').css({ + 'color': '#58ACFA', + 'font-size': '10px' + }); + + // Open dialog to configure xCAT monitor + monitorLnk.bind('click', function(){ + // Check if xCAT monitor is enabled + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'monls', + tgt : '', + args : 'xcatmon', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + openConfXcatMon(data); + } + }); + }); + + info.append(monitorLnk); + toolTip.append(info); + + return toolTip; +} + +/** + * Create a tool tip for power status + * + * @return Tool tip + */ +function createPowerToolTip() { + // Create tooltip container + var toolTip = $('
                          Click here to refresh the power status
                          ').css({ + 'width': '150px', + 'white-space': 'normal', + 'font-weight': 'normal' + }); + return toolTip; +} + +/** + * Create a tool tip for monitoring status + * + * @return Tool tip + */ +function createMonitorToolTip() { + // Create tooltip container + var toolTip = $('
                          Click here to refresh the monitoring status
                          ').css({ + 'width': '150px', + 'white-space': 'normal', + 'font-weight': 'normal' + }); + return toolTip; +} + +/** + * Open dialog to configure xCAT monitor + * + * @param data Data returned from HTTP request + */ +function openConfXcatMon(data) { + // Create info bar + var info = createInfoBar('Configure the xCAT monitor. Select to enable or disable the monitor below.'); + var dialog = $('
                          '); + dialog.append(info); + + // Create status area + var statusArea = $('
                          ').css('padding-top', '10px'); + var label = $(''); + statusArea.append(label); + + // Get xCAT monitor status + var status = data.rsp[0]; + var buttons; + // If xCAT monitor is disabled + if (status.indexOf('not-monitored') > -1) { + status = $('Disabled').css('padding', '0px 5px'); + statusArea.append(status); + + // Create enable and cancel buttons + buttons = { + "Enable": function(){ + // Enable xCAT monitor + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'monstart', + tgt : '', + args : 'xcatmon', + msg : '' + }, + + success : function(data){ + data = decodeRsp(data); + openDialog('info', data.rsp[0]); + } + }); + $(this).dialog("close"); + }, + "Cancel": function(){ + $(this).dialog("close"); + } + }; + } else { + status = $('Enabled').css('padding', '0px 5px'); + statusArea.append(status); + + // Create disable and cancel buttons + buttons = { + "Disable": function(){ + // Disable xCAT monitor + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'monstop', + tgt : '', + args : 'xcatmon', + msg : '' + }, + + success : function(data){ + data = decodeRsp(data); + openDialog('info', data.rsp[0]); + } + }); + $(this).dialog("close"); + }, + "Cancel": function(){ + $(this).dialog("close"); + } + }; + } + + dialog.append(statusArea); + + // Open dialog + dialog.dialog({ + modal: true, + width: 500, + buttons: buttons + }); +} + +/** + * Show chdef output + * + * @param data Data returned from HTTP request + */ +function showChdefOutput(data) { + // Get output + var out = data.rsp; + var args = data.msg.split(';'); + var tabID = args[0].replace('out=', ''); + var tgt = args[1].replace('tgt=', ''); + + // Find info bar on nodes tab, if any + var info = $('#' + tabID).find('.ui-state-highlight'); + if (!info.length) { + // Create info bar if one does not exist + info = createInfoBar(''); + $('#' + tabID).append(info); + } + + // Go through output and append to paragraph + var prg = $('

                          '); + for (var i in out) { + prg.append(tgt + ': ' + out[i] + '
                          '); + } + + info.append(prg); +} + +/** + * Set node attributes + * + * @param data Data returned from HTTP request + */ +function setNodeAttrs(data) { + // Clear hash table containing definable node attributes + nodeAttrs = new Array(); + + // Get definable attributes + var attrs = data.rsp[2].split(/\n/); + + // Go through each line + var attr, key, descr; + for (var i in attrs) { + attr = attrs[i]; + + // If the line is not empty + if (attr) { + // If the line has the attribute name + if (attr.indexOf(':') && attr.indexOf(' ')) { + // Get attribute name and description + key = jQuery.trim(attr.substring(0, attr.indexOf(':'))); + descr = jQuery.trim(attr.substring(attr.indexOf(':') + 1)); + + // Remove arrow brackets + descr = descr.replace(new RegExp('<|>', 'g'), ''); + + // Set hash table where key = attribute name and value = description + nodeAttrs[key] = descr; + } else { + // Remove arrow brackets + attr = attr.replace(new RegExp('<|>', 'g'), ''); + + // Append description to hash table + nodeAttrs[key] = nodeAttrs[key] + '\n' + attr; + } + } // End of if + } // End of for +} + + +/** + * Load the discover z/VM virtual systems page + * + * @param tgtNode Target node to set properties + */ +function discoverVMNodes(tgtNodes) { + var fs, legend, htmlLine; + + // Get nodes tab + var tab = getNodesTab(); + + // Generate new tab ID + var inst = 0; + var newTabId = 'discoverVMNodesTab' + inst; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + inst = inst + 1; + newTabId = 'discoverVMNodesTab' + inst; + } + + // Open new tab + // Create set properties form + var discoverVMNodesForm = $('
                          '); + + // Create info bar + var infoBar = createInfoBar( 'Initiate, stop or query the status of z/VM node discovery. ' + + 'To initiate discovery, specify discovery parameters and click on the Discover button. ' + + 'To stop an on-going discovery related to a z/VM host, specify the host node name and '+ + 'click on the Stop button. ' + + 'To obtain the status of discovery for a particular host, specify the host node name and '+ + 'click on the Stop button.' + ); + discoverVMNodesForm.append(infoBar); + + // Create the status bar and hide it. + var statBarId = 'statusBar_' + newTabId; + //var statBar = $( '
                          ' ); + //discoverVMNodesForm.append( statBar ); + statBar = createStatusBar( statBarId ); + statBar.hide(); + discoverVMNodesForm.append( statBar ); + + // Create Host fieldset + fs = $('
                          '); + legend = $('z/VM Host'); + fs.append(legend); + discoverVMNodesForm.append(fs); + + // Target node or group + htmlLine = $('
                          '); + discoverVMNodesForm.append( htmlLine ); + + // Create Discovery Parameters fieldset + fs = $('
                          '); + legend = $('Discovery Parameters'); + fs.append( legend ); + discoverVMNodesForm.append( fs ); + + // Create an input for each definable attribute + var div, label, input, descr, value; + + // Define DefineTo radio buttons + div = $('
                          ').css( 'display', 'inline-block' ).css( 'vertical-align', 'top' ); + div.append( '' ); + div.append( '
                        • xCAT and OpenStack
                        • ' ); + div.append( '
                        • xCAT only
                        • ' ); + div.append( '
                        • OpenStack only (only already discovered xCAT nodes)
                        • ' ); + discoverVMNodesForm.append( div ); + discoverVMNodesForm.append( '
                          ' ); + + // Userid filter + divUserid = newTabId + "_divUserid"; + div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ); + div.append( '' ); + div.append( '' ).css( 'margin-top', '5px' ); + discoverVMNodesForm.append( div ); + discoverVMNodesForm.append( '
                          ' ); + + // IP address filter + divIP = newTabId + "_divIP"; + div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ); + div.append( '' ); + div.append( '' ).css( 'margin-top', '5px' ); + discoverVMNodesForm.append( div ); + discoverVMNodesForm.append( '
                          ' ); + + // Group name input + divGroup = newTabId + '_divGroup'; + div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ); + div.append( '' ); + div.append( '' ).css( 'margin-top', '5px' ); + discoverVMNodesForm.append( div ); + discoverVMNodesForm.append( '
                          ' ); + + // Node Name Format input + divNodename = newTabId + '_divNodename'; + div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ); + div.append( '' ); + div.append( '' ).css( 'margin-top', '5px' ); + discoverVMNodesForm.append( div ); + discoverVMNodesForm.append( '
                          ' ); + discoverVMNodesForm.find('#' + divNodename).hide(); + + // OpenStack operand input + divOpenStackOps = newTabId + '_divOpenStackOps'; + div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ); + div.append( '' ); + div.append( '' ).css( 'margin-top', '5px' ); + div.append( '
                          ' ); + div.append( '' ); + div.append( '' ).css( 'margin-top', '5px' ); + discoverVMNodesForm.append( div ); + discoverVMNodesForm.append( '
                          ' ); + + // Define Verbose radio buttons + div = $('
                          ').css( 'display', 'inline-table' ).css( 'vertical-align', 'top' ).css( 'text-align', 'top' ); + div.append( '' ); + div.append( '
                        • Normal response, showing only important information
                        • ' ); + div.append( '
                        • Verbose response, normal response plus additional information (e.g. reason a system is ignored)
                        • ' ); + discoverVMNodesForm.append( div ); + discoverVMNodesForm.append( '
                          ' ); + + // Generate tooltips + discoverVMNodesForm.find('div input[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" + } + }); + + // Show appropriate input fields for defineto choices. + discoverVMNodesForm.change(function(){ + var defineTo = $(this).parent().find('input[name="defineTo"]:checked').val(); + if ( defineTo == 'both' ) { + discoverVMNodesForm.find('#' + divUserid).show(); + discoverVMNodesForm.find('#' + divIP).show(); + discoverVMNodesForm.find('#' + divGroup).show(); + discoverVMNodesForm.find('#' + divOpenStackOps).show(); + discoverVMNodesForm.find('#' + divNodename).hide(); + } else if ( defineTo == 'xcatonly' ) { + discoverVMNodesForm.find('#' + divUserid).show(); + discoverVMNodesForm.find('#' + divIP).show(); + discoverVMNodesForm.find('#' + divGroup).show(); + discoverVMNodesForm.find('#' + divOpenStackOps).hide(); + discoverVMNodesForm.find('#' + divNodename).show(); + } else if ( defineTo == 'openstackonly' ) { + discoverVMNodesForm.find('#' + divUserid).hide(); + discoverVMNodesForm.find('#' + divIP).hide(); + discoverVMNodesForm.find('#' + divGroup).hide(); + discoverVMNodesForm.find('#' + divOpenStackOps).show(); + discoverVMNodesForm.find('#' + divNodename).hide(); + } + }); + + + // Discover nodes button action + var discoverBtn = createButton('Discover'); + discoverBtn.click(function() { + var argList = ''; + var filter = ''; + + var hosts = $(this).parent().find('input[name=hosts]').val(); + if ( hosts != '' ) { + argList = 'zvmhost=' + hosts; + } + + var defineTo = $(this).parent().find('input[name="defineTo"]:checked').val(); + argList = argList + '||defineto=' + defineTo; + + var verbose = $(this).parent().find('input[name="verbose"]:checked').val(); + if ( verbose == 'yes' ) { + argList = argList + '||--verbose'; + } + + var useridFilter = $(this).parent().find('input[name=useridFilter]').val(); + if (( defineTo == 'both' || defineTo == 'xcatonly' ) && ( useridFilter != '' )) { + argList = argList + '||useridfilter=' + useridFilter; + } + + var ipFilter = $(this).parent().find('input[name=ipFilter]').val(); + if (( defineTo == 'both' || defineTo == 'xcatonly' ) && ( ipFilter != '' )) { + argList = argList + '||ipfilter=' + ipFilter; + } + + var group = $(this).parent().find('input[name=group]').val(); + if (( defineTo == 'both' || defineTo == 'xcatonly' ) && ( group != '' )) { + argList = argList + '||groups=' + group; + } + + var nodeNameFmt = $(this).parent().find('input[name=nodeNameFmt]').val(); + if ( defineTo == 'xcatonly' && nodeNameFmt != '' ) { + argList = argList + '||nodenameformat=' + nodeNameFmt; + } + + var openStackProj = $(this).parent().find('input[name=openStackProj]').val(); + var openStackUser = $(this).parent().find('input[name=openStackUser]').val(); + if ((( defineTo == 'both' ) || ( defineTo == 'openstackonly' )) && + (( openStackProj != '' ) || ( openStackUser != '' ))) { + if ( openStackProj != '' ) { + osArgs = '--project ' + openStackProj; + } else { + osArgs = ''; + } + if ( openStackUser != '' ) { + if ( osArgs != '' ) { + osArgs = osArgs + ' --user ' + openStackUser; + } else { + osArgs = '--user ' + openStackUser; + } + } + argList = argList + "||openstackoperands='" + osArgs + "'"; + } + + var out = $('

                          '); + out.append( 'Starting node discovery...' ); + out.append( '
                          ' ); + out.append( 'If node discovery is a short running task then its response will follow. If, however, the time it takes to complete discovery exceeds the http request timeout of a few minutes then the discovery response will not be returned to the browser. The status and list buttons can be used to obtained status on the discovery and see what systems have been discovered.' ); + $( '#' + statBarId ).find( 'div' ).append( out ); + statBar.show(); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodediscoverstart', + tgt : '', + args : argList, + att : '', + msg : statBarId + }, + success: function(data) { + data = decodeRsp(data); + updateDiscoverStatusBar( data, 1 ); + } + }); + + }); + discoverVMNodesForm.append(discoverBtn); + + // Status button + var statusBtn = createButton('Status'); + statusBtn.click( function() { + var hosts = $(this).parent().find('input[name=hosts]').val(); + var out = $('

                          '); + out.append( 'Querying status for discovery on ' + hosts + '...' ); + out.append( '
                          ' ); + $( '#' + statBarId ).find( 'div' ).append( out ); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodediscoverstatus', + tgt : '', + args : '--zvmhost||' + hosts, + att : '', + msg : statBarId + }, + success: function(data) { + data = decodeRsp(data); + updateDiscoverStatusBar( data, 1 ); + } + }); + + }); + discoverVMNodesForm.append( statusBtn ); + + // List button + var listBtn = createButton('List'); + listBtn.click( function() { + var hosts = $(this).parent().find('input[name=hosts]').val(); + var out = $('

                          '); + out.append( 'Listing systems discovered by the latest discovery on ' + hosts + '...' ); + out.append( '
                          ' ); + $( '#' + statBarId ).find( 'div' ).append( out ); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodediscoverls', + tgt : '', + args : '-t||zvm||--zvmhost||' + hosts, + att : '', + msg : statBarId + }, + success: function(data) { + data = decodeRsp(data); + updateDiscoverStatusBar( data, 1 ); + } + }); + }); + discoverVMNodesForm.append( listBtn ); + + // Stop button + var stopBtn = createButton('Stop'); + stopBtn.click(function() { + var hosts = $(this).parent().find('input[name=hosts]').val(); + var out = $('

                          '); + out.append( 'Stopping discovery on ' + hosts + '...' ); + out.append( '
                          ' ); + $( '#' + statBarId ).find( 'div' ).append( out ); + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodediscoverstop', + tgt : '', + args : '--zvmhost||' + hosts, + att : '', + msg : statBarId + }, + success: function(data) { + data = decodeRsp(data); + updateDiscoverStatusBar( data, 1 ); + } + }); + }); + discoverVMNodesForm.append( stopBtn ); + + // Append to discover tab + tab.add(newTabId, 'Discover', discoverVMNodesForm, true); + + // Select new tab + tab.select(newTabId); +} + + +/** + * Update discovery status bar + * + * @param data Data returned from HTTP request + */ +function updateDiscoverStatusBar( data, preformatted ) { + var statBarId = data.msg; + var rsp = data.rsp; + var statBar = $( '#' + statBarId ); + + // Go through response to make it readable in the status bar. + var out = $('

                          '); + for ( var i in rsp ) { + if ( preformatted == 1 ) { + out.append( '
                          ' + rsp[i] + '
                          ' ); + } else { + out.append( rsp[i] + '
                          ' ); + } + } + + // Write response to status bar and show the bar. + $( '#' + statBarId ).find( 'div' ).append( out ); + statBar.show(); +} + + +/** + * Load set node properties page + * + * @param tgtNode Target node to set properties + */ +function editNodeProps(tgtNode) { + // Get nodes tab + var tab = getNodesTab(); + + // Generate new tab ID + var inst = 0; + var newTabId = 'editPropsTab' + inst; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + inst = inst + 1; + newTabId = 'editPropsTab' + inst; + } + + // Open new tab + // Create set properties form + var editPropsForm = $('
                          '); + + // Create info bar + var infoBar = createInfoBar('Choose the properties you wish to change on the node. When you are finished, click Save.'); + editPropsForm.append(infoBar); + + // Create an input for each definable attribute + var div, label, input, descr, value; + // Set node attribute + origAttrs[tgtNode]['node'] = tgtNode; + for (var key in nodeAttrs) { + // If an attribute value exists + if (origAttrs[tgtNode][key]) { + // Set the value + value = origAttrs[tgtNode][key]; + } else { + value = ''; + } + + // Create label and input for attribute + div = $('
                          ').css('display', 'inline-table'); + label = $('').css('vertical-align', 'middle'); + input = $('').css('margin-top', '5px'); + + // Change border to blue onchange + input.bind('change', function(event) { + $(this).css('border-color', 'blue'); + }); + + div.append(label); + div.append(input); + editPropsForm.append(div); + } + + // Change style for last division + div.css({ + 'display': 'block', + 'margin': '0px 0px 10px 0px' + }); + + // Generate tooltips + editPropsForm.find('div input[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" + } + }); + + // Save changes + var saveBtn = createButton('Save'); + saveBtn.click(function() { + // Get all inputs + var inputs = $('#' + newTabId + ' input'); + + // Go through each input + var args = ''; + var attrName, attrVal; + inputs.each(function(){ + // If the border color is blue + if ($(this).css('border-left-color') == 'rgb(0, 0, 255)') { + // Change border color back to normal + $(this).css('border-color', ''); + + // Get attribute name and value + attrName = $(this).parent().find('label').text().replace(':', ''); + attrVal = $(this).val(); + + // Build argument string + if (args) { + // Handle subsequent arguments + args += ';' + attrName + '=' + attrVal; + } else { + // Handle the 1st argument + args += attrName + '=' + attrVal; + } + } + }); + + // Send command to change node attributes + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chdef', + tgt : '', + args : '-t;node;-o;' + tgtNode + ';' + args, + msg : 'out=' + newTabId + ';tgt=' + tgtNode + }, + + success: function(data) { + data = decodeRsp(data); + showChdefOutput(data); + } + }); + }); + editPropsForm.append(saveBtn); + + // Cancel changes + var cancelBtn = createButton('Cancel'); + cancelBtn.click(function() { + // Close the tab + tab.remove($(this).parent().parent().attr('id')); + }); + editPropsForm.append(cancelBtn); + + // Append to discover tab + tab.add(newTabId, 'Edit', editPropsForm, true); + + // Select new tab + tab.select(newTabId); +} + +/** + * Open set node attributes dialog + */ +function openSetAttrsDialog() { + // Open new tab + // Create set properties form + var setPropsForm = $('
                          '); + + // Create info bar + var infoBar = createInfoBar('Choose the properties you wish to change on the node. When you are finished, click Save.'); + setPropsForm.append(infoBar); + + // Create an input for each definable attribute + var div, label, input, descr, value; + for (var key in nodeAttrs) { + value = ''; + + // Create label and input for attribute + div = $('
                          ').css('display', 'inline'); + label = $('').css('vertical-align', 'middle'); + input = $('').css('margin-top', '5px'); + + // Change border to blue onchange + input.bind('change', function(event) { + $(this).css('border-color', 'blue'); + }); + + div.append(label); + div.append(input); + setPropsForm.append(div); + } + + // Change style for last division + div.css({ + 'display': 'block', + 'margin': '0px 0px 10px 0px' + }); + + // Generate tooltips + setPropsForm.find('div input[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()); + } + }); + + // Enable vertical scroll + setPropsForm.css('overflow', 'auto'); + + // Open form as a dialog + setPropsForm.dialog({ + title: 'Set attributes', + modal: true, + close: function(){ + $(this).remove(); + }, + height: 400, + width: 800, + buttons: { + "Save": function() { + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get all inputs + var inputs = $(this).find('input'); + + // Go through each input + var args = ''; + var tgtNode, attrName, attrVal; + inputs.each(function(){ + // If the border color is blue + if ($(this).css('border-left-color') == 'rgb(0, 0, 255)') { + // Change border color back to normal + $(this).css('border-color', ''); + + // Get attribute name and value + attrName = $(this).parent().find('label').text().replace(':', ''); + attrVal = $(this).val(); + + // Get node name + if (attrName == 'node') { + tgtNode = attrVal; + } else { + // Build argument string + if (args) { + // Handle subsequent arguments + args += ';' + attrName + '=' + attrVal; + } else { + // Handle the 1st argument + args += attrName + '=' + attrVal; + } + } + } + }); + + // Send command to change node attributes + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chdef', + tgt : '', + args : '-t;node;-o;' + tgtNode + ';' + args, + msg : 'node=' + tgtNode + }, + + /** + * Show results + * + * @param data + * Data returned from HTTP request + * @return Nothing + */ + success: function(data) { + // Get output + data = decodeRsp(data); + var out = data.rsp; + var node = data.msg.replace('node=', ''); + + // Go through output and append to paragraph + var msg = ''; + for (var i in out) { + if (!msg) { + msg = node + ': ' + out[i]; + } else { + msg += '
                          ' + node + ': ' + out[i]; + } + } + + openDialog('info', msg); + } + }); + + // Close dialog + $(this).dialog( "close" ); + }, + "Cancel": function(){ + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Turn on monitoring for a given node + * + * @param node Node to monitor on or off + * @param monitor Monitor state, on or off + */ +function monitorNode(node, monitor) { + // Show ganglia loader + var gangliaCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + gangliaCol.find('img').show(); + + if (monitor == 'on') { + // Append loader to warning bar + var warningBar = $('#nodesTab').find('.ui-state-error p'); + if (warningBar.length) { + warningBar.append(createLoader('')); + } + + if (node) { + // Check if ganglia RPMs are installed + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliacheck;' + node, + msg : node // Node range will be passed along in data.msg + }, + + /** + * Start ganglia on a given node range + * + * @param data Data returned from HTTP request + */ + success : function(data) { + // Get response + data = decodeRsp(data); + var out = data.rsp[0].split(/\n/); + + // Go through each line + var warn = false; + var warningMsg = ''; + for (var i in out) { + // If an RPM is not installed + if (out[i].indexOf('not installed') > -1) { + warn = true; + + if (warningMsg) { + warningMsg += '
                          ' + out[i]; + } else { + warningMsg = out[i]; + } + } + } + + // If there are warnings + if (warn) { + // Create warning bar + var warningBar = createWarnBar(warningMsg); + warningBar.css('margin-bottom', '10px'); + warningBar.prependTo($('#nodesTab')); + } else { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliastart;' + data.msg + ';-r', + msg : data.msg + }, + + success : function(data) { + data = decodeRsp(data); + // Remove any warnings + $('#nodesTab').find('.ui-state-error').remove(); + + // Update datatable + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliastatus;' + data.msg, + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadGangliaStatus(data); + } + }); + } + }); + } // End of if (warn) + } // End of function(data) + }); + } else { + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliastart', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + // Remove any warnings + $('#nodesTab').find('.ui-state-error').remove(); + } + }); + } // End of if (node) + } else { + var args; + if (node) { + args = 'gangliastop;' + node + ';-r'; + } else { + args = 'gangliastop'; + } + + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : args, + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + // Hide ganglia loader + var gangliaCol = $('#' + nodesTableId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + gangliaCol.find('img').hide(); + } + }); + } +} + +/** + * Install Ganglia on a given node + * + * @param node Node to install Ganglia on + */ +function installGanglia(node) { + var iframe = createIFrame('lib/cmd.php?cmd=webrun&tgt=&args=installganglia;' + node + '&msg=' + node + '&opts=flush'); + iframe.prependTo($('#nodesTab')); + + // Turn on Ganglia for node + monitorNode(node, 'on'); +} + +/** + * After nodes are loaded, load more information based on different hardware architectures + * + * @param group Group name + */ +function advancedLoad(group){ + var tempIndex = 0; + var tableHeaders = $('#' + nodesTableId).parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr:eq(0) th'); + var colNameHash = new Object(); + var colName = ''; + var archCol = 0, hcpCol = 0; + + // Find out the column name and their index + for (tempIndex = 0; tempIndex < tableHeaders.size(); tempIndex++){ + var header = tableHeaders.eq(tempIndex); + // Skip headers that are links, e.g. status, power, and monitor + if (header.find('a').size() > 0){ + continue; + } + + colName = header.text(); + + if (colName) { + colNameHash[colName] = tempIndex; + } + } + + // If there is no arch column, exit because you cannot distinguish hardware type + if (!colNameHash['arch']) { + return; + } + + if (!colNameHash['hcp']) { + return; + } + archCol = colNameHash['arch']; + hcpCol = colNameHash['hcp']; + + // Get hardware control point + var rows = $('#' + nodesTableId + ' tbody tr'); + var hcps = new Object(); + var rowsNum = rows.size(); + for (var j = 0; j < rowsNum; j++) { + var val = rows.eq(j).find('td').eq(hcpCol).html(); + var archval = rows.eq(j).find('td').eq(archCol).html(); + if (-1 == archval.indexOf('390')){ + continue; + } + hcps[val] = 1; + } + + if (Object.keys(hcps).length == 0) { + openDialog('warn', "No node found with hcp column filled in and 390 arch!"); + return; + } + // Get Nodes info bar + //var nodeInfoBar = getNodesTabInfoBar(); + //nodeInfoBar.append("\nEntering Advanced Load...\n") + + var args; + var shortzHcps = new Array(); + var zhcpHash = new Object(); + for (var h in hcps) { + // Get node without domain name + args = h.split('.'); + + if (!zhcpHash[args[0]]) { + + shortzHcps.push(args[0]); + zhcpHash[args[0]] = 1; + + // If there are no disk pools or network names cookie for this hcp + if (!$.cookie('xcat_' + args[0] + 'diskpools') || !$.cookie('xcat_' + args[0] + 'networks')) { + // Check if SMAPI is online + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsvm', + tgt : args[0], + args : '', + msg : 'group=' + group + ';hcp=' + args[0] + }, + + // Load hardware control point specific info + // Get disk pools and network names + success : function(data) { + data = decodeRsp(data); + loadHcpInfo(data); + } + }); + } + } + } // End of for + + // Save zHCPs as a cookie + setzHcpCookies(shortzHcps); + + // Retrieve z/VM hypervisors and their zHCPs + 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); + } + }); + } +} + +/** + * Jump to provision page on-click + * + * @param tgtNodes Target nodes + */ +function jump2Provision(tgtNodes){ + var nodeArray = tgtNodes.split(','); + var nodeName = ''; + var index = 0; + var archType = ''; + var errorMsg = ''; + var master = ''; + var tftpserver = ''; + var nfsserver = ''; + var diaDiv = $('
                          '); + + // Check the first node's arch type + for (index in nodeArray){ + nodeName = nodeArray[index]; + + // Skip if node does not have arch + if (!origAttrs[nodeName]['arch']){ + errorMsg = 'Nodes should have arch defined! '; + break; + } + + if (index == 0) { + archType = origAttrs[nodeName]['arch']; + } + + // Skip if nodes do not have same arch + if (archType != origAttrs[nodeName]['arch']){ + errorMsg = 'Nodes should belong to the same arch!
                          '; + break; + } + } + + // Skip if nodes do not have MAC address + for (index in nodeArray){ + if (!origAttrs[nodeName]['mac'] || !origAttrs[nodeName]['ip']){ + errorMsg += 'Nodes should have the IP and MAC addresses defined!
                          '; + break; + } + } + + if (archType.indexOf('390') != -1) { + errorMsg += 'Please use the provision page'; + } + + // Open dialog to show error message + if (errorMsg){ + diaDiv.append(createWarnBar(errorMsg)); + diaDiv.dialog({ + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + 'Close': function(){ + $(this).dialog('destroy'); + } + } + }); + + return; + } + + if (origAttrs[nodeName]['xcatmaster']) { + master = origAttrs[nodeName]['xcatmaster']; + } + + if (origAttrs[nodeName]['tftpserver']) { + tftpserver = origAttrs[nodeName]['tftpserver']; + } + + if (origAttrs[nodeName]['nfsserver']) { + nfsserver = origAttrs[nodeName]['nfsserver']; + } + + window.location.href = 'provision.php?nodes=' + tgtNodes + '&arch=' + archType + '&master=' + master + + '&tftpserver=' + tftpserver + '&nfsserver=' + nfsserver; +} diff --git a/xCAT-UI/js/nodes/nodeset.js b/xCAT-UI/js/nodes/nodeset.js index c1b2acfe8..87d84ba1e 100644 --- a/xCAT-UI/js/nodes/nodeset.js +++ b/xCAT-UI/js/nodes/nodeset.js @@ -1,296 +1,308 @@ -/** - * Load nodeset page - * - * @param tgtNodes Targets to run nodeset against - */ -function loadNodesetPage(tgtNodes) { - // Get OS images - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'tabdump', - tgt : '', - args : 'osimage', - msg : '' - }, - - success : setOSImageCookies - }); - - // Get nodes tab - var tab = getNodesTab(); - - // Generate new tab ID - var inst = 0; - var tabId = 'nodesetTab' + inst; - while ($('#' + tabId).length) { - // If one already exists, generate another one - inst = inst + 1; - tabId = 'nodesetTab' + inst; - } - - // Create nodeset form - var nodesetForm = $('
                          '); - - // Create status bar - var statBarId = 'nodesetStatusBar' + inst; - var statBar = createStatusBar(statBarId).hide(); - - // Create loader - var loader = createLoader('nodesetLoader'); - statBar.find('div').append(loader); - - // Create info bar - var infoBar = createInfoBar('Set the boot state for a node range'); - nodesetForm.append(statBar, infoBar); - - // Create VM fieldset - var vmFS = $('
                          '); - var vmLegend = $('Virtual Machine'); - vmFS.append(vmLegend); - nodesetForm.append(vmFS); - - var vmAttr = $('
                          '); - vmFS.append($('
                          ')); - vmFS.append(vmAttr); - - // Create options fieldset - var imageFS = $('
                          '); - var imageLegend = $('Image'); - imageFS.append(imageLegend); - nodesetForm.append(imageFS); - - var imageAttr = $('
                          '); - imageFS.append($('
                          ')); - imageFS.append(imageAttr); - - // Create target node or group - var tgt = $('
                          '); - vmAttr.append(tgt); - - // Create boot type drop down - var type = $('
                          '); - var typeLabel = $(''); - var typeSelect = $(''); - typeSelect.append('' - + '' - + '' - ); - type.append(typeLabel); - type.append(typeSelect); - imageAttr.append(type); - - // Create operating system image input - var os = $('
                          '); - var osLabel = $(''); - var osSelect = $(''); - osSelect.append($('')); - - var imageNames = $.cookie('xcat_imagenames').split(','); - if (imageNames) { - imageNames.sort(); - for (var i in imageNames) { - osSelect.append($('')); - } - } - os.append(osLabel); - os.append(osSelect); - imageAttr.append(os); - - // Generate tooltips - nodesetForm.find('div input[title],select').tooltip({ - position: "center right", - offset: [-2, 10], - effect: "fade", - opacity: 0.7, - predelay: 800, - events : { - def : "mouseover,mouseout", - input : "mouseover,mouseout", - widget : "focus mouseover,blur mouseout", - tooltip : "mouseover,mouseout" - } - }); - - /** - * Ok - */ - var okBtn = createButton('Ok'); - okBtn.css({ - 'width': '80px', - 'display': 'block' - }); - okBtn.bind('click', function(event) { - // Remove any warning messages - $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); - - // Check state, OS, arch, and profile - var ready = true; - var inputs = $('#' + tabId + ' input'); - for ( var i = 0; i < inputs.length; i++) { - if (!inputs.eq(i).val() && inputs.eq(i).attr('name') != 'diskPw') { - inputs.eq(i).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - inputs.eq(i).css('border', 'solid #BDBDBD 1px'); - } - } - - if (ready) { - // Get nodes - var tgts = $('#' + tabId + ' input[name=target]').val(); - // Get boot type - var type = $('#' + tabId + ' select[id=bootType]').val(); - // Get operating system image - var os = $('#' + tabId + ' select[name=os]').val(); - - // Disable all inputs, selects, and Ok button - inputs.attr('disabled', 'disabled'); - $('#' + tabId + ' select').attr('disabled', 'disabled'); - $(this).attr('disabled', 'true'); - - /** - * (1) Set the OS, arch, and profile - */ - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodeadd', - tgt : '', - args : tgts + ';noderes.netboot=' + type, - msg : 'cmd=nodeadd;inst=' + inst - }, - - success : updateNodesetStatus - }); - - // Show status bar - statBar.show(); - } else { - // Show warning message - var warn = createWarnBar('You are missing some values!'); - warn.prependTo($(this).parents('.ui-tabs-panel')); - } - }); - nodesetForm.append(okBtn); - - // Append to discover tab - tab.add(tabId, 'Nodeset', nodesetForm, true); - - // Select new tab - tab.select(tabId); -} - -/** - * Update nodeset status - * - * @param data Data returned from HTTP request - */ -function updateNodesetStatus(data) { - // Get ajax response - var rsp = data.rsp; - var args = data.msg.split(';'); - var cmd = args[0].replace('cmd=', ''); - - // Get nodeset instance - var inst = args[1].replace('inst=', ''); - // Get status bar ID - var statBarId = 'nodesetStatusBar' + inst; - // Get tab ID - var tabId = 'nodesetTab' + inst; - - // Get nodes - var tgts = $('#' + tabId + ' input[name=target]').val(); - // Get operating system image - var os = $('#' + tabId + ' select[name=os]').val(); - - /** - * (2) Update /etc/hosts - */ - if (cmd == 'nodeadd') { - if (rsp.length) { - $('#' + statBarId).find('img').hide(); - $('#' + statBarId).find('div').append('
                          (Error) Failed to create node definition
                          '); - } else { - // Create target nodes string - var tgtNodesStr = ''; - var nodes = tgts.split(','); - - // Loop through each node - for ( var i in nodes) { - // If it is the 1st and only node - if (i == 0 && i == nodes.length - 1) { - tgtNodesStr += nodes[i]; - } - // If it is the 1st node of many nodes - else if (i == 0 && i != nodes.length - 1) { - // Append a comma to the string - tgtNodesStr += nodes[i] + ', '; - } else { - // If it is the last node - if (i == nodes.length - 1) { - // Append nothing to the string - tgtNodesStr += nodes[i]; - } else { - // Append a comma to the string - tgtNodesStr += nodes[i] + ', '; - } - } - } - - $('#' + statBarId).find('div').append('
                          Node definition created for ' + tgtNodesStr + '
                          '); - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'makehosts', - tgt : '', - args : '', - msg : 'cmd=makehosts;inst=' + inst - }, - - success : updateNodesetStatus - }); - } - } - - /** - * (4) Update DNS - */ - else if (cmd == 'makehosts') { - // If no output, no errors occurred - if (rsp.length) { - $('#' + statBarId).find('div').append('
                          (Error) Failed to update /etc/hosts
                          '); - } else { - $('#' + statBarId).find('div').append('
                          /etc/hosts updated
                          '); - } - - // Go straight to prepare node for boot - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodeset', - tgt : tgts, - args : 'osimage=' + os, - msg : 'cmd=nodeset;inst=' + inst - }, - - success : updateNodesetStatus - }); - } - - /** - * (5) Boot node from network - */ - else if (cmd == 'nodeset') { - // Write ajax response to status bar - var prg = writeRsp(rsp, ''); - $('#' + statBarId).find('div').append(prg); - - // Hide loader - $('#' + statBarId).find('img').hide(); - } +/** + * Load nodeset page + * + * @param tgtNodes Targets to run nodeset against + */ +function loadNodesetPage(tgtNodes) { + // Get OS images + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'osimage', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setOSImageCookies(data); + } + }); + + // Get nodes tab + var tab = getNodesTab(); + + // Generate new tab ID + var inst = 0; + var tabId = 'nodesetTab' + inst; + while ($('#' + tabId).length) { + // If one already exists, generate another one + inst = inst + 1; + tabId = 'nodesetTab' + inst; + } + + // Create nodeset form + var nodesetForm = $('
                          '); + + // Create status bar + var statBarId = 'nodesetStatusBar' + inst; + var statBar = createStatusBar(statBarId).hide(); + + // Create loader + var loader = createLoader('nodesetLoader'); + statBar.find('div').append(loader); + + // Create info bar + var infoBar = createInfoBar('Set the boot state for a node range'); + nodesetForm.append(statBar, infoBar); + + // Create VM fieldset + var vmFS = $('
                          '); + var vmLegend = $('Virtual Machine'); + vmFS.append(vmLegend); + nodesetForm.append(vmFS); + + var vmAttr = $('
                          '); + vmFS.append($('
                          ')); + vmFS.append(vmAttr); + + // Create options fieldset + var imageFS = $('
                          '); + var imageLegend = $('Image'); + imageFS.append(imageLegend); + nodesetForm.append(imageFS); + + var imageAttr = $('
                          '); + imageFS.append($('
                          ')); + imageFS.append(imageAttr); + + // Create target node or group + var tgt = $('
                          '); + vmAttr.append(tgt); + + // Create boot type drop down + var type = $('
                          '); + var typeLabel = $(''); + var typeSelect = $(''); + typeSelect.append('' + + '' + + '' + ); + type.append(typeLabel); + type.append(typeSelect); + imageAttr.append(type); + + // Create operating system image input + var os = $('
                          '); + var osLabel = $(''); + var osSelect = $(''); + osSelect.append($('')); + + var imageNames = $.cookie('xcat_imagenames').split(','); + if (imageNames) { + imageNames.sort(); + for (var i in imageNames) { + osSelect.append($('')); + } + } + os.append(osLabel); + os.append(osSelect); + imageAttr.append(os); + + // Generate tooltips + nodesetForm.find('div input[title],select').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + /** + * Ok + */ + var okBtn = createButton('Ok'); + okBtn.css({ + 'width': '80px', + 'display': 'block' + }); + okBtn.bind('click', function(event) { + // Remove any warning messages + $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); + + // Check state, OS, arch, and profile + var ready = true; + var inputs = $('#' + tabId + ' input'); + for ( var i = 0; i < inputs.length; i++) { + if (!inputs.eq(i).val() && inputs.eq(i).attr('name') != 'diskPw') { + inputs.eq(i).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + inputs.eq(i).css('border', 'solid #BDBDBD 1px'); + } + } + + if (ready) { + // Get nodes + var tgts = $('#' + tabId + ' input[name=target]').val(); + // Get boot type + var type = $('#' + tabId + ' select[id=bootType]').val(); + // Get operating system image + var os = $('#' + tabId + ' select[name=os]').val(); + + // Disable all inputs, selects, and Ok button + inputs.attr('disabled', 'disabled'); + $('#' + tabId + ' select').attr('disabled', 'disabled'); + $(this).attr('disabled', 'true'); + + /** + * (1) Set the OS, arch, and profile + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeadd', + tgt : '', + args : tgts + ';noderes.netboot=' + type, + msg : 'cmd=nodeadd;inst=' + inst + }, + + success : function(data) { + data = decodeRsp(data); + updateNodesetStatus(data); + } + }); + + // Show status bar + statBar.show(); + } else { + // Show warning message + var warn = createWarnBar('You are missing some values!'); + warn.prependTo($(this).parents('.ui-tabs-panel')); + } + }); + nodesetForm.append(okBtn); + + // Append to discover tab + tab.add(tabId, 'Nodeset', nodesetForm, true); + + // Select new tab + tab.select(tabId); +} + +/** + * Update nodeset status + * + * @param data Data returned from HTTP request + */ +function updateNodesetStatus(data) { + // Get ajax response + var rsp = data.rsp; + var args = data.msg.split(';'); + var cmd = args[0].replace('cmd=', ''); + + // Get nodeset instance + var inst = args[1].replace('inst=', ''); + // Get status bar ID + var statBarId = 'nodesetStatusBar' + inst; + // Get tab ID + var tabId = 'nodesetTab' + inst; + + // Get nodes + var tgts = $('#' + tabId + ' input[name=target]').val(); + // Get operating system image + var os = $('#' + tabId + ' select[name=os]').val(); + + /** + * (2) Update /etc/hosts + */ + if (cmd == 'nodeadd') { + if (rsp.length) { + $('#' + statBarId).find('img').hide(); + $('#' + statBarId).find('div').append('
                          (Error) Failed to create node definition
                          '); + } else { + // Create target nodes string + var tgtNodesStr = ''; + var nodes = tgts.split(','); + + // Loop through each node + for ( var i in nodes) { + // If it is the 1st and only node + if (i == 0 && i == nodes.length - 1) { + tgtNodesStr += nodes[i]; + } + // If it is the 1st node of many nodes + else if (i == 0 && i != nodes.length - 1) { + // Append a comma to the string + tgtNodesStr += nodes[i] + ', '; + } else { + // If it is the last node + if (i == nodes.length - 1) { + // Append nothing to the string + tgtNodesStr += nodes[i]; + } else { + // Append a comma to the string + tgtNodesStr += nodes[i] + ', '; + } + } + } + + $('#' + statBarId).find('div').append('
                          Node definition created for ' + tgtNodesStr + '
                          '); + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'makehosts', + tgt : '', + args : '', + msg : 'cmd=makehosts;inst=' + inst + }, + + success : function(data) { + data = decodeRsp(data); + updateNodesetStatus(data); + } + }); + } + } + + /** + * (4) Update DNS + */ + else if (cmd == 'makehosts') { + // If no output, no errors occurred + if (rsp.length) { + $('#' + statBarId).find('div').append('
                          (Error) Failed to update /etc/hosts
                          '); + } else { + $('#' + statBarId).find('div').append('
                          /etc/hosts updated
                          '); + } + + // Go straight to prepare node for boot + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodeset', + tgt : tgts, + args : 'osimage=' + os, + msg : 'cmd=nodeset;inst=' + inst + }, + + success : function(data) { + data = decodeRsp(data); + updateNodesetStatus(data); + } + }); + } + + /** + * (5) Boot node from network + */ + else if (cmd == 'nodeset') { + // Write ajax response to status bar + var prg = writeRsp(rsp, ''); + $('#' + statBarId).find('div').append(prg); + + // Hide loader + $('#' + statBarId).find('img').hide(); + } } \ No newline at end of file diff --git a/xCAT-UI/js/nodes/physical.js b/xCAT-UI/js/nodes/physical.js index e8df2d4c8..24b010c8c 100644 --- a/xCAT-UI/js/nodes/physical.js +++ b/xCAT-UI/js/nodes/physical.js @@ -1,933 +1,935 @@ -var bpaList; -var fspList; -var lparList; -var bladeList; -var rackList; -var unknownList; -var graphicalNodeList; -var selectNode; - -/** - * Get all nodes useful attributes from remote server - * - * @param dataTypeIndex The index in the array which contains attributes we need. - * @param attrNullNode The target node list for this attribute - */ -function initGraphicalData() { - $('#graphTab').append(createLoader()); - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'graph', - msg : '' - }, - success : function(data) { - if (!data.rsp[0]) { - return; - } - extractGraphicalData(data.rsp[0]); - getNodesAndDraw(); - } - }); -} - -/** - * Extract all nodes userful data into a hash, which will be used for creating graphical - * - * @param data The response from xCAT command 'nodels all nodetype.nodetype ppc.parent ...' - * @return nodes list for next time query - */ -function extractGraphicalData(data) { - var nodes = data.split(';'); - var attrs; - var nodeName; - - // Extract useful info into tempList - for (var i = 0; i < nodes.length; i++) { - attrs = nodes[i].split(':'); - nodeName = attrs[0]; - if (undefined == graphicalNodeList[nodeName]) { - graphicalNodeList[nodeName] = new Object(); - } - - graphicalNodeList[nodeName]['type'] = attrs[1].toLowerCase(); - switch (attrs[1].toLowerCase()) { - case 'cec': - case 'frame': - case 'lpar': - case 'lpar,osi': - case 'osi,lpar': - graphicalNodeList[nodeName]['parent'] = attrs[2]; - graphicalNodeList[nodeName]['mtm'] = attrs[3]; - graphicalNodeList[nodeName]['status'] = attrs[4]; - break; - case 'blade': - graphicalNodeList[nodeName]['mpa'] = attrs[2]; - graphicalNodeList[nodeName]['unit'] = attrs[3]; - graphicalNodeList[nodeName]['status'] = attrs[4]; - break; - case 'systemx': - graphicalNodeList[nodeName]['rack'] = attrs[2]; - graphicalNodeList[nodeName]['unit'] = attrs[3]; - graphicalNodeList[nodeName]['mtm'] = attrs[4]; - graphicalNodeList[nodeName]['status'] = attrs[5]; - break; - default: - break; - } - } -} - -function createPhysicalLayout(nodeList) { - var flag = false; - - // When the graphical layout is shown, do not need to redraw - if (1 < $('#graphTab').children().length) { - return; - } - - // Save the new selected nodes - if (graphicalNodeList) { - for (var i in graphicalNodeList) { - flag = true; - break; - } - } - - bpaList = new Object(); - fspList = new Object(); - lparList = new Object(); - bladeList = new Object(); - selectNode = new Object(); - rackList = new Object(); - unknownList = new Array(); - - // There is no graphical data, get the info now - if (!flag) { - graphicalNodeList = new Object(); - initGraphicalData(); - } else { - getNodesAndDraw(); - } -} - -function getNodesAndDraw() { - var groupName = $.cookie('xcat_selectgrouponnodes'); - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'nodels', - tgt : groupName, - args : '', - msg : '' - }, - success : function(data) { - for (var temp in data.rsp) { - var nodeName = data.rsp[temp][0]; - if ('' == nodeName) { - continue; - } - fillList(nodeName); - } - $('#graphTab').empty(); - createGraphical(); - } - }); -} - -function fillList(nodeName, defaultnodetype) { - var parentName = ''; - var mtm = ''; - var status = ''; - var nodeType = ''; - var mpa = ''; - var unit = ''; - var rack = ''; - if (!graphicalNodeList[nodeName]) { - parentName = ''; - mtm = ''; - status = ''; - nodeType = defaultnodetype; - } else { - status = graphicalNodeList[nodeName]['status']; - nodeType = graphicalNodeList[nodeName]['type']; - switch (nodeType) { - case 'frame': - case 'lpar,osi': - case 'lpar': - case 'osi': - case 'cec': - parentName = graphicalNodeList[nodeName]['parent']; - mtm = graphicalNodeList[nodeName]['mtm']; - break; - case 'blade': - mpa = graphicalNodeList[nodeName]['mpa']; - unit = graphicalNodeList[nodeName]['unit']; - break; - case 'systemx': - rack = graphicalNodeList[nodeName]['rack']; - unit = graphicalNodeList[nodeName]['unit']; - break; - default: - break; - } - - } - - if ('' == status) { - status = 'unknown'; - } - - switch (nodeType) { - case 'frame': - if (undefined == bpaList[nodeName]) { - bpaList[nodeName] = new Array(); - } - - break; - case 'lpar,osi': - case 'lpar': - case 'osi': - if ('' == parentName) { - break; - } - - if (undefined == fspList[parentName]) { - fillList(parentName, 'cec'); - } - - fspList[parentName]['children'].push(nodeName); - lparList[nodeName] = status; - - break; - case 'cec': - if (undefined != fspList[nodeName]) { - break; - } - - fspList[nodeName] = new Object(); - fspList[nodeName]['children'] = new Array(); - fspList[nodeName]['mtm'] = mtm; - - if ('' == parentName) { - break; - } - - if (undefined == bpaList[parentName]) { - fillList(parentName, 'frame'); - } - - bpaList[parentName].push(nodeName); - break; - case 'blade': - if (undefined == bladeList[mpa]) { - bladeList[mpa] = new Array(); - } - bladeList[mpa].push(nodeName + ',' + unit); - - break; - case 'systemx': - if (!rack) { - rack = '_notsupply_'; - } - - if (undefined == rackList[rack]) { - rackList[rack] = new Array(); - } - - rackList[rack].push(nodeName + ',' + unit); - - break; - default: - unknownList.push(nodeName); - break; - } -} - -function createGraphical() { - var tabArea = $('#graphTab'); - var selectNodeDiv = $('
                          '); - var temp = 0; - for (var i in selectNode) { - temp++; - break; - } - - // There is no selected LPAR, show the info bar - if (temp == 0) { - tabArea.append(createInfoBar('Hover over a CEC and select the LPARs to do operations against.')); - } else { - // Show selected LPARs - updateSelectNodeDiv(); - } - - // Add buttons - tabArea.append(createActionMenu()); - tabArea.append(selectNodeDiv); - createSystempGraphical(bpaList, fspList, tabArea); - createBladeGraphical(bladeList, tabArea); - createSystemxGraphical(rackList, tabArea); - addUnknownGraphical(unknownList, tabArea); -} - -/** - * Create the physical/graphical layout for System p machines - * - * @param bpa All BPA and their related FSPs - * @param fsp All FSP and their related LPARs - * @param area The element to append graphical layout - */ -function createSystempGraphical(bpa, fsp, area) { - var usedFsp = new Object(); - var graphTable = $('
                          '); - var elementNum = 0; - var row = null; - var showFlag = false; - - // There is a node in the BPA list, so show add the title and show all frames - for (var bpaName in bpa) { - showFlag = true; - $('#graphTab').append('system p
                          '); - $('#graphTab').append(graphTable); - break; - } - - for (var bpaName in bpa) { - if (0 == elementNum % 3) { - row = $(''); - graphTable.append(row); - } - - elementNum++; - - var td = $(''); - var frameDiv = $('
                          '); - frameDiv.append('
                          '); - - // For P7-IH, all the CECs are insert into the frame from bottom to up, - // so we have to show the CECs same as the physical layout - var tempBlankDiv = $('
                          '); - var tempHeight = 0; - for (var fspIndex in bpa[bpaName]) { - var fspName = bpa[bpaName][fspIndex]; - usedFsp[fspName] = 1; - - // This is the P7-IH, we should add the blank at the top - if ((0 == fspIndex) && ('9125-F2C' == fsp[fspName]['mtm'])) { - frameDiv.append(tempBlankDiv); - } - - frameDiv.append(createFspDiv(fspName, fsp[fspName]['mtm'], fsp)); - frameDiv.append(createFspTip(fspName, fsp[fspName]['mtm'], fsp)); - - tempHeight += calculateBlank(fsp[fspName]['mtm']); - } - - // tempHeight is the total height for all CECs, so we should minus BPA div - // height and CEC div heights - tempHeight = 428 - tempHeight; - tempBlankDiv.css('height', tempHeight); - td.append(frameDiv); - row.append(td); - } - - // Find the single FSP and sort descend by units - var singleFsp = new Array(); - for (var fspName in fsp) { - if (usedFsp[fspName]) { - continue; - } - - singleFsp.push([ fspName, fsp[fspName]['mtm'] ]); - } - - // If there is no frame, we should check if there is single CEC and show - // the title and add node area - if (!showFlag) { - for (var fspIndex in singleFsp) { - $('#graphTab').append('system p
                          '); - $('#graphTab').append(graphTable); - break; - } - } - - singleFsp.sort(function(a, b) { - var unitNumA = 4; - var unitNumB = 4; - if (hardwareInfo[a[1]]) { - unitNumA = hardwareInfo[a[1]][1]; - } - - if (hardwareInfo[b[1]]) { - unitNumB = hardwareInfo[b[1]][1]; - } - - return (unitNumB - unitNumA); - }); - - elementNum = 0; - for (var fspIndex in singleFsp) { - var fspName = singleFsp[fspIndex][0]; - if (0 == elementNum % 3) { - row = $(''); - graphTable.append(row); - } - elementNum++; - - var td = $(''); - td.append(createFspDiv(fspName, fsp[fspName]['mtm'], fsp)); - td.append(createFspTip(fspName, fsp[fspName]['mtm'], fsp)); - row.append(td); - } - - $('.tooltip input[type = checkbox]').bind('click', function() { - var lparName = $(this).attr('name'); - if ('' == lparName) { - return; - } - if (true == $(this).attr('checked')) { - changeNode(lparName, 'select'); - } else { - changeNode(lparName, 'unselect'); - } - - updateSelectNodeDiv(); - }); - - $('.fspDiv2, .fspDiv4, .fspDiv42').tooltip({ - position : "center right", - relative : true, - offset : [ 10, -40 ], - effect : "fade", - opacity : 0.9 - }); - - $('.tooltip a').bind('click', function() { - var lparName = $(this).html(); - $('#nodesDatatable #' + lparName).trigger('click'); - }); - - $('.fspDiv2, .fspDiv4, .fspDiv42').bind('click', function() { - var fspName = $(this).attr('value'); - var selectCount = 0; - for (var lparIndex in fspList[fspName]['children']) { - var lparName = fspList[fspName]['children'][lparIndex]; - if (selectNode[lparName]) { - selectCount++; - } - } - - // All LPARs are selected, so unselect nodes - if (selectCount == fspList[fspName]['children'].length) { - for (var lparIndex in fspList[fspName]['children']) { - var lparName = fspList[fspName]['children'][lparIndex]; - changeNode(lparName, 'unselect'); - } - } - - // No selected LPARs on the cec, so add all LPARs into selectNode hash - else { - for (var lparIndex in fspList[fspName]['children']) { - var lparName = fspList[fspName]['children'][lparIndex]; - changeNode(lparName, 'select'); - } - } - - updateSelectNodeDiv(); - }); - - $('.fspCheckbox').bind('click', function() { - var itemName = $(this).attr('name'); - name = itemName.substr(6); - - if ($(this).attr('checked')) { - selectNode[name] = 1; - } else { - delete selectNode[name]; - } - - updateSelectNodeDiv(); - }); -} - -/** - * Create the physical/graphical layout for blades - * - * @param blades The blade list in global - * @param area The element to append the graphical layout - */ -function createBladeGraphical(blades, area) { - var graphTable = $('
                          '); - var mpa = ''; - var bladeName = ''; - var index = 0; - var mpaNumber = 0; - var row; - var showFlag = false; - - // Only show the title and nodes when there are blade in the blade list - for (mpa in blades) { - showFlag = true; - break; - } - - if (showFlag) { - $('#graphTab').append('Blade
                          '); - $('#graphTab').append(graphTable); - } - // If there is no blade node, return directly - else { - return; - } - - for (mpa in blades) { - var tempArray = new Array(14); - var bladeInfo = new Array(); - var unit = 0; - if (0 == mpaNumber % 3) { - row = $(''); - graphTable.append(row); - } - - mpaNumber++; - - var td = $(''); - var chasisDiv = $('
                          '); - - // Fill the array with blade information, to create the empty slot - for (index in blades[mpa]) { - bladeInfo = blades[mpa][index].split(','); - unit = parseInt(bladeInfo[1]); - tempArray[unit - 1] = bladeInfo[0]; - - } - - // Draw the blades and empty slot in chasis - for (index = 0; index < 14; index++) { - if (tempArray[index]) { - bladeName = tempArray[index]; - chasisDiv.append('
                          '); - } else { - chasisDiv.append('
                          '); - } - } - - td.append(chasisDiv); - row.append(td); - } - -} - -/** - * Create the physical/graphical layout for System x machines - * - * @param xnodes The system x node list in global - * @param area The element to append graphical layout - */ -function createSystemxGraphical(xnodes, area) { - var graphTable = $('
                          '); - var xnodename = ''; - var index = 0; - var rack = ''; - var row; - var xNodeCount = 0; - var showflag = false; - - // Only the title and System x node when there are x nodes in the list - for (rack in rackList) { - showflag = true; - break; - } - - if (showflag) { - $('#graphTab').append('system x
                          '); - $('#graphTab').append(graphTable); - } - // There is nothing to show, return directly - else { - return; - } - - for (rack in rackList) { - for (index in rackList[rack]) { - var xNodeName = rackList[rack][index]; - if (0 == xNodeCount % 3) { - row = $(''); - graphTable.append(row); - } - xNodeCount++; - var td = $(''); - var xNodeDiv = '
                          '; - td.append(xNodeDiv); - row.append(td); - } - } -} - -function addUnknownGraphical(unknownNodes, tab) { - // Do not continue if no nodes were found - if (unknownNodes.length < 1) - return; - - var list = ""; - tab.append('
                          '); - for (var index in unknownNodes) { - list += unknownNodes[index] + ', '; - - } - - // Delete last comma - list = list.substr(0, list.length - 2); - tab.append(list); -} - -/** - * Update the LPARs background in CEC, LPAR area and selectNode - */ -function updateSelectNodeDiv() { - var temp = 0; - $('#selectNodeDiv').empty(); - - // Add buttons - if (selectNode.length) { - $('#selectNodeDiv').append('Nodes: '); - for (var lparName in selectNode) { - $('#selectNodeDiv').append(lparName + ' '); - temp++; - if (temp > 6) { - $('#selectNodeDiv').append('...'); - break; - } - } - } -} - -/** - * Create the action menu - */ -function createActionMenu() { - // Create action bar - var actionBar = $('
                          ').css("width", "400px"); - - // Power on - var powerOnLnk = $('Power on'); - powerOnLnk.click(function() { - var tgtNodes = getSelectNodes(); - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'rpower', - tgt : tgtNodes, - args : 'on', - msg : '' - } - }); - }); - - // Power off - var powerOffLnk = $('Power off'); - powerOffLnk.click(function() { - var tgtNodes = getSelectNodes(); - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'rpower', - tgt : tgtNodes, - args : 'off', - msg : '' - } - }); - }); - - // Delete - var deleteLnk = $('Delete'); - deleteLnk.click(function() { - var tgtNodes = getSelectNodes(); - if (tgtNodes) { - loadDeletePage(tgtNodes); - } - }); - - // Unlock - var unlockLnk = $('Unlock'); - unlockLnk.click(function() { - var tgtNodes = getSelectNodes(); - if (tgtNodes) { - loadUnlockPage(tgtNodes); - } - }); - - // Run script - var scriptLnk = $('Run script'); - scriptLnk.click(function() { - var tgtNodes = getSelectNodes(); - if (tgtNodes) { - loadScriptPage(tgtNodes); - } - }); - - // Update - var updateLnk = $('Update'); - updateLnk.click(function() { - var tgtNodes = getSelectNodes(); - if (tgtNodes) { - loadUpdatenodePage(tgtNodes); - } - }); - - // Set boot state - var setBootStateLnk = $('Set boot state'); - setBootStateLnk.click(function() { - var tgtNodes = getSelectNodes(); - if (tgtNodes) { - loadNodesetPage(tgtNodes); - } - }); - - // Boot to network - var boot2NetworkLnk = $('Boot to network'); - boot2NetworkLnk.click(function() { - var tgtNodes = getSelectNodes(); - if (tgtNodes) { - loadNetbootPage(tgtNodes); - } - }); - - // Remote console - var rconLnk = $('Open console'); - rconLnk.bind('click', function(event) { - var tgtNodes = getSelectNodes(); - if (tgtNodes) { - loadRconsPage(tgtNodes); - } - }); - - // Edit properties - var editProps = $('Edit properties'); - editProps.bind('click', function(event) { - for (var node in selectNode) { - loadEditPropsPage(node); - } - }); - - // Actions - var actionsLnk = 'Actions'; - var actsMenu = createMenu([ deleteLnk, powerOnLnk, powerOffLnk, scriptLnk ]); - - // Configurations - var configLnk = 'Configuration'; - var configMenu = createMenu([ unlockLnk, updateLnk, editProps ]); - - // Provision - var provLnk = 'Provision'; - var provMenu = createMenu([ boot2NetworkLnk, setBootStateLnk, rconLnk ]); - - // Create an action menu - var actionsMenu = createMenu([ [ actionsLnk, actsMenu ], - [ configLnk, configMenu ], [ provLnk, provMenu ] ]); - actionsMenu.superfish(); - actionsMenu.css('display', 'inline-block'); - actionBar.append(actionsMenu); - actionBar.css('margin-top', '10px'); - - // Set correct theme for action menu - actionsMenu.find('li').hover(function() { - setMenu2Theme($(this)); - }, function() { - setMenu2Normal($(this)); - }); - - return actionBar; -} - -/** - * Create the physical/graphical layout - */ -function createFspDiv(fspName, mtm, fsp) { - // Create FSP title - var lparStatusRow = ''; - var temp = ''; - - for (var lparIndex in fsp[fspName]['children']) { - // Show 8 lpars on one cec at most. - if (lparIndex >= 8) { - break; - } - - var lparName = fsp[fspName]['children'][lparIndex]; - var color = statusMap(lparList[lparName]); - lparStatusRow += ''; - } - - // Select the backgroud - var divClass = ''; - if ('' == mtm) { - temp = '8231-E2B'; - } else { - temp = mtm; - } - - if (!hardwareInfo[temp]){ - hardwareInfo[temp] = ['unkown', 2]; - } - - if (hardwareInfo[temp][1]) { - divClass += 'fspDiv' + hardwareInfo[temp][1]; - } else { - divClass += 'fspDiv4'; - } - - // Create return value - var retHtml = ''; - retHtml += '
                          '; - retHtml += '
                          ' + lparStatusRow - + '
                          '; - return retHtml; -} - -/** - * Create the physical/graphical FSP tooltip which is used to select the LPAR - */ -function createFspTip(fspName, mtm, fsp) { - var tip = $('
                          '); - var tempTable = $('
                          '); - var temp = ''; - if ('' == mtm) { - temp = 'unkown'; - } else { - temp = mtm; - } - - if (hardwareInfo[temp]) { - tip.append('

                          ' + fspName + '(' + hardwareInfo[temp][0] + ')


                          '); - } else { - tip.append('

                          ' + fspName + '


                          '); - } - - for (var lparIndex in fsp[fspName]['children']) { - var lparName = fsp[fspName]['children'][lparIndex]; - var color = statusMap(lparList[lparName]); - var row = ''; - row += '' + lparName + ''; - row += '' + lparList[lparName] + ''; - tempTable.append(row); - } - - tip.append(tempTable); - return tip; -} -/** - * Map the LPAR status into a color - * - * @param status LPAR status in nodelist table - * @return Corresponding color name - */ -function statusMap(status) { - var color = 'gainsboro'; - - switch (status) { - case 'alive': - case 'ready': - case 'pbs': - case 'sshd': - case 'booting': - case 'booted': - case 'ping': - color = 'green'; - break; - case 'noping': - case 'unreachable': - color = 'red'; - break; - default: - color = 'grey'; - break; - } - - return color; -} - -/** - * Select all LPAR checkboxes - */ -function selectAllLpars(checkbox) { - var temp = checkbox.attr('checked'); - $('#selectNodeTable input[type = checkbox]').attr('checked', temp); -} - -/** - * Export all LPAR names from selectNode - * - * @return lpars' string - */ -function getSelectNodes() { - var ret = ''; - for (var lparName in selectNode) { - ret += lparName + ','; - } - - return ret.substring(0, ret.length - 1); -} - -/** - * When the node is selected or unselected, update the area on CEC, update - * the global list, and update the tooltip table - */ -function changeNode(lparName, status) { - var imgUrl = ''; - var checkFlag = true; - if ('select' == status) { - selectNode[lparName] = 1; - imgUrl = 'url(images/nodes/s-' + statusMap(lparList[lparName]) - + '.gif)'; - checkFlag = true; - } else { - delete selectNode[lparName]; - imgUrl = 'url(images/nodes/' + statusMap(lparList[lparName]) + '.gif)'; - checkFlag = false; - } - $('#' + lparName + 'status').css('background-image', imgUrl); - $('.tooltip input[name="' + lparName + '"]').attr('checked', checkFlag); -} - -/** - * The P7-IH's CECs are insert from bottom to up, so we had to calculate the blank height - * - * @return Height for the CEC - */ -function calculateBlank(mtm) { - if ('' == mtm) { - return 24; - } - - if (!hardwareInfo[mtm]) { - return 24; - } - - switch (hardwareInfo[mtm][1]) { - case 1: - return 13; - break; - case 2: - return 24; - break; - case 4: - return 47; - break; - default: - return 0; - break; - } +var bpaList; +var fspList; +var lparList; +var bladeList; +var rackList; +var unknownList; +var graphicalNodeList; +var selectNode; + +/** + * Get all nodes useful attributes from remote server + * + * @param dataTypeIndex The index in the array which contains attributes we need. + * @param attrNullNode The target node list for this attribute + */ +function initGraphicalData() { + $('#graphTab').append(createLoader()); + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'graph', + msg : '' + }, + success : function(data) { + data = decodeRsp(data); + if (!data.rsp[0]) { + return; + } + extractGraphicalData(data.rsp[0]); + getNodesAndDraw(); + } + }); +} + +/** + * Extract all nodes userful data into a hash, which will be used for creating graphical + * + * @param data The response from xCAT command 'nodels all nodetype.nodetype ppc.parent ...' + * @return nodes list for next time query + */ +function extractGraphicalData(data) { + var nodes = data.split(';'); + var attrs; + var nodeName; + + // Extract useful info into tempList + for (var i = 0; i < nodes.length; i++) { + attrs = nodes[i].split(':'); + nodeName = attrs[0]; + if (undefined == graphicalNodeList[nodeName]) { + graphicalNodeList[nodeName] = new Object(); + } + + graphicalNodeList[nodeName]['type'] = attrs[1].toLowerCase(); + switch (attrs[1].toLowerCase()) { + case 'cec': + case 'frame': + case 'lpar': + case 'lpar,osi': + case 'osi,lpar': + graphicalNodeList[nodeName]['parent'] = attrs[2]; + graphicalNodeList[nodeName]['mtm'] = attrs[3]; + graphicalNodeList[nodeName]['status'] = attrs[4]; + break; + case 'blade': + graphicalNodeList[nodeName]['mpa'] = attrs[2]; + graphicalNodeList[nodeName]['unit'] = attrs[3]; + graphicalNodeList[nodeName]['status'] = attrs[4]; + break; + case 'systemx': + graphicalNodeList[nodeName]['rack'] = attrs[2]; + graphicalNodeList[nodeName]['unit'] = attrs[3]; + graphicalNodeList[nodeName]['mtm'] = attrs[4]; + graphicalNodeList[nodeName]['status'] = attrs[5]; + break; + default: + break; + } + } +} + +function createPhysicalLayout(nodeList) { + var flag = false; + + // When the graphical layout is shown, do not need to redraw + if (1 < $('#graphTab').children().length) { + return; + } + + // Save the new selected nodes + if (graphicalNodeList) { + for (var i in graphicalNodeList) { + flag = true; + break; + } + } + + bpaList = new Object(); + fspList = new Object(); + lparList = new Object(); + bladeList = new Object(); + selectNode = new Object(); + rackList = new Object(); + unknownList = new Array(); + + // There is no graphical data, get the info now + if (!flag) { + graphicalNodeList = new Object(); + initGraphicalData(); + } else { + getNodesAndDraw(); + } +} + +function getNodesAndDraw() { + var groupName = $.cookie('xcat_selectgrouponnodes'); + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'nodels', + tgt : groupName, + args : '', + msg : '' + }, + success : function(data) { + data = decodeRsp(data); + for (var temp in data.rsp) { + var nodeName = data.rsp[temp][0]; + if ('' == nodeName) { + continue; + } + fillList(nodeName); + } + $('#graphTab').empty(); + createGraphical(); + } + }); +} + +function fillList(nodeName, defaultnodetype) { + var parentName = ''; + var mtm = ''; + var status = ''; + var nodeType = ''; + var mpa = ''; + var unit = ''; + var rack = ''; + if (!graphicalNodeList[nodeName]) { + parentName = ''; + mtm = ''; + status = ''; + nodeType = defaultnodetype; + } else { + status = graphicalNodeList[nodeName]['status']; + nodeType = graphicalNodeList[nodeName]['type']; + switch (nodeType) { + case 'frame': + case 'lpar,osi': + case 'lpar': + case 'osi': + case 'cec': + parentName = graphicalNodeList[nodeName]['parent']; + mtm = graphicalNodeList[nodeName]['mtm']; + break; + case 'blade': + mpa = graphicalNodeList[nodeName]['mpa']; + unit = graphicalNodeList[nodeName]['unit']; + break; + case 'systemx': + rack = graphicalNodeList[nodeName]['rack']; + unit = graphicalNodeList[nodeName]['unit']; + break; + default: + break; + } + + } + + if ('' == status) { + status = 'unknown'; + } + + switch (nodeType) { + case 'frame': + if (undefined == bpaList[nodeName]) { + bpaList[nodeName] = new Array(); + } + + break; + case 'lpar,osi': + case 'lpar': + case 'osi': + if ('' == parentName) { + break; + } + + if (undefined == fspList[parentName]) { + fillList(parentName, 'cec'); + } + + fspList[parentName]['children'].push(nodeName); + lparList[nodeName] = status; + + break; + case 'cec': + if (undefined != fspList[nodeName]) { + break; + } + + fspList[nodeName] = new Object(); + fspList[nodeName]['children'] = new Array(); + fspList[nodeName]['mtm'] = mtm; + + if ('' == parentName) { + break; + } + + if (undefined == bpaList[parentName]) { + fillList(parentName, 'frame'); + } + + bpaList[parentName].push(nodeName); + break; + case 'blade': + if (undefined == bladeList[mpa]) { + bladeList[mpa] = new Array(); + } + bladeList[mpa].push(nodeName + ',' + unit); + + break; + case 'systemx': + if (!rack) { + rack = '_notsupply_'; + } + + if (undefined == rackList[rack]) { + rackList[rack] = new Array(); + } + + rackList[rack].push(nodeName + ',' + unit); + + break; + default: + unknownList.push(nodeName); + break; + } +} + +function createGraphical() { + var tabArea = $('#graphTab'); + var selectNodeDiv = $('
                          '); + var temp = 0; + for (var i in selectNode) { + temp++; + break; + } + + // There is no selected LPAR, show the info bar + if (temp == 0) { + tabArea.append(createInfoBar('Hover over a CEC and select the LPARs to do operations against.')); + } else { + // Show selected LPARs + updateSelectNodeDiv(); + } + + // Add buttons + tabArea.append(createActionMenu()); + tabArea.append(selectNodeDiv); + createSystempGraphical(bpaList, fspList, tabArea); + createBladeGraphical(bladeList, tabArea); + createSystemxGraphical(rackList, tabArea); + addUnknownGraphical(unknownList, tabArea); +} + +/** + * Create the physical/graphical layout for System p machines + * + * @param bpa All BPA and their related FSPs + * @param fsp All FSP and their related LPARs + * @param area The element to append graphical layout + */ +function createSystempGraphical(bpa, fsp, area) { + var usedFsp = new Object(); + var graphTable = $('
                          '); + var elementNum = 0; + var row = null; + var showFlag = false; + + // There is a node in the BPA list, so show add the title and show all frames + for (var bpaName in bpa) { + showFlag = true; + $('#graphTab').append('system p
                          '); + $('#graphTab').append(graphTable); + break; + } + + for (var bpaName in bpa) { + if (0 == elementNum % 3) { + row = $(''); + graphTable.append(row); + } + + elementNum++; + + var td = $(''); + var frameDiv = $('
                          '); + frameDiv.append('
                          '); + + // For P7-IH, all the CECs are insert into the frame from bottom to up, + // so we have to show the CECs same as the physical layout + var tempBlankDiv = $('
                          '); + var tempHeight = 0; + for (var fspIndex in bpa[bpaName]) { + var fspName = bpa[bpaName][fspIndex]; + usedFsp[fspName] = 1; + + // This is the P7-IH, we should add the blank at the top + if ((0 == fspIndex) && ('9125-F2C' == fsp[fspName]['mtm'])) { + frameDiv.append(tempBlankDiv); + } + + frameDiv.append(createFspDiv(fspName, fsp[fspName]['mtm'], fsp)); + frameDiv.append(createFspTip(fspName, fsp[fspName]['mtm'], fsp)); + + tempHeight += calculateBlank(fsp[fspName]['mtm']); + } + + // tempHeight is the total height for all CECs, so we should minus BPA div + // height and CEC div heights + tempHeight = 428 - tempHeight; + tempBlankDiv.css('height', tempHeight); + td.append(frameDiv); + row.append(td); + } + + // Find the single FSP and sort descend by units + var singleFsp = new Array(); + for (var fspName in fsp) { + if (usedFsp[fspName]) { + continue; + } + + singleFsp.push([ fspName, fsp[fspName]['mtm'] ]); + } + + // If there is no frame, we should check if there is single CEC and show + // the title and add node area + if (!showFlag) { + for (var fspIndex in singleFsp) { + $('#graphTab').append('system p
                          '); + $('#graphTab').append(graphTable); + break; + } + } + + singleFsp.sort(function(a, b) { + var unitNumA = 4; + var unitNumB = 4; + if (hardwareInfo[a[1]]) { + unitNumA = hardwareInfo[a[1]][1]; + } + + if (hardwareInfo[b[1]]) { + unitNumB = hardwareInfo[b[1]][1]; + } + + return (unitNumB - unitNumA); + }); + + elementNum = 0; + for (var fspIndex in singleFsp) { + var fspName = singleFsp[fspIndex][0]; + if (0 == elementNum % 3) { + row = $(''); + graphTable.append(row); + } + elementNum++; + + var td = $(''); + td.append(createFspDiv(fspName, fsp[fspName]['mtm'], fsp)); + td.append(createFspTip(fspName, fsp[fspName]['mtm'], fsp)); + row.append(td); + } + + $('.tooltip input[type = checkbox]').bind('click', function() { + var lparName = $(this).attr('name'); + if ('' == lparName) { + return; + } + if (true == $(this).attr('checked')) { + changeNode(lparName, 'select'); + } else { + changeNode(lparName, 'unselect'); + } + + updateSelectNodeDiv(); + }); + + $('.fspDiv2, .fspDiv4, .fspDiv42').tooltip({ + position : "center right", + relative : true, + offset : [ 10, -40 ], + effect : "fade", + opacity : 0.9 + }); + + $('.tooltip a').bind('click', function() { + var lparName = $(this).html(); + $('#nodesDatatable #' + lparName).trigger('click'); + }); + + $('.fspDiv2, .fspDiv4, .fspDiv42').bind('click', function() { + var fspName = $(this).attr('value'); + var selectCount = 0; + for (var lparIndex in fspList[fspName]['children']) { + var lparName = fspList[fspName]['children'][lparIndex]; + if (selectNode[lparName]) { + selectCount++; + } + } + + // All LPARs are selected, so unselect nodes + if (selectCount == fspList[fspName]['children'].length) { + for (var lparIndex in fspList[fspName]['children']) { + var lparName = fspList[fspName]['children'][lparIndex]; + changeNode(lparName, 'unselect'); + } + } + + // No selected LPARs on the cec, so add all LPARs into selectNode hash + else { + for (var lparIndex in fspList[fspName]['children']) { + var lparName = fspList[fspName]['children'][lparIndex]; + changeNode(lparName, 'select'); + } + } + + updateSelectNodeDiv(); + }); + + $('.fspCheckbox').bind('click', function() { + var itemName = $(this).attr('name'); + name = itemName.substr(6); + + if ($(this).attr('checked')) { + selectNode[name] = 1; + } else { + delete selectNode[name]; + } + + updateSelectNodeDiv(); + }); +} + +/** + * Create the physical/graphical layout for blades + * + * @param blades The blade list in global + * @param area The element to append the graphical layout + */ +function createBladeGraphical(blades, area) { + var graphTable = $('
                          '); + var mpa = ''; + var bladeName = ''; + var index = 0; + var mpaNumber = 0; + var row; + var showFlag = false; + + // Only show the title and nodes when there are blade in the blade list + for (mpa in blades) { + showFlag = true; + break; + } + + if (showFlag) { + $('#graphTab').append('Blade
                          '); + $('#graphTab').append(graphTable); + } + // If there is no blade node, return directly + else { + return; + } + + for (mpa in blades) { + var tempArray = new Array(14); + var bladeInfo = new Array(); + var unit = 0; + if (0 == mpaNumber % 3) { + row = $(''); + graphTable.append(row); + } + + mpaNumber++; + + var td = $(''); + var chasisDiv = $('
                          '); + + // Fill the array with blade information, to create the empty slot + for (index in blades[mpa]) { + bladeInfo = blades[mpa][index].split(','); + unit = parseInt(bladeInfo[1]); + tempArray[unit - 1] = bladeInfo[0]; + + } + + // Draw the blades and empty slot in chasis + for (index = 0; index < 14; index++) { + if (tempArray[index]) { + bladeName = tempArray[index]; + chasisDiv.append('
                          '); + } else { + chasisDiv.append('
                          '); + } + } + + td.append(chasisDiv); + row.append(td); + } + +} + +/** + * Create the physical/graphical layout for System x machines + * + * @param xnodes The system x node list in global + * @param area The element to append graphical layout + */ +function createSystemxGraphical(xnodes, area) { + var graphTable = $('
                          '); + var xnodename = ''; + var index = 0; + var rack = ''; + var row; + var xNodeCount = 0; + var showflag = false; + + // Only the title and System x node when there are x nodes in the list + for (rack in rackList) { + showflag = true; + break; + } + + if (showflag) { + $('#graphTab').append('system x
                          '); + $('#graphTab').append(graphTable); + } + // There is nothing to show, return directly + else { + return; + } + + for (rack in rackList) { + for (index in rackList[rack]) { + var xNodeName = rackList[rack][index]; + if (0 == xNodeCount % 3) { + row = $(''); + graphTable.append(row); + } + xNodeCount++; + var td = $(''); + var xNodeDiv = '
                          '; + td.append(xNodeDiv); + row.append(td); + } + } +} + +function addUnknownGraphical(unknownNodes, tab) { + // Do not continue if no nodes were found + if (unknownNodes.length < 1) + return; + + var list = ""; + tab.append('
                          '); + for (var index in unknownNodes) { + list += unknownNodes[index] + ', '; + + } + + // Delete last comma + list = list.substr(0, list.length - 2); + tab.append(list); +} + +/** + * Update the LPARs background in CEC, LPAR area and selectNode + */ +function updateSelectNodeDiv() { + var temp = 0; + $('#selectNodeDiv').empty(); + + // Add buttons + if (selectNode.length) { + $('#selectNodeDiv').append('Nodes: '); + for (var lparName in selectNode) { + $('#selectNodeDiv').append(lparName + ' '); + temp++; + if (temp > 6) { + $('#selectNodeDiv').append('...'); + break; + } + } + } +} + +/** + * Create the action menu + */ +function createActionMenu() { + // Create action bar + var actionBar = $('
                          ').css("width", "400px"); + + // Power on + var powerOnLnk = $('Power on'); + powerOnLnk.click(function() { + var tgtNodes = getSelectNodes(); + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rpower', + tgt : tgtNodes, + args : 'on', + msg : '' + } + }); + }); + + // Power off + var powerOffLnk = $('Power off'); + powerOffLnk.click(function() { + var tgtNodes = getSelectNodes(); + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rpower', + tgt : tgtNodes, + args : 'off', + msg : '' + } + }); + }); + + // Delete + var deleteLnk = $('Delete'); + deleteLnk.click(function() { + var tgtNodes = getSelectNodes(); + if (tgtNodes) { + loadDeletePage(tgtNodes); + } + }); + + // Unlock + var unlockLnk = $('Unlock'); + unlockLnk.click(function() { + var tgtNodes = getSelectNodes(); + if (tgtNodes) { + loadUnlockPage(tgtNodes); + } + }); + + // Run script + var scriptLnk = $('Run script'); + scriptLnk.click(function() { + var tgtNodes = getSelectNodes(); + if (tgtNodes) { + loadScriptPage(tgtNodes); + } + }); + + // Update + var updateLnk = $('Update'); + updateLnk.click(function() { + var tgtNodes = getSelectNodes(); + if (tgtNodes) { + loadUpdatenodePage(tgtNodes); + } + }); + + // Set boot state + var setBootStateLnk = $('Set boot state'); + setBootStateLnk.click(function() { + var tgtNodes = getSelectNodes(); + if (tgtNodes) { + loadNodesetPage(tgtNodes); + } + }); + + // Boot to network + var boot2NetworkLnk = $('Boot to network'); + boot2NetworkLnk.click(function() { + var tgtNodes = getSelectNodes(); + if (tgtNodes) { + loadNetbootPage(tgtNodes); + } + }); + + // Remote console + var rconLnk = $('Open console'); + rconLnk.bind('click', function(event) { + var tgtNodes = getSelectNodes(); + if (tgtNodes) { + loadRconsPage(tgtNodes); + } + }); + + // Edit properties + var editProps = $('Edit properties'); + editProps.bind('click', function(event) { + for (var node in selectNode) { + loadEditPropsPage(node); + } + }); + + // Actions + var actionsLnk = 'Actions'; + var actsMenu = createMenu([ deleteLnk, powerOnLnk, powerOffLnk, scriptLnk ]); + + // Configurations + var configLnk = 'Configuration'; + var configMenu = createMenu([ unlockLnk, updateLnk, editProps ]); + + // Provision + var provLnk = 'Provision'; + var provMenu = createMenu([ boot2NetworkLnk, setBootStateLnk, rconLnk ]); + + // Create an action menu + var actionsMenu = createMenu([ [ actionsLnk, actsMenu ], + [ configLnk, configMenu ], [ provLnk, provMenu ] ]); + actionsMenu.superfish(); + actionsMenu.css('display', 'inline-block'); + actionBar.append(actionsMenu); + actionBar.css('margin-top', '10px'); + + // Set correct theme for action menu + actionsMenu.find('li').hover(function() { + setMenu2Theme($(this)); + }, function() { + setMenu2Normal($(this)); + }); + + return actionBar; +} + +/** + * Create the physical/graphical layout + */ +function createFspDiv(fspName, mtm, fsp) { + // Create FSP title + var lparStatusRow = ''; + var temp = ''; + + for (var lparIndex in fsp[fspName]['children']) { + // Show 8 lpars on one cec at most. + if (lparIndex >= 8) { + break; + } + + var lparName = fsp[fspName]['children'][lparIndex]; + var color = statusMap(lparList[lparName]); + lparStatusRow += ''; + } + + // Select the backgroud + var divClass = ''; + if ('' == mtm) { + temp = '8231-E2B'; + } else { + temp = mtm; + } + + if (!hardwareInfo[temp]){ + hardwareInfo[temp] = ['unkown', 2]; + } + + if (hardwareInfo[temp][1]) { + divClass += 'fspDiv' + hardwareInfo[temp][1]; + } else { + divClass += 'fspDiv4'; + } + + // Create return value + var retHtml = ''; + retHtml += '
                          '; + retHtml += '
                          ' + lparStatusRow + + '
                          '; + return retHtml; +} + +/** + * Create the physical/graphical FSP tooltip which is used to select the LPAR + */ +function createFspTip(fspName, mtm, fsp) { + var tip = $('
                          '); + var tempTable = $('
                          '); + var temp = ''; + if ('' == mtm) { + temp = 'unkown'; + } else { + temp = mtm; + } + + if (hardwareInfo[temp]) { + tip.append('

                          ' + fspName + '(' + hardwareInfo[temp][0] + ')


                          '); + } else { + tip.append('

                          ' + fspName + '


                          '); + } + + for (var lparIndex in fsp[fspName]['children']) { + var lparName = fsp[fspName]['children'][lparIndex]; + var color = statusMap(lparList[lparName]); + var row = ''; + row += '' + lparName + ''; + row += '' + lparList[lparName] + ''; + tempTable.append(row); + } + + tip.append(tempTable); + return tip; +} +/** + * Map the LPAR status into a color + * + * @param status LPAR status in nodelist table + * @return Corresponding color name + */ +function statusMap(status) { + var color = 'gainsboro'; + + switch (status) { + case 'alive': + case 'ready': + case 'pbs': + case 'sshd': + case 'booting': + case 'booted': + case 'ping': + color = 'green'; + break; + case 'noping': + case 'unreachable': + color = 'red'; + break; + default: + color = 'grey'; + break; + } + + return color; +} + +/** + * Select all LPAR checkboxes + */ +function selectAllLpars(checkbox) { + var temp = checkbox.attr('checked'); + $('#selectNodeTable input[type = checkbox]').attr('checked', temp); +} + +/** + * Export all LPAR names from selectNode + * + * @return lpars' string + */ +function getSelectNodes() { + var ret = ''; + for (var lparName in selectNode) { + ret += lparName + ','; + } + + return ret.substring(0, ret.length - 1); +} + +/** + * When the node is selected or unselected, update the area on CEC, update + * the global list, and update the tooltip table + */ +function changeNode(lparName, status) { + var imgUrl = ''; + var checkFlag = true; + if ('select' == status) { + selectNode[lparName] = 1; + imgUrl = 'url(images/nodes/s-' + statusMap(lparList[lparName]) + + '.gif)'; + checkFlag = true; + } else { + delete selectNode[lparName]; + imgUrl = 'url(images/nodes/' + statusMap(lparList[lparName]) + '.gif)'; + checkFlag = false; + } + $('#' + lparName + 'status').css('background-image', imgUrl); + $('.tooltip input[name="' + lparName + '"]').attr('checked', checkFlag); +} + +/** + * The P7-IH's CECs are insert from bottom to up, so we had to calculate the blank height + * + * @return Height for the CEC + */ +function calculateBlank(mtm) { + if ('' == mtm) { + return 24; + } + + if (!hardwareInfo[mtm]) { + return 24; + } + + switch (hardwareInfo[mtm][1]) { + case 1: + return 13; + break; + case 2: + return 24; + break; + case 4: + return 47; + break; + default: + return 0; + break; + } } \ No newline at end of file diff --git a/xCAT-UI/js/nodes/rnetboot.js b/xCAT-UI/js/nodes/rnetboot.js index c745c8922..7f03e069b 100644 --- a/xCAT-UI/js/nodes/rnetboot.js +++ b/xCAT-UI/js/nodes/rnetboot.js @@ -1,220 +1,223 @@ -/** - * Load netboot page - * - * @param tgtNodes Targets to run rnetboot against - */ -function loadNetbootPage(tgtNodes) { - // Get node OS - var osHash = new Object(); - var nodes = tgtNodes.split(','); - for (var i in nodes) { - var os = getNodeAttr(nodes[i], 'os'); - var osBase = os.match(/[a-zA-Z]+/); - if (osBase) { - nodes[osBase] = 1; - } - } - - // Get nodes tab - var tab = getNodesTab(); - - // Generate new tab ID - var inst = 0; - var newTabId = 'netbootTab' + inst; - while ($('#' + newTabId).length) { - // If one already exists, generate another one - inst = inst + 1; - newTabId = 'netbootTab' + inst; - } - - // Create netboot form - var netbootForm = $('
                          '); - - // Create status bar - var statBarId = 'netbootStatusBar' + inst; - var statusBar = createStatusBar(statBarId).hide(); - - // Create loader - var loader = createLoader('netbootLoader'); - statusBar.find('div').append(loader); - - // Create info bar - var infoBar = createInfoBar('Cause the range of nodes to boot to network'); - netbootForm.append(statusBar, infoBar); - - // Create VM fieldset - var vmFS = $('
                          '); - var vmLegend = $('Virtual Machine'); - vmFS.append(vmLegend); - netbootForm.append(vmFS); - - var vmAttr = $('
                          '); - vmFS.append($('
                          ')); - vmFS.append(vmAttr); - - // Create options fieldset - var optionsFS = $('
                          '); - var optionsLegend = $('Options'); - optionsFS.append(optionsLegend); - netbootForm.append(optionsFS); - - var optionsAttr = $('
                          '); - optionsFS.append($('
                          ')); - optionsFS.append(optionsAttr); - - // Create target node or group input - var target = $('
                          '); - vmAttr.append(target); - - // Create options - var optsLabel = $(''); - var optsList = $('
                            '); - optionsAttr.append(optsList); - - // Create boot order checkbox - var opt = $('
                          • '); - var bootOrderChkBox = $(''); - opt.append(bootOrderChkBox); - opt.append('Set the boot device order'); - optsList.append(opt); - // Create boot order input - var bootOrder = $('
                          • '); - bootOrder.hide(); - optsList.append(bootOrder); - - // Create force reboot checkbox - optsList.append('
                          • Force reboot
                          • '); - // Create force shutdown checkbox - optsList.append('
                          • Force immediate shutdown of the partition
                          • '); - if (osHash['AIX']) { - // Create iscsi dump checkbox - optsList.append('
                          • Do a iscsi dump on AIX
                          • '); - } - - // Show boot order when checkbox is checked - bootOrderChkBox.bind('click', function(event) { - if ($(this).is(':checked')) { - bootOrder.show(); - } else { - bootOrder.hide(); - } - }); - - // Determine plugin - var tmp = tgtNodes.split(','); - for ( var i = 0; i < tmp.length; i++) { - var mgt = getNodeAttr(tmp[i], 'mgt'); - // If it is zvm - if (mgt == 'zvm') { - // Add IPL input - optsList.append('
                            '); - break; - } - } - - // Generate tooltips - netbootForm.find('div input[title]').tooltip({ - position: "center right", - offset: [-2, 10], - effect: "fade", - opacity: 0.7, - predelay: 800, - events : { - def : "mouseover,mouseout", - input : "mouseover,mouseout", - widget : "focus mouseover,blur mouseout", - tooltip : "mouseover,mouseout" - } - }); - - /** - * Ok - */ - var okBtn = createButton('Ok'); - okBtn.css({ - 'width': '80px', - 'display': 'block' - }); - okBtn.bind('click', function(event) { - // Remove any warning messages - $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); - - // Check inputs - var ready = true; - var inputs = $("#" + newTabId + " input[type='text']:visible"); - for ( var i = 0; i < inputs.length; i++) { - if (!inputs.eq(i).val()) { - inputs.eq(i).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - inputs.eq(i).css('border', 'solid #BDBDBD 1px'); - } - } - - // Generate arguments - var chkBoxes = $("#" + newTabId + " input[type='checkbox']:checked"); - var optStr = ''; - var opt; - for ( var i = 0; i < chkBoxes.length; i++) { - opt = chkBoxes.eq(i).attr('name'); - optStr += '-' + opt; - - // If it is the boot order - if (opt == 's') { - // Get the boot order - optStr += ';' + $('#' + newTabId + ' input[name=bootOrder]').val(); - } - - // Append ; to end of string - if (i < (chkBoxes.length - 1)) { - optStr += ';'; - } - } - - // If no inputs are empty - if (ready) { - // Get nodes - var tgts = $('#' + newTabId + ' input[name=target]').val(); - - // Get IPL address - var ipl = $('#' + newTabId + ' input[name=ipl]'); - if (ipl) { - optStr += 'ipl=' + ipl.val(); - } - - // Disable all inputs and Ok button - $('#' + newTabId + ' input').attr('disabled', 'disabled'); - $(this).attr('disabled', 'true'); - - /** - * (1) Boot to network - */ - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'rnetboot', - tgt : tgts, - args : optStr, - msg : 'out=' + statBarId + ';cmd=rnetboot;tgt=' + tgts - }, - - success : updateStatusBar - }); - - // Show status bar - statusBar.show(); - } else { - // Show warning message - var warn = createWarnBar('Please provide a value for each missing field.'); - warn.prependTo($(this).parents('.ui-tabs-panel')); - } - }); - netbootForm.append(okBtn); - - // Append to discover tab - tab.add(newTabId, 'Boot', netbootForm, true); - - // Select new tab - tab.select(newTabId); +/** + * Load netboot page + * + * @param tgtNodes Targets to run rnetboot against + */ +function loadNetbootPage(tgtNodes) { + // Get node OS + var osHash = new Object(); + var nodes = tgtNodes.split(','); + for (var i in nodes) { + var os = getNodeAttr(nodes[i], 'os'); + var osBase = os.match(/[a-zA-Z]+/); + if (osBase) { + nodes[osBase] = 1; + } + } + + // Get nodes tab + var tab = getNodesTab(); + + // Generate new tab ID + var inst = 0; + var newTabId = 'netbootTab' + inst; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + inst = inst + 1; + newTabId = 'netbootTab' + inst; + } + + // Create netboot form + var netbootForm = $('
                            '); + + // Create status bar + var statBarId = 'netbootStatusBar' + inst; + var statusBar = createStatusBar(statBarId).hide(); + + // Create loader + var loader = createLoader('netbootLoader'); + statusBar.find('div').append(loader); + + // Create info bar + var infoBar = createInfoBar('Cause the range of nodes to boot to network'); + netbootForm.append(statusBar, infoBar); + + // Create VM fieldset + var vmFS = $('
                            '); + var vmLegend = $('Virtual Machine'); + vmFS.append(vmLegend); + netbootForm.append(vmFS); + + var vmAttr = $('
                            '); + vmFS.append($('
                            ')); + vmFS.append(vmAttr); + + // Create options fieldset + var optionsFS = $('
                            '); + var optionsLegend = $('Options'); + optionsFS.append(optionsLegend); + netbootForm.append(optionsFS); + + var optionsAttr = $('
                            '); + optionsFS.append($('
                            ')); + optionsFS.append(optionsAttr); + + // Create target node or group input + var target = $('
                            '); + vmAttr.append(target); + + // Create options + var optsLabel = $(''); + var optsList = $('
                              '); + optionsAttr.append(optsList); + + // Create boot order checkbox + var opt = $('
                            • '); + var bootOrderChkBox = $(''); + opt.append(bootOrderChkBox); + opt.append('Set the boot device order'); + optsList.append(opt); + // Create boot order input + var bootOrder = $('
                            • '); + bootOrder.hide(); + optsList.append(bootOrder); + + // Create force reboot checkbox + optsList.append('
                            • Force reboot
                            • '); + // Create force shutdown checkbox + optsList.append('
                            • Force immediate shutdown of the partition
                            • '); + if (osHash['AIX']) { + // Create iscsi dump checkbox + optsList.append('
                            • Do a iscsi dump on AIX
                            • '); + } + + // Show boot order when checkbox is checked + bootOrderChkBox.bind('click', function(event) { + if ($(this).is(':checked')) { + bootOrder.show(); + } else { + bootOrder.hide(); + } + }); + + // Determine plugin + var tmp = tgtNodes.split(','); + for ( var i = 0; i < tmp.length; i++) { + var mgt = getNodeAttr(tmp[i], 'mgt'); + // If it is zvm + if (mgt == 'zvm') { + // Add IPL input + optsList.append('
                              '); + break; + } + } + + // Generate tooltips + netbootForm.find('div input[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + /** + * Ok + */ + var okBtn = createButton('Ok'); + okBtn.css({ + 'width': '80px', + 'display': 'block' + }); + okBtn.bind('click', function(event) { + // Remove any warning messages + $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); + + // Check inputs + var ready = true; + var inputs = $("#" + newTabId + " input[type='text']:visible"); + for ( var i = 0; i < inputs.length; i++) { + if (!inputs.eq(i).val()) { + inputs.eq(i).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + inputs.eq(i).css('border', 'solid #BDBDBD 1px'); + } + } + + // Generate arguments + var chkBoxes = $("#" + newTabId + " input[type='checkbox']:checked"); + var optStr = ''; + var opt; + for ( var i = 0; i < chkBoxes.length; i++) { + opt = chkBoxes.eq(i).attr('name'); + optStr += '-' + opt; + + // If it is the boot order + if (opt == 's') { + // Get the boot order + optStr += ';' + $('#' + newTabId + ' input[name=bootOrder]').val(); + } + + // Append ; to end of string + if (i < (chkBoxes.length - 1)) { + optStr += ';'; + } + } + + // If no inputs are empty + if (ready) { + // Get nodes + var tgts = $('#' + newTabId + ' input[name=target]').val(); + + // Get IPL address + var ipl = $('#' + newTabId + ' input[name=ipl]'); + if (ipl) { + optStr += 'ipl=' + ipl.val(); + } + + // Disable all inputs and Ok button + $('#' + newTabId + ' input').attr('disabled', 'disabled'); + $(this).attr('disabled', 'true'); + + /** + * (1) Boot to network + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rnetboot', + tgt : tgts, + args : optStr, + msg : 'out=' + statBarId + ';cmd=rnetboot;tgt=' + tgts + }, + + success : function(data) { + data = decodeRsp(data); + updateStatusBar(data); + } + }); + + // Show status bar + statusBar.show(); + } else { + // Show warning message + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this).parents('.ui-tabs-panel')); + } + }); + netbootForm.append(okBtn); + + // Append to discover tab + tab.add(newTabId, 'Boot', netbootForm, true); + + // Select new tab + tab.select(newTabId); } \ No newline at end of file diff --git a/xCAT-UI/js/nodes/rscan.js b/xCAT-UI/js/nodes/rscan.js index 5c9585274..06fdbff09 100644 --- a/xCAT-UI/js/nodes/rscan.js +++ b/xCAT-UI/js/nodes/rscan.js @@ -1,171 +1,174 @@ -/** - * Load rscan page - * - * @param tgtNodes Targets to run rscan against - */ -function loadRscanPage(tgtNodes) { - // Get node OS - var osHash = new Object(); - var nodes = tgtNodes.split(','); - for (var i in nodes) { - var os = getNodeAttr(nodes[i], 'os'); - var osBase = os.match(/[a-zA-Z]+/); - if (osBase) { - nodes[osBase] = 1; - } - } - - // Get nodes tab - var tab = getNodesTab(); - - // Generate new tab ID - var inst = 0; - var newTabId = 'rscanTab' + inst; - while ($('#' + newTabId).length) { - // If one already exists, generate another one - inst = inst + 1; - newTabId = 'rscanTab' + inst; - } - - // Create rscan form - var rscanForm = $('
                              '); - - // Create status bar - var statBarId = 'rscanStatusBar' + inst; - var statBar = createStatusBar(statBarId).hide(); - - // Create loader - var loader = createLoader('rscanLoader'); - statBar.find('div').append(loader); - - // Create info bar - var infoBar = createInfoBar('Collects node information from one or more hardware control points'); - rscanForm.append(statBar, infoBar); - - // Create VM fieldset - var vmFS = $('
                              '); - var vmLegend = $('Virtual Machine'); - vmFS.append(vmLegend); - rscanForm.append(vmFS); - - var vmAttr = $('
                              '); - vmFS.append($('
                              ')); - vmFS.append(vmAttr); - - // Create options fieldset - var optionsFS = $('
                              '); - var optionsLegend = $('Options'); - optionsFS.append(optionsLegend); - rscanForm.append(optionsFS); - - var optionsAttr = $('
                              '); - optionsFS.append($('
                              ')); - optionsFS.append(optionsAttr); - - // Create target node or group input - var target = $('
                              '); - vmAttr.append(target); - - // Create options - var optsList = $('
                                '); - optionsAttr.append(optsList); - - optsList.append('
                              • Updates and then prints out node definitions in the xCAT database for CEC/BPA
                              • '); - optsList.append('
                              • Writes output to xCAT database
                              • '); - optsList.append('
                              • XML format
                              • '); - optsList.append('
                              • Stanza formated output
                              • '); - - // Generate tooltips - rscanForm.find('div input[title]').tooltip({ - position: "center right", - offset: [-2, 10], - effect: "fade", - opacity: 0.7, - predelay: 800, - events : { - def : "mouseover,mouseout", - input : "mouseover,mouseout", - widget : "focus mouseover,blur mouseout", - tooltip : "mouseover,mouseout" - } - }); - - /** - * Ok - */ - var okBtn = createButton('Ok'); - okBtn.css({ - 'width': '80px', - 'display': 'block' - }); - okBtn.bind('click', function(event) { - // Remove any warning messages - $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); - - // Check inputs - var ready = true; - var inputs = $("#" + newTabId + " input[type='text']"); - for ( var i = 0; i < inputs.length; i++) { - if (!inputs.eq(i).val()) { - inputs.eq(i).css('border', 'solid #FF0000 1px'); - ready = false; - } else { - inputs.eq(i).css('border', 'solid #BDBDBD 1px'); - } - } - - // Generate arguments - var chkBoxes = $("#" + newTabId + " input[type='checkbox']:checked"); - var optStr = ''; - var opt; - for ( var i = 0; i < chkBoxes.length; i++) { - opt = chkBoxes.eq(i).attr('name'); - optStr += '-' + opt; - - // Append ; to end of string - if (i < (chkBoxes.length - 1)) { - optStr += ';'; - } - } - - // If no inputs are empty - if (ready) { - // Get nodes - var tgts = $('#' + newTabId + ' input[name=target]').val(); - - // Disable all inputs and Ok button - $('#' + newTabId + ' input').attr('disabled', 'disabled'); - $(this).attr('disabled', 'true'); - - /** - * (1) Scan - */ - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'rscan', - tgt : tgts, - args : optStr, - msg : 'out=' + statBarId + ';cmd=rscan;tgt=' + tgts - }, - - success : updateStatusBar - }); - - // Show status bar - statBar.show(); - } else { - // Show warning message - var warn = createWarnBar('Please provide a value for each missing field.'); - warn.prependTo($(this).parents('.ui-tabs-panel')); - } - }); - rscanForm.append(okBtn); - - // Append to discover tab - tab.add(newTabId, 'Scan', rscanForm, true); - - // Select new tab - tab.select(newTabId); +/** + * Load rscan page + * + * @param tgtNodes Targets to run rscan against + */ +function loadRscanPage(tgtNodes) { + // Get node OS + var osHash = new Object(); + var nodes = tgtNodes.split(','); + for (var i in nodes) { + var os = getNodeAttr(nodes[i], 'os'); + var osBase = os.match(/[a-zA-Z]+/); + if (osBase) { + nodes[osBase] = 1; + } + } + + // Get nodes tab + var tab = getNodesTab(); + + // Generate new tab ID + var inst = 0; + var newTabId = 'rscanTab' + inst; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + inst = inst + 1; + newTabId = 'rscanTab' + inst; + } + + // Create rscan form + var rscanForm = $('
                                '); + + // Create status bar + var statBarId = 'rscanStatusBar' + inst; + var statBar = createStatusBar(statBarId).hide(); + + // Create loader + var loader = createLoader('rscanLoader'); + statBar.find('div').append(loader); + + // Create info bar + var infoBar = createInfoBar('Collects node information from one or more hardware control points'); + rscanForm.append(statBar, infoBar); + + // Create VM fieldset + var vmFS = $('
                                '); + var vmLegend = $('Virtual Machine'); + vmFS.append(vmLegend); + rscanForm.append(vmFS); + + var vmAttr = $('
                                '); + vmFS.append($('
                                ')); + vmFS.append(vmAttr); + + // Create options fieldset + var optionsFS = $('
                                '); + var optionsLegend = $('Options'); + optionsFS.append(optionsLegend); + rscanForm.append(optionsFS); + + var optionsAttr = $('
                                '); + optionsFS.append($('
                                ')); + optionsFS.append(optionsAttr); + + // Create target node or group input + var target = $('
                                '); + vmAttr.append(target); + + // Create options + var optsList = $('
                                  '); + optionsAttr.append(optsList); + + optsList.append('
                                • Updates and then prints out node definitions in the xCAT database for CEC/BPA
                                • '); + optsList.append('
                                • Writes output to xCAT database
                                • '); + optsList.append('
                                • XML format
                                • '); + optsList.append('
                                • Stanza formated output
                                • '); + + // Generate tooltips + rscanForm.find('div input[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + /** + * Ok + */ + var okBtn = createButton('Ok'); + okBtn.css({ + 'width': '80px', + 'display': 'block' + }); + okBtn.bind('click', function(event) { + // Remove any warning messages + $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); + + // Check inputs + var ready = true; + var inputs = $("#" + newTabId + " input[type='text']"); + for ( var i = 0; i < inputs.length; i++) { + if (!inputs.eq(i).val()) { + inputs.eq(i).css('border', 'solid #FF0000 1px'); + ready = false; + } else { + inputs.eq(i).css('border', 'solid #BDBDBD 1px'); + } + } + + // Generate arguments + var chkBoxes = $("#" + newTabId + " input[type='checkbox']:checked"); + var optStr = ''; + var opt; + for ( var i = 0; i < chkBoxes.length; i++) { + opt = chkBoxes.eq(i).attr('name'); + optStr += '-' + opt; + + // Append ; to end of string + if (i < (chkBoxes.length - 1)) { + optStr += ';'; + } + } + + // If no inputs are empty + if (ready) { + // Get nodes + var tgts = $('#' + newTabId + ' input[name=target]').val(); + + // Disable all inputs and Ok button + $('#' + newTabId + ' input').attr('disabled', 'disabled'); + $(this).attr('disabled', 'true'); + + /** + * (1) Scan + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rscan', + tgt : tgts, + args : optStr, + msg : 'out=' + statBarId + ';cmd=rscan;tgt=' + tgts + }, + + success : function(data) { + data = decodeRsp(data); + updateStatusBar(data); + } + }); + + // Show status bar + statBar.show(); + } else { + // Show warning message + var warn = createWarnBar('Please provide a value for each missing field.'); + warn.prependTo($(this).parents('.ui-tabs-panel')); + } + }); + rscanForm.append(okBtn); + + // Append to discover tab + tab.add(newTabId, 'Scan', rscanForm, true); + + // Select new tab + tab.select(newTabId); } \ No newline at end of file diff --git a/xCAT-UI/js/nodes/updatenode.js b/xCAT-UI/js/nodes/updatenode.js index 943972e8e..d0a177a40 100644 --- a/xCAT-UI/js/nodes/updatenode.js +++ b/xCAT-UI/js/nodes/updatenode.js @@ -1,403 +1,409 @@ -/** - * Load updatenode page - * - * @param tgtNodes Targets to run updatenode against - */ -function loadUpdatenodePage(tgtNodes) { - // Get OS images - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'tabdump', - tgt : '', - args : 'osimage', - msg : '' - }, - - success : setOSImageCookies - }); - - // Get node OS - var osHash = new Object(); - var nodes = tgtNodes.split(','); - for (var i in nodes) { - var os = getNodeAttr(nodes[i], 'os'); - var osBase = os.match(/[a-zA-Z]+/); - if (osBase) { - nodes[osBase] = 1; - } - } - - // Get nodes tab - var tab = getNodesTab(); - - // Generate new tab ID - var inst = 0; - var newTabId = 'updatenodeTab' + inst; - while ($('#' + newTabId).length) { - // If one already exists, generate another one - inst = inst + 1; - newTabId = 'updatenodeTab' + inst; - } - - // Create rscan form - var updatenodeForm = $('
                                  '); - - // Create status bar - var statBarId = 'updatenodeStatusBar' + inst; - var statusBar = createStatusBar(statBarId).hide(); - - // Create loader - var loader = createLoader('updatenodeLoader'); - statusBar.find('div').append(loader); - - // Create info bar - var infoBar = createInfoBar('Update nodes in an xCAT environment'); - updatenodeForm.append(statusBar, infoBar); - - // Create VM fieldset - var vmFS = $('
                                  '); - var vmLegend = $('Virtual Machine'); - vmFS.append(vmLegend); - updatenodeForm.append(vmFS); - - var vmAttr = $('
                                  '); - vmFS.append($('
                                  ')); - vmFS.append(vmAttr); - - // Create options fieldset - var optionsFS = $('
                                  '); - var optionsLegend = $('Options'); - optionsFS.append(optionsLegend); - updatenodeForm.append(optionsFS); - - var optionsAttr = $('
                                  '); - optionsFS.append($('
                                  ')); - optionsFS.append(optionsAttr); - - // Create target node or group input - var tgt = $('
                                  '); - vmAttr.append(tgt); - - // Create options - var optionsList = $('
                                    '); - optionsAttr.append(optionsList); - - // Create update all software checkbox (only AIX) - if (osHash['AIX']) { - var updateAllOption = $('
                                  • '); - var updateAllChkBox = $(''); - updateAllOption.append(updateAllChkBox); - optionsList.append(updateAllOption); - updateAllOption.append('Install or update all software contained in the source directory'); - - // Create source directory input - var allSwScrDirectory = $('
                                  • '); - // Browse server directory and files - var allSWSrcDirBrowse = createButton('Browse'); - allSWSrcDirBrowse.serverBrowser({ - onSelect : function(path) { - $('#allSwSrcDirectory').val(path); - }, - onLoad : function() { - return $('#allSwSrcDirectory').val(); - }, - knownExt : [ 'exe', 'js', 'txt' ], - knownPaths : [ { - text : 'Install', - image : 'desktop.png', - path : '/install' - } ], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/install' // Limit user to only install directory - }); - allSwScrDirectory.append(allSWSrcDirBrowse); - allSwScrDirectory.hide(); - optionsList.append(allSwScrDirectory); - - // Show source directory when checked - updateAllChkBox.bind('click', function(event) { - if ($(this).is(':checked')) { - allSwScrDirectory.show(); - } else { - allSwScrDirectory.hide(); - } - }); - } - - // Create update software checkbox - var updateOption = $('
                                  • '); - var updateChkBox = $(''); - optionsList.append(updateOption); - updateOption.append(updateChkBox); - updateOption.append('Update existing software'); - - // Create source directory input - var scrDirectory = $('
                                  • '); - // Browse server directory and files - var srcDirBrowse = createButton('Browse'); - srcDirBrowse.serverBrowser({ - onSelect : function(path) { - $('#srcDirectory').val(path); - }, - onLoad : function() { - return $('#srcDirectory').val(); - }, - knownExt : [ 'exe', 'js', 'txt' ], - knownPaths : [ { - text : 'Install', - image : 'desktop.png', - path : '/install' - } ], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/install' // Limit user to only install directory - }); - scrDirectory.append(srcDirBrowse); - scrDirectory.hide(); - optionsList.append(scrDirectory); - - // Create other packages input - var otherPkgs = $('
                                  • '); - otherPkgs.hide(); - optionsList.append(otherPkgs); - - // Create RPM flags input (only AIX) - var aixRpmFlags = $('
                                  • '); - aixRpmFlags.hide(); - optionsList.append(aixRpmFlags); - - // Create installp flags input (only AIX) - var aixInstallPFlags = $('
                                  • '); - aixInstallPFlags.hide(); - optionsList.append(aixInstallPFlags); - - // Create emgr flags input (only AIX) - var aixEmgrFlags = $('
                                  • '); - aixEmgrFlags.hide(); - optionsList.append(aixEmgrFlags); - - // Show flags when checked - updateChkBox.bind('click', function(event) { - if ($(this).is(':checked')) { - scrDirectory.show(); - otherPkgs.show(); - if (osHash['AIX']) { - aixRpmFlags.show(); - aixInstallPFlags.show(); - aixEmgrFlags.show(); - } - } else { - scrDirectory.hide(); - otherPkgs.hide(); - if (osHash['AIX']) { - aixRpmFlags.hide(); - aixInstallPFlags.hide(); - aixEmgrFlags.hide(); - } - } - }); - - // Create postscripts input - var postOption = $('
                                  • '); - var postChkBox = $(''); - optionsList.append(postOption); - postOption.append(postChkBox); - postOption.append('Run postscripts'); - var postscripts = $('
                                  • '); - postscripts.hide(); - optionsList.append(postscripts); - - // Show alternate source directory when checked - postChkBox.bind('click', function(event) { - if ($(this).is(':checked')) { - postscripts.show(); - } else { - postscripts.hide(); - } - }); - optionsList.append('
                                  • Distribute and synchronize files
                                  • '); - optionsList.append('
                                  • Update the ssh keys and host keys for the service nodes and compute nodes
                                  • '); - - // Create update OS checkbox - if (!osHash['AIX']) { - var osOption = $('
                                  • '); - var osChkBox = $(''); - optionsList.append(osOption); - osOption.append(osChkBox); - osOption.append('Update the operating system'); - - var os = $('
                                  • ').hide(); - 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); - optionsList.append(os); - - // Show alternate source directory when checked - osChkBox.bind('click', function(event) { - if ($(this).is(':checked')) { - os.show(); - } else { - os.hide(); - } - }); - } - - // Generate tooltips - updatenodeForm.find('div input[title]').tooltip({ - position: "center right", - offset: [-2, 10], - effect: "fade", - opacity: 0.7, - predelay: 800, - events : { - def : "mouseover,mouseout", - input : "mouseover,mouseout", - widget : "focus mouseover,blur mouseout", - tooltip : "mouseover,mouseout" - } - }); - - /** - * Ok - */ - var updateBtn = createButton('Update'); - updateBtn.css({ - 'width': '80px', - 'display': 'block' - }); - updateBtn.bind('click', function(event) { - // Remove any warning messages - $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); - var ready = true; - - // Generate arguments - var chkBoxes = $("#" + newTabId + " input[type='checkbox']:checked"); - var optionsStr = ''; - var option; - for ( var i = 0; i < chkBoxes.length; i++) { - option = chkBoxes.eq(i).attr('name'); - optionsStr += '-' + option; - - // If update all software is checked - if (option == 'S') { - var srcDir = $('#' + newTabId + ' input[name=allSwSrcDirectory]').val(); - if (srcDir) { - optionsStr += ';-d ' + srcDir; - } - } - - // If update software is checked - if (option == 'S') { - // Get source directory - var srcDirectory = $('#' + newTabId + ' input[name=srcDirectory]').val(); - if (srcDirectory) { - optionsStr += ';-d;' + srcDirectory; - } - - // Get otherpkgs - var otherpkgs = $('#' + newTabId + ' input[name=otherpkgs]').val(); - if (otherpkgs) { - optionsStr += ';otherpkgs=' + otherpkgs; - } - - // Get rpm_flags - var rpm_flags = $('#' + newTabId + ' input[name=rpm_flags]').val(); - if (rpm_flags) { - optionsStr += ';rpm_flags=' + rpm_flags; - } - - // Get installp_flags - var installp_flags = $('#' + newTabId + ' input[name=installp_flags]').val(); - if (installp_flags) { - optionsStr += ';installp_flags=' + installp_flags; - } - - // Get emgr_flags - var emgr_flags = $('#' + newTabId + ' input[name=emgr_flags]').val(); - if (emgr_flags) { - optionsStr += ';emgr_flags=' + emgr_flags; - } - } - - // If postscripts is checked - if (option == 'P') { - // Get postscripts - optionsStr += ';' + $('#' + newTabId + ' input[name=postscripts]').val(); - } - - // If operating system is checked - if (option == 'o') { - // Get the OS - optionsStr += ';' + $('#' + newTabId + ' input[name=os]').val(); - } - - // Append ; to end of string - if (i < (chkBoxes.length - 1)) { - optionsStr += ';'; - } - } - - // If no inputs are empty - if (ready) { - // Get nodes - var tgts = $('#' + newTabId + ' input[name=target]').val(); - - // Disable all inputs and Ok button - $('#' + newTabId + ' input').attr('disabled', 'disabled'); - $(this).attr('disabled', 'true'); - - /** - * (1) Boot to network - */ - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'updatenode', - tgt : tgts, - args : optionsStr, - msg : 'out=' + statBarId + ';cmd=updatenode;tgt=' + tgts - }, - - success : updateStatusBar - }); - - // Show status bar - statusBar.show(); - } else { - // Show warning message - var warn = createWarnBar('You are missing some values'); - warn.prependTo($(this).parents('.ui-tabs-panel')); - } - }); - updatenodeForm.append(updateBtn); - - // Append to discover tab - tab.add(newTabId, 'Update', updatenodeForm, true); - - // Select new tab - tab.select(newTabId); +/** + * Load updatenode page + * + * @param tgtNodes Targets to run updatenode against + */ +function loadUpdatenodePage(tgtNodes) { + // Get OS images + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'osimage', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setOSImageCookies(data); + } + }); + + // Get node OS + var osHash = new Object(); + var nodes = tgtNodes.split(','); + for (var i in nodes) { + var os = getNodeAttr(nodes[i], 'os'); + var osBase = os.match(/[a-zA-Z]+/); + if (osBase) { + nodes[osBase] = 1; + } + } + + // Get nodes tab + var tab = getNodesTab(); + + // Generate new tab ID + var inst = 0; + var newTabId = 'updatenodeTab' + inst; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + inst = inst + 1; + newTabId = 'updatenodeTab' + inst; + } + + // Create rscan form + var updatenodeForm = $('
                                    '); + + // Create status bar + var statBarId = 'updatenodeStatusBar' + inst; + var statusBar = createStatusBar(statBarId).hide(); + + // Create loader + var loader = createLoader('updatenodeLoader'); + statusBar.find('div').append(loader); + + // Create info bar + var infoBar = createInfoBar('Update nodes in an xCAT environment'); + updatenodeForm.append(statusBar, infoBar); + + // Create VM fieldset + var vmFS = $('
                                    '); + var vmLegend = $('Virtual Machine'); + vmFS.append(vmLegend); + updatenodeForm.append(vmFS); + + var vmAttr = $('
                                    '); + vmFS.append($('
                                    ')); + vmFS.append(vmAttr); + + // Create options fieldset + var optionsFS = $('
                                    '); + var optionsLegend = $('Options'); + optionsFS.append(optionsLegend); + updatenodeForm.append(optionsFS); + + var optionsAttr = $('
                                    '); + optionsFS.append($('
                                    ')); + optionsFS.append(optionsAttr); + + // Create target node or group input + var tgt = $('
                                    '); + vmAttr.append(tgt); + + // Create options + var optionsList = $('
                                      '); + optionsAttr.append(optionsList); + + // Create update all software checkbox (only AIX) + if (osHash['AIX']) { + var updateAllOption = $('
                                    • '); + var updateAllChkBox = $(''); + updateAllOption.append(updateAllChkBox); + optionsList.append(updateAllOption); + updateAllOption.append('Install or update all software contained in the source directory'); + + // Create source directory input + var allSwScrDirectory = $('
                                    • '); + // Browse server directory and files + var allSWSrcDirBrowse = createButton('Browse'); + allSWSrcDirBrowse.serverBrowser({ + onSelect : function(path) { + $('#allSwSrcDirectory').val(path); + }, + onLoad : function() { + return $('#allSwSrcDirectory').val(); + }, + knownExt : [ 'exe', 'js', 'txt' ], + knownPaths : [ { + text : 'Install', + image : 'desktop.png', + path : '/install' + } ], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/install' // Limit user to only install directory + }); + allSwScrDirectory.append(allSWSrcDirBrowse); + allSwScrDirectory.hide(); + optionsList.append(allSwScrDirectory); + + // Show source directory when checked + updateAllChkBox.bind('click', function(event) { + if ($(this).is(':checked')) { + allSwScrDirectory.show(); + } else { + allSwScrDirectory.hide(); + } + }); + } + + // Create update software checkbox + var updateOption = $('
                                    • '); + var updateChkBox = $(''); + optionsList.append(updateOption); + updateOption.append(updateChkBox); + updateOption.append('Update existing software'); + + // Create source directory input + var scrDirectory = $('
                                    • '); + // Browse server directory and files + var srcDirBrowse = createButton('Browse'); + srcDirBrowse.serverBrowser({ + onSelect : function(path) { + $('#srcDirectory').val(path); + }, + onLoad : function() { + return $('#srcDirectory').val(); + }, + knownExt : [ 'exe', 'js', 'txt' ], + knownPaths : [ { + text : 'Install', + image : 'desktop.png', + path : '/install' + } ], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/install' // Limit user to only install directory + }); + scrDirectory.append(srcDirBrowse); + scrDirectory.hide(); + optionsList.append(scrDirectory); + + // Create other packages input + var otherPkgs = $('
                                    • '); + otherPkgs.hide(); + optionsList.append(otherPkgs); + + // Create RPM flags input (only AIX) + var aixRpmFlags = $('
                                    • '); + aixRpmFlags.hide(); + optionsList.append(aixRpmFlags); + + // Create installp flags input (only AIX) + var aixInstallPFlags = $('
                                    • '); + aixInstallPFlags.hide(); + optionsList.append(aixInstallPFlags); + + // Create emgr flags input (only AIX) + var aixEmgrFlags = $('
                                    • '); + aixEmgrFlags.hide(); + optionsList.append(aixEmgrFlags); + + // Show flags when checked + updateChkBox.bind('click', function(event) { + if ($(this).is(':checked')) { + scrDirectory.show(); + otherPkgs.show(); + if (osHash['AIX']) { + aixRpmFlags.show(); + aixInstallPFlags.show(); + aixEmgrFlags.show(); + } + } else { + scrDirectory.hide(); + otherPkgs.hide(); + if (osHash['AIX']) { + aixRpmFlags.hide(); + aixInstallPFlags.hide(); + aixEmgrFlags.hide(); + } + } + }); + + // Create postscripts input + var postOption = $('
                                    • '); + var postChkBox = $(''); + optionsList.append(postOption); + postOption.append(postChkBox); + postOption.append('Run postscripts'); + var postscripts = $('
                                    • '); + postscripts.hide(); + optionsList.append(postscripts); + + // Show alternate source directory when checked + postChkBox.bind('click', function(event) { + if ($(this).is(':checked')) { + postscripts.show(); + } else { + postscripts.hide(); + } + }); + optionsList.append('
                                    • Distribute and synchronize files
                                    • '); + optionsList.append('
                                    • Update the ssh keys and host keys for the service nodes and compute nodes
                                    • '); + + // Create update OS checkbox + if (!osHash['AIX']) { + var osOption = $('
                                    • '); + var osChkBox = $(''); + optionsList.append(osOption); + osOption.append(osChkBox); + osOption.append('Update the operating system'); + + var os = $('
                                    • ').hide(); + 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); + optionsList.append(os); + + // Show alternate source directory when checked + osChkBox.bind('click', function(event) { + if ($(this).is(':checked')) { + os.show(); + } else { + os.hide(); + } + }); + } + + // Generate tooltips + updatenodeForm.find('div input[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + /** + * Ok + */ + var updateBtn = createButton('Update'); + updateBtn.css({ + 'width': '80px', + 'display': 'block' + }); + updateBtn.bind('click', function(event) { + // Remove any warning messages + $(this).parents('.ui-tabs-panel').find('.ui-state-error').remove(); + var ready = true; + + // Generate arguments + var chkBoxes = $("#" + newTabId + " input[type='checkbox']:checked"); + var optionsStr = ''; + var option; + for ( var i = 0; i < chkBoxes.length; i++) { + option = chkBoxes.eq(i).attr('name'); + optionsStr += '-' + option; + + // If update all software is checked + if (option == 'S') { + var srcDir = $('#' + newTabId + ' input[name=allSwSrcDirectory]').val(); + if (srcDir) { + optionsStr += ';-d ' + srcDir; + } + } + + // If update software is checked + if (option == 'S') { + // Get source directory + var srcDirectory = $('#' + newTabId + ' input[name=srcDirectory]').val(); + if (srcDirectory) { + optionsStr += ';-d;' + srcDirectory; + } + + // Get otherpkgs + var otherpkgs = $('#' + newTabId + ' input[name=otherpkgs]').val(); + if (otherpkgs) { + optionsStr += ';otherpkgs=' + otherpkgs; + } + + // Get rpm_flags + var rpm_flags = $('#' + newTabId + ' input[name=rpm_flags]').val(); + if (rpm_flags) { + optionsStr += ';rpm_flags=' + rpm_flags; + } + + // Get installp_flags + var installp_flags = $('#' + newTabId + ' input[name=installp_flags]').val(); + if (installp_flags) { + optionsStr += ';installp_flags=' + installp_flags; + } + + // Get emgr_flags + var emgr_flags = $('#' + newTabId + ' input[name=emgr_flags]').val(); + if (emgr_flags) { + optionsStr += ';emgr_flags=' + emgr_flags; + } + } + + // If postscripts is checked + if (option == 'P') { + // Get postscripts + optionsStr += ';' + $('#' + newTabId + ' input[name=postscripts]').val(); + } + + // If operating system is checked + if (option == 'o') { + // Get the OS + optionsStr += ';' + $('#' + newTabId + ' input[name=os]').val(); + } + + // Append ; to end of string + if (i < (chkBoxes.length - 1)) { + optionsStr += ';'; + } + } + + // If no inputs are empty + if (ready) { + // Get nodes + var tgts = $('#' + newTabId + ' input[name=target]').val(); + + // Disable all inputs and Ok button + $('#' + newTabId + ' input').attr('disabled', 'disabled'); + $(this).attr('disabled', 'true'); + + /** + * (1) Boot to network + */ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'updatenode', + tgt : tgts, + args : optionsStr, + msg : 'out=' + statBarId + ';cmd=updatenode;tgt=' + tgts + }, + + success : function(data) { + data = decodeRsp(data); + updateStatusBar(data); + } + }); + + // Show status bar + statusBar.show(); + } else { + // Show warning message + var warn = createWarnBar('You are missing some values'); + warn.prependTo($(this).parents('.ui-tabs-panel')); + } + }); + updatenodeForm.append(updateBtn); + + // Append to discover tab + tab.add(newTabId, 'Update', updatenodeForm, true); + + // Select new tab + tab.select(newTabId); } \ No newline at end of file diff --git a/xCAT-UI/js/provision/images.js b/xCAT-UI/js/provision/images.js index d1a6f174d..fd4967321 100644 --- a/xCAT-UI/js/provision/images.js +++ b/xCAT-UI/js/provision/images.js @@ -1,1435 +1,1462 @@ -/** - * Global variables - */ -var origAttrs = new Object(); // Original image attributes -var defAttrs; // Definable image attributes -var imgTableId = 'imagesDatatable'; // Images datatable ID -var softwareList = { - "rsct" : ["rsct.core.utils", "rsct.core", "src"], - "pe" : ["IBMJava2-142-ppc64-JRE", "ibm_lapi_ip_rh6p", "ibm_lapi_us_rh6p", "IBM_pe_license", "ibm_pe_rh6p", "ppe_pdb_ppc64_rh600", "sci_ppc_32bit_rh600", "sci_ppc_64bit_rh600", "vac.cmp", - "vac.lib", "vac.lic", "vacpp.cmp", "vacpp.help.pdf", "vacpp.lib", "vacpp.man", "vacpp.rte", "vacpp.rte.lnk", "vacpp.samples", "xlf.cmp", "xlf.help.pdf", "xlf.lib", "xlf.lic", "xlf.man", - "xlf.msg.rte", "xlf.rte", "xlf.rte.lnk", "xlf.samples", "xlmass.lib", "xlsmp.lib", "xlsmp.msg.rte", "xlsmp.rte"], - "gpfs" : ["gpfs.base", "gpfs.gpl", "gpfs.gplbin", "gpfs.msg.en_US"], - "essl" : ["essl.3232.rte", "essl.3264.rte", "essl.6464.rte", "essl.common", "essl.license", "essl.man", "essl.msg", "essl.rte", "ibm-java2", "pessl.common", "pessl.license", "pessl.man", - "pessl.msg", "pessl.rte.ppe"], - "loadl" : ["IBMJava2", "LoadL-full-license-RH6", "LoadL-resmgr-full-RH6", "LoadL-scheduler-full-RH6"], - "ganglia" : ["rrdtool", "ganglia", "ganglia-gmetad", "ganglia-gmond"], - "base" : ["createrepo"] -}; - -/** - * Load images page - */ -function loadImagesPage() { - // Set padding for images page - $('#imagesTab').css('padding', '20px 60px'); - - // Get images within the database - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsdef', - tgt : '', - args : '-t;osimage;-l', - msg : '' - }, - - success : loadImages - }); -} - -/** - * Load images within the database - * - * @param data Data returned from HTTP request - */ -function loadImages(data) { - // Data returned - var rsp = data.rsp; - if (rsp[0].indexOf('Could not find any object definitions') > -1) { - rsp = new Array(); - } - - // Image attributes hash - var attrs = new Object(); - // Image attributes - var headers = new Object(); - - // Clear hash table containing image attributes - origAttrs = ''; - - var image; - var args; - for (var i in rsp) { - // Get the image - var pos = rsp[i].indexOf('Object name:'); - if (pos > -1) { - var temp = rsp[i].split(': '); - image = jQuery.trim(temp[1]); - - // Create a hash for the image attributes - attrs[image] = new Object(); - i++; - } - - // Get key and value - args = rsp[i].split('='); - var key = jQuery.trim(args[0]); - var val = jQuery.trim(args[1]); - - // Create a hash table - attrs[image][key] = val; - headers[key] = 1; - } - - // Save attributes in hash table - origAttrs = attrs; - - // Sort headers - var sorted = new Array(); - for (var key in headers) { - sorted.push(key); - } - sorted.sort(); - - // Add column for check box and image name - sorted.unshift('', 'imagename'); - - // Create a datatable - var dTable = new DataTable(imgTableId); - dTable.init(sorted); - - // Go through each image - for (var img in attrs) { - // Create a row - var row = new Array(); - // Create a check box - var checkBx = ''; - // Push in checkbox and image name - row.push(checkBx, img); - - // Go through each header - for (var i = 2; i < sorted.length; i++) { - // Add the node attributes to the row - var key = sorted[i]; - var val = attrs[img][key]; - if (val) { - row.push(val); - } else { - row.push(''); - } - } - - // Add the row to the table - dTable.add(row); - } - - // Clear the tab before inserting the table - $('#imagesTab').children().remove(); - - // Create info bar for images tab - var info = createInfoBar('Double click on a cell to edit. Click outside the table to save changes. Hit the Escape key to ignore changes.'); - $('#imagesTab').append(info); - - /** - * The following actions are available for images: - * copy Linux distribution and edit image properties - */ - - // Copy CD into install directory - var copyCDLnk = $('Copy CD'); - copyCDLnk.click(function() { - openCopyCdDialog(); - }); - - // Generate stateless or statelite image - var generateLnk = $('Generate image'); - generateLnk.click(function() { - loadCreateImage(); - }); - - // Edit image attributes - var editLnk = $('Edit'); - editLnk.click(function() { - var tgtImages = getNodesChecked(imgTableId).split(','); - if (tgtImages) { - for (var i in tgtImages) { - openEditImagePage(tgtImages[i]); - } - } - }); - - // Add a row - var addLnk = $('Add'); - addLnk.click(function() { - openAddImageDialog(); - }); - - // Remove a row - var removeLnk = $('Remove'); - removeLnk.click(function() { - var images = getNodesChecked(imgTableId); - if (images) { - confirmImageDeleteDialog(images); - } - }); - - // Refresh image table - var refreshLnk = $('Refresh'); - refreshLnk.click(function() { - // Get images within the database - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsdef', - tgt : '', - args : '-t;osimage;-l', - msg : '' - }, - - success : loadImages - }); - }); - - // Insert table - $('#imagesTab').append(dTable.object()); - - // Turn table into a datatable - var myDataTable = $('#' + imgTableId).dataTable({ - 'iDisplayLength': 50, - 'bLengthChange': false, - "bScrollCollapse": true, - "sScrollY": "400px", - "sScrollX": "110%", - "bAutoWidth": true, - "oLanguage": { - "oPaginate": { - "sNext": "", - "sPrevious": "" - } - } - }); - - // Set datatable width - $('#' + imgTableId + '_wrapper').css({ - 'width': '880px' - }); - - // Actions - var actionBar = $('
                                      ').css("width", "450px"); - var advancedLnk = 'Advanced'; - var advancedMenu = createMenu([copyCDLnk, generateLnk]); - - // Create an action menu - var actionsMenu = createMenu([refreshLnk, addLnk, editLnk, removeLnk, [advancedLnk, advancedMenu]]); - 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 = $(''); - $('#' + imgTableId + '_wrapper').prepend(menuDiv); - menuDiv.append(actionBar); - $('#' + imgTableId + '_filter').appendTo(menuDiv); - - /** - * Enable editable columns - */ - - // Do not make 1st or 2nd columns editable - $('#' + imgTableId + ' td:not(td:nth-child(1),td:nth-child(2))').editable( - function(value, settings) { - // Get column index - var colPos = this.cellIndex; - - // Get row index - var dTable = $('#' + imgTableId).dataTable(); - var rowPos = dTable.fnGetPosition(this.parentNode); - - // Update datatable - dTable.fnUpdate(value, rowPos, colPos); - - // Get image name - var image = $(this).parent().find('td:eq(1)').text(); - - // Get table headers - var headers = $('#' + imgTableId).parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr:eq(0) th'); - - // Get attribute name - var attrName = jQuery.trim(headers.eq(colPos).text()); - // Get column value - var value = $(this).text(); - // Build argument - var args = attrName + '=' + value; - - // Send command to change image attributes - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chdef', - tgt : '', - args : '-t;osimage;-o;' + image + ';' + args, - msg : 'out=imagesTab;tgt=' + image - }, - - success: showChdefOutput - }); - - return value; - }, { - onblur : 'submit', // Clicking outside editable area submits changes - type : 'textarea', // Input type to use - placeholder: ' ', - event : "dblclick", // Double click and edit - height : '30px' // The height of the text area - }); - - // Get definable node attributes - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'lsdef', - tgt : '', - args : '-t;osimage;-h', - msg : '' - }, - - success : setImageDefAttrs - }); -} - -/** - * Open dialog to confirm deleting image - * - * @param images Comma delimited image names - */ -function confirmImageDeleteDialog(images) { - // Make images list more readable - var dialogId = 'confirmImageRemove'; - var tmp = images.replace(new RegExp(',', 'g'), ', '); - var confirmDialog = $('
                                      ' - + '

                                      Are you sure you want to remove ' + tmp + '?

                                      ' - + '
                                      '); - - // Open dialog to confirm delete - confirmDialog.dialog({ - modal: true, - close: function(){ - $(this).remove(); - }, - title: 'Confirm', - width: 500, - buttons: { - "Ok": function(){ - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - // Add image to xCAT - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'rmdef', - tgt : '', - args : '-t;osimage;-o;' + images, - msg : dialogId - }, - - success : updateImageDialog - }); - }, - "Cancel": function(){ - $(this).dialog("close"); - } - } - }); -} - -/** - * Open a dialog to add an image - */ -function openAddImageDialog() { - // Create dialog to add image - var dialogId = 'addImage'; - var addImageForm = $('
                                      '); - - // 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.'); - - var imageFS = $('
                                      '); - var imageLegend = $('Image'); - imageFS.append(imageLegend); - var imageAttr = $('
                                      '); - imageFS.append($('
                                      ')); - imageFS.append(imageAttr); - - var optionFS = $('
                                      '); - var optionLegend = $('Options'); - optionFS.append(optionLegend); - var optionAttr = $('
                                      '); - optionFS.append($('
                                      ')); - optionFS.append(optionAttr); - - addImageForm.append(info, imageFS, optionFS); - - // Create inputs for image attributes - var imageName = $('
                                      '); - var imageType = $('
                                      '); - var architecture = $('
                                      '); - var osName = $('
                                      '); - var osVersion = $('
                                      '); - var profile = $('
                                      '); - var provisionMethod = $('
                                      '); - var provisionSelect = $(''); - provisionMethod.append(provisionSelect); - - // Create inputs for optional attributes - var otherpkgDirectory = $('
                                      '); - var otherpkgDirectoryInput = $(''); - otherpkgDirectory.append(otherpkgDirectoryInput); - otherpkgDirectoryInput.serverBrowser({ - onSelect : function(path) { - $('#addImage input[name="otherpkgdir"]').val(path); - }, - onLoad : function() { - return $('#addImage input[name="otherpkgdir"]').val(); - }, - knownPaths : [{ - text : 'Install', - image : 'desktop.png', - path : '/install' - }], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/install' // Limit user to only install directory - }); - var packageDirectory = $('
                                      '); - var packageDirectoryInput = $(''); - packageDirectory.append(packageDirectoryInput); - packageDirectoryInput.serverBrowser({ - onSelect : function(path) { - $('#addImage input[name="pkgdir"]').val(path); - }, - onLoad : function() { - return $('#addImage input[name="pkgdir"]').val(); - }, - knownPaths : [{ - text : 'Install', - image : 'desktop.png', - path : '/install' - }], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/install' // Limit user to only install directory - }); - var packageList = $('
                                      '); - var packageListInput = $(''); - packageList.append(packageListInput); - packageListInput.serverBrowser({ - onSelect : function(path) { - $('#addImage input[name="pkglist"]').val(path); - }, - onLoad : function() { - return $('#addImage input[name="pkglist"]').val(); - }, - knownPaths : [{ - text : 'Install', - image : 'desktop.png', - path : '/install' - }], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/install' // Limit user to only install directory - }); - var template = $('
                                      '); - var templateInput = $(''); - template.append(templateInput); - templateInput.serverBrowser({ - onSelect : function(path) { - $('#addImage input[name="template"]').val(path); - }, - onLoad : function() { - return $('#addImage input[name="template"]').val(); - }, - knownPaths : [{ - text : 'Install', - image : 'desktop.png', - path : '/install' - }], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/install' // Limit user to only install directory - }); - - imageAttr.append(imageName, imageType, architecture, osName, osVersion, profile, provisionMethod); - optionAttr.append(otherpkgDirectory, packageDirectory, packageList, template); - - // Generate tooltips - addImageForm.find('div input[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 - addImageForm.dialog({ - title:'Add image', - modal: true, - close: function(){ - $(this).remove(); - }, - beight: 400, - width: 600, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - // Get image attributes - var imageType = $(this).find('input[name="imagetype"]'); - 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"]'); - - // Get optional image attributes - var otherpkgDirectory = $(this).find('input[name="otherpkgdir"]'); - var pkgDirectory = $(this).find('input[name="pkgdir"]'); - var pkgList = $(this).find('input[name="pkglist"]'); - var template = $(this).find('input[name="template"]'); - - // 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");} - }); - - // Create arguments to send via AJAX - var args = '-t;osimage;-o;' + imageName.val() + ';' + - 'imagetype=' + imageType.val() + ';' + - 'osarch=' + architecture.val() + ';' + - 'osname=' + osName.val() + ';' + - 'osvers=' + osVersion.val() + ';' + - 'profile=' + profile.val() + ';' + - 'provmethod=' + provisionMethod.val(); - - // Get optional attributes - if (otherpkgDirectory.val()) - args += ';otherpkgdir=' + otherpkgDirectory.val(); - if (pkgDirectory.val()) - args += ';pkgdir=' + pkgDirectory.val(); - if (pkgList.val()) - args += ';pkglist=' + pkgList.val(); - if (template.val()) - args += ';template=' + template.val(); - - // Add image to xCAT - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chdef', - tgt : '', - args : args, - msg : dialogId - }, - - success : updateImageDialog - }); - } - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Update image dialog - * - * @param data HTTP request data - */ -function updateImageDialog(data) { - var dialogId = data.msg; - var infoMsg; - - // Delete loader if one does exist - $('.ui-dialog #' + dialogId + ' img[src="images/loader.gif"]').remove(); - - // Create info message - if (jQuery.isArray(data.rsp)) { - infoMsg = ''; - - // If the data returned is more than 10 lines, get only the last line - var i, start; - if (data.rsp.length > 10) - start = data.rsp.length - 1; - else - start = 0; - - for (i = start; i < data.rsp.length; i++) - 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': '90%' - }); - - infoBar.append(icon, msg, close); - infoBar.prependTo($('.ui-dialog #' + dialogId)); -} - -/** - * Set definable image attributes - * - * @param data Data returned from HTTP request - */ -function setImageDefAttrs(data) { - // Clear hash table containing definable image attributes - defAttrs = new Array(); - - // Get definable attributes - var attrs = data.rsp[2].split(/\n/); - - // Go through each line - var attr, key, descr; - for (var i in attrs) { - attr = attrs[i]; - - // If the line is not empty - if (attr) { - // If the line has the attribute name - if (attr.indexOf(':') && attr.indexOf(' ')) { - // Get attribute name and description - key = jQuery.trim(attr.substring(0, attr.indexOf(':'))); - descr = jQuery.trim(attr.substring(attr.indexOf(':') + 1)); - descr = descr.replace(new RegExp('<', 'g'), '[').replace(new RegExp('>', 'g'), ']'); - - // Set hash table where key = attribute name and value = description - defAttrs[key] = descr; - } else { - // Append description to hash table - defAttrs[key] = defAttrs[key] + '\n' + attr.replace(new RegExp('<', 'g'), '[').replace(new RegExp('>', 'g'), ']'); - } - } // End of if - } // End of for -} - -/** - * Load create image page - */ -function loadCreateImage() { - // Get nodes tab - var tab = getProvisionTab(); - var tabId = 'createImageTab'; - - // Generate new tab ID - if ($('#' + tabId).size()) { - tab.select(tabId); - return; - } - - var imageOsVers = $.cookie("xcat_osvers").split(","); - var imageArch = $.cookie("xcat_osarchs").split(","); - var profiles = $.cookie("xcat_profiles").split(","); - - var createImgForm = $('
                                      '); - var createImgFS = $('
                                      ').append('Create Image'); - createImgForm.append(createImgFS); - - // Show info bar - var infoBar = createInfoBar('Specify the parameters for the image (stateless or statelite) you want to create, then click Create.'); - createImgFS.append(infoBar); - - // Drop down for OS versions - var osVerSelect = $(''); - for (var i in imageOsVers) - osVerSelect.append(''); - createImgFS.append($('
                                      ').append(osVerSelect)); - - // Drop down for OS architectures - var imgSelect = $(''); - for (var i in imageArch) - imgSelect.append(''); - createImgFS.append($('
                                      ').append(imgSelect)); - - // Netboot interface input - createImgFS.append($('
                                      ')); - - // Profile selector - var profileSelect = $('' + - '' + - '' + - '
                                      ')); - - // Create HPC software stack fieldset - createHpcFS(createImgForm); - - // The button used to create images is created here - var createImageBtn = createButton("Create"); - createImageBtn.bind('click', function(event) { - createImage(); - }); - - createImgForm.append(createImageBtn); - - // Add tab - tab.add(tabId, 'Create', createImgForm, true); - tab.select(tabId); - - // Check the selected OS version and OS arch for HPC stack - // If they are valid, show the HCP stack fieldset - hpcShow(); -} - -/** - * Create HPC fieldset - * - * @param container The container to hold the HPC fieldset - */ -function createHpcFS(container) { - var hpcFieldset = $('
                                      '); - hpcFieldset.append('HPC Software Stack'); - - var str = 'Before selecting the software, you should have the following already completed on your xCAT cluster:

                                      ' - + '1. If you are using the xCAT hierarchy, your service nodes are installed and running.
                                      ' - + '2. Your compute nodes are defined in xCAT, and you have verified your hardware control capabilities, ' - + 'gathered MAC addresses, and done all the other necessary preparations for a diskless install.
                                      ' - + '3. You should have a diskless image created with the base OS installed and verified it on at least one test node.
                                      ' - + '4. You should install the software on the management node and copy all correponding packages into the location "/install/custom/otherpkgs/" based on ' - + 'these documents.
                                      '; - hpcFieldset.append(createInfoBar(str)); - - // Advanced software - str = '
                                      • GPFS
                                      • ' + - '
                                      • RSCT
                                      • ' + - '
                                      • PE
                                      • ' + - '
                                      • ESSl & PESSL
                                      • ' + - '
                                      ' + - '
                                      • Ganglia
                                      • ' + - '
                                      '; - hpcFieldset.append(str); - - container.append($('
                                      ').append(hpcFieldset)); -} - -/** - * Check the dependance for ESSL and start the software check for ESSL - * - * @param softwareObject The checkbox object of ESSL - */ -function esslCheck(softwareObject) { - var softwareName = softwareObject.name; - if (!$('#createImageTab input[name=pe]').attr('checked')) { - var warnBar = createWarnBar('You must first select the PE'); - $(':checkbox[name=essl]').attr("checked", false); - - // Clear existing warnings and append new warning - $('#hpcsoft .ui-state-error').remove(); - $('#hpcsoft').prepend(warnBar); - - return; - } else { - softwareCheck(softwareObject); - } -} - -/** - * Check the parameters for the HPC software - * - * @param softwareObject Checkbox object of the HPC software - * @return True if the checkbox is checked, false otherwise - */ -function softwareCheck(softwareObject) { - var softwareName = softwareObject.name; - $('#createImageTab #' + softwareName + 'li .ui-state-error').remove(); - $('#createImageTab #' + softwareName + 'li').append(createLoader()); - var cmdString = genRpmCmd(softwareName); - $.ajax( { - url : 'lib/systemcmd.php', - dataType : 'json', - data : { - cmd : cmdString, - msg : softwareName - }, - success : function(data) { - if (rpmCheck(data.rsp, data.msg)) { - genLsCmd(data.msg); - $.ajax( { - url : 'lib/systemcmd.php', - dataType : 'json', - data : { - cmd : genLsCmd(data.msg), - msg : data.msg - }, - success : rpmCopyCheck - }); - } - } - }); -} - -/** - * Check if the RPMs are copied to the special location - * - * @param data Data returned from HTTP request - */ -function rpmCopyCheck(data) { - // Remove the loading image - var errorStr = ''; - var softwareName = data.msg; - - // Check the return information - var reg = /.+:(.+): No such.*/; - var resultArray = data.rsp.split("\n"); - for ( var i in resultArray) { - var temp = reg.exec(resultArray[i]); - if (temp) { - // Find out the path and RPM name - var pos = temp[1].lastIndexOf('/'); - var path = temp[1].substring(0, pos); - var rpmName = temp[1].substring(pos + 1).replace('*', ''); - errorStr += 'copy ' + rpmName + ' to ' + path + '
                                      '; - } - } - $('#createImageTab #' + softwareName + 'li').find('img').remove(); - - // No error, show the check image - if (!errorStr) { - var infoPart = '
                                      '; - $('#createImageTab #' + softwareName + 'li').append(infoPart); - } else { - // Show the error message - errorStr = 'To install the RSCT on your compute node. You should:
                                      ' + errorStr + '
                                      '; - var warnBar = createWarnBar(errorStr); - $(':checkbox[name=' + softwareName + ']').attr("checked", false); - - // Clear existing warnings and append new warning - $('#hpcsoft .ui-state-error').remove(); - $('#hpcsoft').prepend(warnBar); - } -} - -/** - * Generate the RPM command for rpmcheck - * - * @param softwareName The name of the software - * @return The RPM command - */ -function genRpmCmd(softwareName) { - var cmdString; - cmdString = 'rpm -q '; - for (var i in softwareList[softwareName]) { - cmdString += softwareList[softwareName][i] + ' '; - } - - for (var i in softwareList['base']) { - cmdString += softwareList['base'][i] + ' '; - } - - return cmdString; -} - -/** - * Check if the RPMs for the HPC software are copied to the special location - * - * @param softwareName The name of the software - */ -function genLsCmd(softwareName) { - var osvers = $('#createImageTab #osvers').val(); - var osarch = $('#createImageTab #osarch').val(); - var path = '/install/post/otherpkgs/' + osvers + '/' + osarch + '/' + softwareName; - var checkCmd = 'ls '; - - for (var i in softwareList[softwareName]) { - checkCmd += path + '/' + softwareList[softwareName][i] + '*.rpm '; - } - checkCmd += '2>&1'; - - return checkCmd; -} - -/** - * Check if all RPMs are installed - * - * @param checkInfo 'rpm -q' output - * @return True if all RPMs are installed, false otherwise - */ -function rpmCheck(checkInfo, name) { - var errorStr = ''; - - var checkArray = checkInfo.split('\n'); - for (var i in checkArray) { - if (checkArray[i].indexOf('not install') != -1) { - errorStr += checkArray[i] + '
                                      '; - } - } - - if (!errorStr) { - return true; - } - - errorStr = errorStr.substr(0, errorStr.length - 1); - $(':checkbox[name=' + name + ']').attr('checked', false); - - // Add the error - var warnBar = createWarnBar(errorStr); - $('#createImageTab #' + name + 'li').find('img').remove(); - - // Clear existing warnings and append new warning - $('#hpcsoft .ui-state-error').remove(); - $('#hpcsoft').prepend(warnBar); - - return; -} - -/** - * Check the option and decide whether to show the hpcsoft or not - */ -function hpcShow() { - // The current UI only supports RHELS 6 - // If you want to support all, delete the subcheck - if ($('#createImageTab #osvers').attr('value') != "rhels6" || $('#createImageTab #osarch').attr('value') != "ppc64" || $('#createImageTab #profile').attr('value') != "compute") { - $('#createImageTab #partlysupport').hide(); - } else { - $('#createImageTab #partlysupport').show(); - } -} - -/** - * Load set image properties page - * - * @param tgtImage Target image to set properties - */ -function openEditImagePage(tgtImage) { - // Get nodes tab - var tab = getProvisionTab(); - - // Generate new tab ID - var inst = 0; - var newTabId = 'editImageTab' + inst; - while ($('#' + newTabId).length) { - // If one already exists, generate another one - inst = inst + 1; - newTabId = 'editImageTab' + inst; - } - - // Open new tab - // Create set properties form - var setPropsForm = $('
                                      '); - - // Create info bar - var infoBar = createInfoBar('Choose the properties you wish to change on the node. When you are finished, click Save.'); - setPropsForm.append(infoBar); - - // Create an input for each definable attribute - var div, label, input, value; - var attrIndex = 0; - // Set node attribute - origAttrs[tgtImage]['imagename'] = tgtImage; - for (var key in defAttrs) { - // If an attribute value exists - if (origAttrs[tgtImage][key]) { - // Set the value - value = origAttrs[tgtImage][key]; - } else { - value = ''; - } - - // Create label and input for attribute - div = $('
                                      ').css('display', 'inline'); - label = $('').css('vertical-align', 'middle'); - input = $('').css({ - 'margin-top': '5px', - 'float': 'none', - 'width': 'inherit' - }); - - // There is an element called groups that will override the defaults for the groups attribute. - // Hence, the input must have use CSS to override the float and width. - - // Split attributes into 2 per row - if (attrIndex > 0 && !(attrIndex % 2)) { - div.css('display', 'inline-block'); - } - - attrIndex++; - - // Create server browser - switch (key) { - case 'pkgdir': - input.serverBrowser({ - onSelect : function(path) { - $('#pkgdir').val(path); - }, - onLoad : function() { - return $('#pkgdir').val(); - }, - knownExt : [ 'exe', 'js', 'txt' ], - knownPaths : [{ - text : 'Install', - image : 'desktop.png', - path : '/install' - }], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/install' // Limit user to only install directory - }); - break; - case 'otherpkgdir': - input.serverBrowser({ - onSelect : function(path) { - $('#otherpkgdir').val(path); - }, - onLoad : function() { - return $('#otherpkgdir').val(); - }, - knownExt : [ 'exe', 'js', 'txt' ], - knownPaths : [{ - text : 'Install', - image : 'desktop.png', - path : '/install' - }], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/install' // Limit user to only install directory - }); - break; - case 'pkglist': - input.serverBrowser({ - onSelect : function(path) { - $('#pkglist').val(path); - }, - onLoad : function() { - return $('#pkglist').val(); - }, - knownExt : [ 'exe', 'js', 'txt' ], - knownPaths : [{ - text : 'Install', - image : 'desktop.png', - path : '/install' - }], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/opt/xcat/share' // Limit user to only install directory - }); - break; - case 'otherpkglist': - input.serverBrowser({ - onSelect : function(path) { - $('#otherpkglist').val(path); - }, - onLoad : function() { - return $('#otherpkglist').val(); - }, - knownExt : [ 'exe', 'js', 'txt' ], - knownPaths : [{ - text : 'Install', - image : 'desktop.png', - path : '/install' - }], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/install' // Limit user to only install directory - }); - break; - case 'template': - input.serverBrowser({ - onSelect : function(path) { - $('#template').val(path); - }, - onLoad : function() { - return $('#template').val(); - }, - knownExt : [ 'exe', 'js', 'txt' ], - knownPaths : [{ - text : 'Install', - image : 'desktop.png', - path : '/install' - }], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/opt/xcat/share' // Limit user to only install directory - }); - break; - default: - // Do nothing - } - - // Change border to blue onchange - input.bind('change', function(event) { - $(this).css('border-color', 'blue'); - }); - - div.append(label, input); - setPropsForm.append(div); - } - - // Change style for last division - div.css({ - 'display': 'block', - 'margin': '0px 0px 10px 0px' - }); - - // Generate tooltips - setPropsForm.find('div input[title]').tooltip({ - position: "center right", - offset: [-2, 10], - effect: "fade", - opacity: 0.8, - delay: 500, - predelay: 800, - events: { - def: "mouseover,mouseout", - input: "mouseover,mouseout", - widget: "focus mouseover,blur mouseout", - tooltip: "mouseover,mouseout" - } - }); - - /** - * Save - */ - var saveBtn = createButton('Save'); - saveBtn.bind('click', function(event) { - // Get all inputs - var inputs = $('#' + newTabId + ' input'); - - // Go through each input - var args = ''; - var attrName, attrVal; - inputs.each(function(){ - // If the border color is blue - if ($(this).css('border-left-color') == 'rgb(0, 0, 255)') { - // Change border color back to normal - $(this).css('border-color', ''); - - // Get attribute name and value - attrName = $(this).parent().find('label').text().replace(':', ''); - attrVal = $(this).val(); - - // Build argument string - if (args) { - // Handle subsequent arguments - args += ';' + attrName + '=' + attrVal; - } else { - // Handle the 1st argument - args += attrName + '=' + attrVal; - } - } - }); - - // Send command to change image attributes - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'chdef', - tgt : '', - args : '-t;osimage;-o;' + tgtImage + ';' + args, - msg : 'out=' + newTabId + ';tgt=' + tgtImage - }, - - success: showChdefOutput - }); - }); - setPropsForm.append(saveBtn); - - /** - * Cancel - */ - var cancelBtn = createButton('Cancel'); - cancelBtn.bind('click', function(event) { - // Close the tab - tab.remove($(this).parent().parent().attr('id')); - }); - setPropsForm.append(cancelBtn); - - // Append to discover tab - tab.add(newTabId, 'Edit', setPropsForm, true); - - // Select new tab - tab.select(newTabId); -} - -/** - * Load copy CD page - */ -function openCopyCdDialog() { - // Create copy Linux form - var dialogId = 'imageCopyCd'; - var copyLinuxForm = $('
                                      '); - - // Create info bar - var infoBar = createInfoBar('Copy Linux distributions and service levels from CDs or DVDs to the install directory.'); - copyLinuxForm.append(infoBar); - - // Create Linux ISO input - var iso = $('
                                      '); - var isoLabel = $('').css('vertical-align', 'middle'); - var isoInput = $('').css('width', '300px'); - iso.append(isoLabel); - iso.append(isoInput); - copyLinuxForm.append(iso); - - // Create architecture input - copyLinuxForm.append('
                                      '); - // Create distribution input - copyLinuxForm.append('
                                      '); - - /** - * Browse - */ - var browseBtn = createButton('Browse'); - iso.append(browseBtn); - // Browse server directory and files - browseBtn.serverBrowser({ - onSelect : function(path) { - $('#imageCopyCd #iso').val(path); - }, - onLoad : function() { - return $('#imageCopyCd #iso').val(); - }, - knownExt : [ 'exe', 'js', 'txt' ], - knownPaths : [ { - text : 'Install', - image : 'desktop.png', - path : '/install' - } ], - imageUrl : 'images/serverbrowser/', - systemImageUrl : 'images/serverbrowser/', - handlerUrl : 'lib/getpath.php', - title : 'Browse', - requestMethod : 'POST', - width : '500', - height : '300', - basePath : '/install' // Limit user to only install directory - }); - - // Generate tooltips - copyLinuxForm.find('div input[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 copy CD - copyLinuxForm.dialog({ - title:'Copy CD', - close: function(){ - $(this).remove(); - }, - modal: true, - width: 600, - buttons: { - "Copy": function() { - // Show loader - $('.ui-dialog #imageCopyCd').append(createLoader('')); - - // Change dialog buttons - $(this).dialog('option', 'buttons', { - 'Close': function() {$(this).dialog("close");} - }); - - // Get image attributes - var iso = $(this).find('input[name="iso"]'); - var arch = $(this).find('input[name="arch"]'); - var distro = $(this).find('input[name="distro"]'); - - // Send ajax request to copy ISO - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'copycds', - tgt : '', - args : '-n;' + distro.val() + ';-a;' + arch.val() + ';' + iso.val(), - msg : dialogId - }, - - success : updateImageDialog - }); - }, - "Cancel": function() { - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Use user input or select to create image - */ -function createImage() { - var osvers = $("#createImageTab #osvers").val(); - var osarch = $("#createImageTab #osarch").val(); - var profile = $("#createImageTab #profile").val(); - var bootInterface = $("#createImageTab #netbootif").val(); - var bootMethod = $("#createImageTab #bootmethod").val(); - - $('#createImageTab .ui-state-error').remove(); - // If there no input for the bootInterface - if (!bootInterface) { - var warnBar = createWarnBar('Please specify the netboot interface'); - $("#createImageTab").prepend(warnBar); - return; - } - - var createImageArgs = "createimage;" + osvers + ";" + osarch + ";" + profile + ";" + bootInterface + ";" + bootMethod + ";"; - - $("#createImageTab :checkbox:checked").each(function() { - createImageArgs += $(this).attr("name") + ","; - }); - - createImageArgs = createImageArgs.substring(0, (createImageArgs.length - 1)); - $.ajax({ - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : createImageArgs, - msg : '' - }, - success : function(data) { - - } - }); +/** + * Global variables + */ +var origAttrs = new Object(); // Original image attributes +var defAttrs; // Definable image attributes +var imgTableId = 'imagesDatatable'; // Images datatable ID +var softwareList = { + "rsct" : ["rsct.core.utils", "rsct.core", "src"], + "pe" : ["IBMJava2-142-ppc64-JRE", "ibm_lapi_ip_rh6p", "ibm_lapi_us_rh6p", "IBM_pe_license", "ibm_pe_rh6p", "ppe_pdb_ppc64_rh600", "sci_ppc_32bit_rh600", "sci_ppc_64bit_rh600", "vac.cmp", + "vac.lib", "vac.lic", "vacpp.cmp", "vacpp.help.pdf", "vacpp.lib", "vacpp.man", "vacpp.rte", "vacpp.rte.lnk", "vacpp.samples", "xlf.cmp", "xlf.help.pdf", "xlf.lib", "xlf.lic", "xlf.man", + "xlf.msg.rte", "xlf.rte", "xlf.rte.lnk", "xlf.samples", "xlmass.lib", "xlsmp.lib", "xlsmp.msg.rte", "xlsmp.rte"], + "gpfs" : ["gpfs.base", "gpfs.gpl", "gpfs.gplbin", "gpfs.msg.en_US"], + "essl" : ["essl.3232.rte", "essl.3264.rte", "essl.6464.rte", "essl.common", "essl.license", "essl.man", "essl.msg", "essl.rte", "ibm-java2", "pessl.common", "pessl.license", "pessl.man", + "pessl.msg", "pessl.rte.ppe"], + "loadl" : ["IBMJava2", "LoadL-full-license-RH6", "LoadL-resmgr-full-RH6", "LoadL-scheduler-full-RH6"], + "ganglia" : ["rrdtool", "ganglia", "ganglia-gmetad", "ganglia-gmond"], + "base" : ["createrepo"] +}; + +/** + * Load images page + */ +function loadImagesPage() { + // Set padding for images page + $('#imagesTab').css('padding', '20px 60px'); + + // Get images within the database + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsdef', + tgt : '', + args : '-t;osimage;-l', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadImages(data); + } + }); +} + +/** + * Load images within the database + * + * @param data Data returned from HTTP request + */ +function loadImages(data) { + // Data returned + var rsp = data.rsp; + if (rsp[0].indexOf('Could not find any object definitions') > -1) { + rsp = new Array(); + } + + // Image attributes hash + var attrs = new Object(); + // Image attributes + var headers = new Object(); + + // Clear hash table containing image attributes + origAttrs = ''; + + var image; + var args; + for (var i in rsp) { + // Get the image + var pos = rsp[i].indexOf('Object name:'); + if (pos > -1) { + var temp = rsp[i].split(': '); + image = jQuery.trim(temp[1]); + + // Create a hash for the image attributes + attrs[image] = new Object(); + i++; + } + + // Get key and value + args = rsp[i].split('='); + var key = jQuery.trim(args[0]); + var val = jQuery.trim(args[1]); + + // Create a hash table + attrs[image][key] = val; + headers[key] = 1; + } + + // Save attributes in hash table + origAttrs = attrs; + + // Sort headers + var sorted = new Array(); + for (var key in headers) { + sorted.push(key); + } + sorted.sort(); + + // Add column for check box and image name + sorted.unshift('', 'imagename'); + + // Create a datatable + var dTable = new DataTable(imgTableId); + dTable.init(sorted); + + // Go through each image + for (var img in attrs) { + // Create a row + var row = new Array(); + // Create a check box + var checkBx = ''; + // Push in checkbox and image name + row.push(checkBx, img); + + // Go through each header + for (var i = 2; i < sorted.length; i++) { + // Add the node attributes to the row + var key = sorted[i]; + var val = attrs[img][key]; + if (val) { + row.push(val); + } else { + row.push(''); + } + } + + // Add the row to the table + dTable.add(row); + } + + // Clear the tab before inserting the table + $('#imagesTab').children().remove(); + + // Create info bar for images tab + var info = createInfoBar('Double click on a cell to edit. Click outside the table to save changes. Hit the Escape key to ignore changes.'); + $('#imagesTab').append(info); + + /** + * The following actions are available for images: + * copy Linux distribution and edit image properties + */ + + // Copy CD into install directory + var copyCDLnk = $('Copy CD'); + copyCDLnk.click(function() { + openCopyCdDialog(); + }); + + // Generate stateless or statelite image + var generateLnk = $('Generate image'); + generateLnk.click(function() { + loadCreateImage(); + }); + + // Edit image attributes + var editLnk = $('Edit'); + editLnk.click(function() { + var tgtImages = getNodesChecked(imgTableId).split(','); + if (tgtImages) { + for (var i in tgtImages) { + openEditImagePage(tgtImages[i]); + } + } + }); + + // Add a row + var addLnk = $('Add'); + addLnk.click(function() { + openAddImageDialog(); + }); + + // Remove a row + var removeLnk = $('Remove'); + removeLnk.click(function() { + var images = getNodesChecked(imgTableId); + if (images) { + confirmImageDeleteDialog(images); + } + }); + + // Refresh image table + var refreshLnk = $('Refresh'); + refreshLnk.click(function() { + // Get images within the database + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsdef', + tgt : '', + args : '-t;osimage;-l', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadImages(data); + } + }); + }); + + // Insert table + $('#imagesTab').append(dTable.object()); + + // Turn table into a datatable + var myDataTable = $('#' + imgTableId).dataTable({ + 'iDisplayLength': 50, + 'bLengthChange': false, + "bScrollCollapse": true, + "sScrollY": "400px", + "sScrollX": "110%", + "bAutoWidth": true, + "oLanguage": { + "oPaginate": { + "sNext": "", + "sPrevious": "" + } + } + }); + + // Set datatable width + $('#' + imgTableId + '_wrapper').css({ + 'width': '880px' + }); + + // Actions + var actionBar = $('
                                      ').css("width", "450px"); + var advancedLnk = 'Advanced'; + var advancedMenu = createMenu([copyCDLnk, generateLnk]); + + // Create an action menu + var actionsMenu = createMenu([refreshLnk, addLnk, editLnk, removeLnk, [advancedLnk, advancedMenu]]); + 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 = $(''); + $('#' + imgTableId + '_wrapper').prepend(menuDiv); + menuDiv.append(actionBar); + $('#' + imgTableId + '_filter').appendTo(menuDiv); + + /** + * Enable editable columns + */ + + // Do not make 1st or 2nd columns editable + $('#' + imgTableId + ' td:not(td:nth-child(1),td:nth-child(2))').editable( + function(value, settings) { + // Get column index + var colPos = this.cellIndex; + + // Get row index + var dTable = $('#' + imgTableId).dataTable(); + var rowPos = dTable.fnGetPosition(this.parentNode); + + // Update datatable + dTable.fnUpdate(value, rowPos, colPos); + + // Get image name + var image = $(this).parent().find('td:eq(1)').text(); + + // Get table headers + var headers = $('#' + imgTableId).parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr:eq(0) th'); + + // Get attribute name + var attrName = jQuery.trim(headers.eq(colPos).text()); + // Get column value + var value = $(this).text(); + // Build argument + var args = attrName + '=' + value; + + // Send command to change image attributes + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chdef', + tgt : '', + args : '-t;osimage;-o;' + image + ';' + args, + msg : 'out=imagesTab;tgt=' + image + }, + + success : function(data) { + data = decodeRsp(data); + showChdefOutput(data); + } + }); + + return value; + }, { + onblur : 'submit', // Clicking outside editable area submits changes + type : 'textarea', // Input type to use + placeholder: ' ', + event : "dblclick", // Double click and edit + height : '30px' // The height of the text area + }); + + // Get definable node attributes + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'lsdef', + tgt : '', + args : '-t;osimage;-h', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setImageDefAttrs(data); + } + }); +} + +/** + * Open dialog to confirm deleting image + * + * @param images Comma delimited image names + */ +function confirmImageDeleteDialog(images) { + // Make images list more readable + var dialogId = 'confirmImageRemove'; + var tmp = images.replace(new RegExp(',', 'g'), ', '); + var confirmDialog = $('
                                      ' + + '

                                      Are you sure you want to remove ' + tmp + '?

                                      ' + + '
                                      '); + + // Open dialog to confirm delete + confirmDialog.dialog({ + modal: true, + close: function(){ + $(this).remove(); + }, + title: 'Confirm', + width: 500, + buttons: { + "Ok": function(){ + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + // Add image to xCAT + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'rmdef', + tgt : '', + args : '-t;osimage;-o;' + images, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateImageDialog(data); + } + }); + }, + "Cancel": function(){ + $(this).dialog("close"); + } + } + }); +} + +/** + * Open a dialog to add an image + */ +function openAddImageDialog() { + // Create dialog to add image + var dialogId = 'addImage'; + var addImageForm = $('
                                      '); + + // 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.'); + + var imageFS = $('
                                      '); + var imageLegend = $('Image'); + imageFS.append(imageLegend); + var imageAttr = $('
                                      '); + imageFS.append($('
                                      ')); + imageFS.append(imageAttr); + + var optionFS = $('
                                      '); + var optionLegend = $('Options'); + optionFS.append(optionLegend); + var optionAttr = $('
                                      '); + optionFS.append($('
                                      ')); + optionFS.append(optionAttr); + + addImageForm.append(info, imageFS, optionFS); + + // Create inputs for image attributes + var imageName = $('
                                      '); + var imageType = $('
                                      '); + var architecture = $('
                                      '); + var osName = $('
                                      '); + var osVersion = $('
                                      '); + var profile = $('
                                      '); + var provisionMethod = $('
                                      '); + var provisionSelect = $(''); + provisionMethod.append(provisionSelect); + + // Create inputs for optional attributes + var otherpkgDirectory = $('
                                      '); + var otherpkgDirectoryInput = $(''); + otherpkgDirectory.append(otherpkgDirectoryInput); + otherpkgDirectoryInput.serverBrowser({ + onSelect : function(path) { + $('#addImage input[name="otherpkgdir"]').val(path); + }, + onLoad : function() { + return $('#addImage input[name="otherpkgdir"]').val(); + }, + knownPaths : [{ + text : 'Install', + image : 'desktop.png', + path : '/install' + }], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/install' // Limit user to only install directory + }); + var packageDirectory = $('
                                      '); + var packageDirectoryInput = $(''); + packageDirectory.append(packageDirectoryInput); + packageDirectoryInput.serverBrowser({ + onSelect : function(path) { + $('#addImage input[name="pkgdir"]').val(path); + }, + onLoad : function() { + return $('#addImage input[name="pkgdir"]').val(); + }, + knownPaths : [{ + text : 'Install', + image : 'desktop.png', + path : '/install' + }], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/install' // Limit user to only install directory + }); + var packageList = $('
                                      '); + var packageListInput = $(''); + packageList.append(packageListInput); + packageListInput.serverBrowser({ + onSelect : function(path) { + $('#addImage input[name="pkglist"]').val(path); + }, + onLoad : function() { + return $('#addImage input[name="pkglist"]').val(); + }, + knownPaths : [{ + text : 'Install', + image : 'desktop.png', + path : '/install' + }], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/install' // Limit user to only install directory + }); + var template = $('
                                      '); + var templateInput = $(''); + template.append(templateInput); + templateInput.serverBrowser({ + onSelect : function(path) { + $('#addImage input[name="template"]').val(path); + }, + onLoad : function() { + return $('#addImage input[name="template"]').val(); + }, + knownPaths : [{ + text : 'Install', + image : 'desktop.png', + path : '/install' + }], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/install' // Limit user to only install directory + }); + + imageAttr.append(imageName, imageType, architecture, osName, osVersion, profile, provisionMethod); + optionAttr.append(otherpkgDirectory, packageDirectory, packageList, template); + + // Generate tooltips + addImageForm.find('div input[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 + addImageForm.dialog({ + title:'Add image', + modal: true, + close: function(){ + $(this).remove(); + }, + beight: 400, + width: 600, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + // Get image attributes + var imageType = $(this).find('input[name="imagetype"]'); + 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"]'); + + // Get optional image attributes + var otherpkgDirectory = $(this).find('input[name="otherpkgdir"]'); + var pkgDirectory = $(this).find('input[name="pkgdir"]'); + var pkgList = $(this).find('input[name="pkglist"]'); + var template = $(this).find('input[name="template"]'); + + // 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");} + }); + + // Create arguments to send via AJAX + var args = '-t;osimage;-o;' + imageName.val() + ';' + + 'imagetype=' + imageType.val() + ';' + + 'osarch=' + architecture.val() + ';' + + 'osname=' + osName.val() + ';' + + 'osvers=' + osVersion.val() + ';' + + 'profile=' + profile.val() + ';' + + 'provmethod=' + provisionMethod.val(); + + // Get optional attributes + if (otherpkgDirectory.val()) + args += ';otherpkgdir=' + otherpkgDirectory.val(); + if (pkgDirectory.val()) + args += ';pkgdir=' + pkgDirectory.val(); + if (pkgList.val()) + args += ';pkglist=' + pkgList.val(); + if (template.val()) + args += ';template=' + template.val(); + + // Add image to xCAT + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chdef', + tgt : '', + args : args, + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateImageDialog(data); + } + }); + } + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Update image dialog + * + * @param data HTTP request data + */ +function updateImageDialog(data) { + var dialogId = data.msg; + var infoMsg; + + // Delete loader if one does exist + $('.ui-dialog #' + dialogId + ' img[src="images/loader.gif"]').remove(); + + // Create info message + if (jQuery.isArray(data.rsp)) { + infoMsg = ''; + + // If the data returned is more than 10 lines, get only the last line + var i, start; + if (data.rsp.length > 10) + start = data.rsp.length - 1; + else + start = 0; + + for (i = start; i < data.rsp.length; i++) + 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': '90%' + }); + + infoBar.append(icon, msg, close); + infoBar.prependTo($('.ui-dialog #' + dialogId)); +} + +/** + * Set definable image attributes + * + * @param data Data returned from HTTP request + */ +function setImageDefAttrs(data) { + // Clear hash table containing definable image attributes + defAttrs = new Array(); + + // Get definable attributes + var attrs = data.rsp[2].split(/\n/); + + // Go through each line + var attr, key, descr; + for (var i in attrs) { + attr = attrs[i]; + + // If the line is not empty + if (attr) { + // If the line has the attribute name + if (attr.indexOf(':') && attr.indexOf(' ')) { + // Get attribute name and description + key = jQuery.trim(attr.substring(0, attr.indexOf(':'))); + descr = jQuery.trim(attr.substring(attr.indexOf(':') + 1)); + descr = descr.replace(new RegExp('<', 'g'), '[').replace(new RegExp('>', 'g'), ']'); + + // Set hash table where key = attribute name and value = description + defAttrs[key] = descr; + } else { + // Append description to hash table + defAttrs[key] = defAttrs[key] + '\n' + attr.replace(new RegExp('<', 'g'), '[').replace(new RegExp('>', 'g'), ']'); + } + } // End of if + } // End of for +} + +/** + * Load create image page + */ +function loadCreateImage() { + // Get nodes tab + var tab = getProvisionTab(); + var tabId = 'createImageTab'; + + // Generate new tab ID + if ($('#' + tabId).size()) { + tab.select(tabId); + return; + } + + var imageOsVers = $.cookie("xcat_osvers").split(","); + var imageArch = $.cookie("xcat_osarchs").split(","); + var profiles = $.cookie("xcat_profiles").split(","); + + var createImgForm = $('
                                      '); + var createImgFS = $('
                                      ').append('Create Image'); + createImgForm.append(createImgFS); + + // Show info bar + var infoBar = createInfoBar('Specify the parameters for the image (stateless or statelite) you want to create, then click Create.'); + createImgFS.append(infoBar); + + // Drop down for OS versions + var osVerSelect = $(''); + for (var i in imageOsVers) + osVerSelect.append(''); + createImgFS.append($('
                                      ').append(osVerSelect)); + + // Drop down for OS architectures + var imgSelect = $(''); + for (var i in imageArch) + imgSelect.append(''); + createImgFS.append($('
                                      ').append(imgSelect)); + + // Netboot interface input + createImgFS.append($('
                                      ')); + + // Profile selector + var profileSelect = $('' + + '' + + '' + + '
                                      ')); + + // Create HPC software stack fieldset + createHpcFS(createImgForm); + + // The button used to create images is created here + var createImageBtn = createButton("Create"); + createImageBtn.bind('click', function(event) { + createImage(); + }); + + createImgForm.append(createImageBtn); + + // Add tab + tab.add(tabId, 'Create', createImgForm, true); + tab.select(tabId); + + // Check the selected OS version and OS arch for HPC stack + // If they are valid, show the HCP stack fieldset + hpcShow(); +} + +/** + * Create HPC fieldset + * + * @param container The container to hold the HPC fieldset + */ +function createHpcFS(container) { + var hpcFieldset = $('
                                      '); + hpcFieldset.append('HPC Software Stack'); + + var str = 'Before selecting the software, you should have the following already completed on your xCAT cluster:

                                      ' + + '1. If you are using the xCAT hierarchy, your service nodes are installed and running.
                                      ' + + '2. Your compute nodes are defined in xCAT, and you have verified your hardware control capabilities, ' + + 'gathered MAC addresses, and done all the other necessary preparations for a diskless install.
                                      ' + + '3. You should have a diskless image created with the base OS installed and verified it on at least one test node.
                                      ' + + '4. You should install the software on the management node and copy all correponding packages into the location "/install/custom/otherpkgs/" based on ' + + 'these documents.
                                      '; + hpcFieldset.append(createInfoBar(str)); + + // Advanced software + str = '
                                      • GPFS
                                      • ' + + '
                                      • RSCT
                                      • ' + + '
                                      • PE
                                      • ' + + '
                                      • ESSl & PESSL
                                      • ' + + '
                                      ' + + '
                                      • Ganglia
                                      • ' + + '
                                      '; + hpcFieldset.append(str); + + container.append($('
                                      ').append(hpcFieldset)); +} + +/** + * Check the dependance for ESSL and start the software check for ESSL + * + * @param softwareObject The checkbox object of ESSL + */ +function esslCheck(softwareObject) { + var softwareName = softwareObject.name; + if (!$('#createImageTab input[name=pe]').attr('checked')) { + var warnBar = createWarnBar('You must first select the PE'); + $(':checkbox[name=essl]').attr("checked", false); + + // Clear existing warnings and append new warning + $('#hpcsoft .ui-state-error').remove(); + $('#hpcsoft').prepend(warnBar); + + return; + } else { + softwareCheck(softwareObject); + } +} + +/** + * Check the parameters for the HPC software + * + * @param softwareObject Checkbox object of the HPC software + * @return True if the checkbox is checked, false otherwise + */ +function softwareCheck(softwareObject) { + var softwareName = softwareObject.name; + $('#createImageTab #' + softwareName + 'li .ui-state-error').remove(); + $('#createImageTab #' + softwareName + 'li').append(createLoader()); + var cmdString = genRpmCmd(softwareName); + $.ajax( { + url : 'lib/systemcmd.php', + dataType : 'json', + data : { + cmd : cmdString, + msg : softwareName + }, + success : function(data) { + if (rpmCheck(data.rsp, data.msg)) { + genLsCmd(data.msg); + $.ajax( { + url : 'lib/systemcmd.php', + dataType : 'json', + data : { + cmd : genLsCmd(data.msg), + msg : data.msg + }, + success : function(data) { + data = decodeRsp(data); + rpmCopyCheck(data); + } + }); + } + } + }); +} + +/** + * Check if the RPMs are copied to the special location + * + * @param data Data returned from HTTP request + */ +function rpmCopyCheck(data) { + // Remove the loading image + var errorStr = ''; + var softwareName = data.msg; + + // Check the return information + var reg = /.+:(.+): No such.*/; + var resultArray = data.rsp.split("\n"); + for ( var i in resultArray) { + var temp = reg.exec(resultArray[i]); + if (temp) { + // Find out the path and RPM name + var pos = temp[1].lastIndexOf('/'); + var path = temp[1].substring(0, pos); + var rpmName = temp[1].substring(pos + 1).replace('*', ''); + errorStr += 'copy ' + rpmName + ' to ' + path + '
                                      '; + } + } + $('#createImageTab #' + softwareName + 'li').find('img').remove(); + + // No error, show the check image + if (!errorStr) { + var infoPart = '
                                      '; + $('#createImageTab #' + softwareName + 'li').append(infoPart); + } else { + // Show the error message + errorStr = 'To install the RSCT on your compute node. You should:
                                      ' + errorStr + '
                                      '; + var warnBar = createWarnBar(errorStr); + $(':checkbox[name=' + softwareName + ']').attr("checked", false); + + // Clear existing warnings and append new warning + $('#hpcsoft .ui-state-error').remove(); + $('#hpcsoft').prepend(warnBar); + } +} + +/** + * Generate the RPM command for rpmcheck + * + * @param softwareName The name of the software + * @return The RPM command + */ +function genRpmCmd(softwareName) { + var cmdString; + cmdString = 'rpm -q '; + for (var i in softwareList[softwareName]) { + cmdString += softwareList[softwareName][i] + ' '; + } + + for (var i in softwareList['base']) { + cmdString += softwareList['base'][i] + ' '; + } + + return cmdString; +} + +/** + * Check if the RPMs for the HPC software are copied to the special location + * + * @param softwareName The name of the software + */ +function genLsCmd(softwareName) { + var osvers = $('#createImageTab #osvers').val(); + var osarch = $('#createImageTab #osarch').val(); + var path = '/install/post/otherpkgs/' + osvers + '/' + osarch + '/' + softwareName; + var checkCmd = 'ls '; + + for (var i in softwareList[softwareName]) { + checkCmd += path + '/' + softwareList[softwareName][i] + '*.rpm '; + } + checkCmd += '2>&1'; + + return checkCmd; +} + +/** + * Check if all RPMs are installed + * + * @param checkInfo 'rpm -q' output + * @return True if all RPMs are installed, false otherwise + */ +function rpmCheck(checkInfo, name) { + var errorStr = ''; + + var checkArray = checkInfo.split('\n'); + for (var i in checkArray) { + if (checkArray[i].indexOf('not install') != -1) { + errorStr += checkArray[i] + '
                                      '; + } + } + + if (!errorStr) { + return true; + } + + errorStr = errorStr.substr(0, errorStr.length - 1); + $(':checkbox[name=' + name + ']').attr('checked', false); + + // Add the error + var warnBar = createWarnBar(errorStr); + $('#createImageTab #' + name + 'li').find('img').remove(); + + // Clear existing warnings and append new warning + $('#hpcsoft .ui-state-error').remove(); + $('#hpcsoft').prepend(warnBar); + + return; +} + +/** + * Check the option and decide whether to show the hpcsoft or not + */ +function hpcShow() { + // The current UI only supports RHELS 6 + // If you want to support all, delete the subcheck + if ($('#createImageTab #osvers').attr('value') != "rhels6" || $('#createImageTab #osarch').attr('value') != "ppc64" || $('#createImageTab #profile').attr('value') != "compute") { + $('#createImageTab #partlysupport').hide(); + } else { + $('#createImageTab #partlysupport').show(); + } +} + +/** + * Load set image properties page + * + * @param tgtImage Target image to set properties + */ +function openEditImagePage(tgtImage) { + // Get nodes tab + var tab = getProvisionTab(); + + // Generate new tab ID + var inst = 0; + var newTabId = 'editImageTab' + inst; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + inst = inst + 1; + newTabId = 'editImageTab' + inst; + } + + // Open new tab + // Create set properties form + var setPropsForm = $('
                                      '); + + // Create info bar + var infoBar = createInfoBar('Choose the properties you wish to change on the node. When you are finished, click Save.'); + setPropsForm.append(infoBar); + + // Create an input for each definable attribute + var div, label, input, value; + var attrIndex = 0; + // Set node attribute + origAttrs[tgtImage]['imagename'] = tgtImage; + for (var key in defAttrs) { + // If an attribute value exists + if (origAttrs[tgtImage][key]) { + // Set the value + value = origAttrs[tgtImage][key]; + } else { + value = ''; + } + + // Create label and input for attribute + div = $('
                                      ').css('display', 'inline'); + label = $('').css('vertical-align', 'middle'); + input = $('').css({ + 'margin-top': '5px', + 'float': 'none', + 'width': 'inherit' + }); + + // There is an element called groups that will override the defaults for the groups attribute. + // Hence, the input must have use CSS to override the float and width. + + // Split attributes into 2 per row + if (attrIndex > 0 && !(attrIndex % 2)) { + div.css('display', 'inline-block'); + } + + attrIndex++; + + // Create server browser + switch (key) { + case 'pkgdir': + input.serverBrowser({ + onSelect : function(path) { + $('#pkgdir').val(path); + }, + onLoad : function() { + return $('#pkgdir').val(); + }, + knownExt : [ 'exe', 'js', 'txt' ], + knownPaths : [{ + text : 'Install', + image : 'desktop.png', + path : '/install' + }], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/install' // Limit user to only install directory + }); + break; + case 'otherpkgdir': + input.serverBrowser({ + onSelect : function(path) { + $('#otherpkgdir').val(path); + }, + onLoad : function() { + return $('#otherpkgdir').val(); + }, + knownExt : [ 'exe', 'js', 'txt' ], + knownPaths : [{ + text : 'Install', + image : 'desktop.png', + path : '/install' + }], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/install' // Limit user to only install directory + }); + break; + case 'pkglist': + input.serverBrowser({ + onSelect : function(path) { + $('#pkglist').val(path); + }, + onLoad : function() { + return $('#pkglist').val(); + }, + knownExt : [ 'exe', 'js', 'txt' ], + knownPaths : [{ + text : 'Install', + image : 'desktop.png', + path : '/install' + }], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/opt/xcat/share' // Limit user to only install directory + }); + break; + case 'otherpkglist': + input.serverBrowser({ + onSelect : function(path) { + $('#otherpkglist').val(path); + }, + onLoad : function() { + return $('#otherpkglist').val(); + }, + knownExt : [ 'exe', 'js', 'txt' ], + knownPaths : [{ + text : 'Install', + image : 'desktop.png', + path : '/install' + }], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/install' // Limit user to only install directory + }); + break; + case 'template': + input.serverBrowser({ + onSelect : function(path) { + $('#template').val(path); + }, + onLoad : function() { + return $('#template').val(); + }, + knownExt : [ 'exe', 'js', 'txt' ], + knownPaths : [{ + text : 'Install', + image : 'desktop.png', + path : '/install' + }], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/opt/xcat/share' // Limit user to only install directory + }); + break; + default: + // Do nothing + } + + // Change border to blue onchange + input.bind('change', function(event) { + $(this).css('border-color', 'blue'); + }); + + div.append(label, input); + setPropsForm.append(div); + } + + // Change style for last division + div.css({ + 'display': 'block', + 'margin': '0px 0px 10px 0px' + }); + + // Generate tooltips + setPropsForm.find('div input[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.8, + delay: 500, + predelay: 800, + events: { + def: "mouseover,mouseout", + input: "mouseover,mouseout", + widget: "focus mouseover,blur mouseout", + tooltip: "mouseover,mouseout" + } + }); + + /** + * Save + */ + var saveBtn = createButton('Save'); + saveBtn.bind('click', function(event) { + // Get all inputs + var inputs = $('#' + newTabId + ' input'); + + // Go through each input + var args = ''; + var attrName, attrVal; + inputs.each(function(){ + // If the border color is blue + if ($(this).css('border-left-color') == 'rgb(0, 0, 255)') { + // Change border color back to normal + $(this).css('border-color', ''); + + // Get attribute name and value + attrName = $(this).parent().find('label').text().replace(':', ''); + attrVal = $(this).val(); + + // Build argument string + if (args) { + // Handle subsequent arguments + args += ';' + attrName + '=' + attrVal; + } else { + // Handle the 1st argument + args += attrName + '=' + attrVal; + } + } + }); + + // Send command to change image attributes + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'chdef', + tgt : '', + args : '-t;osimage;-o;' + tgtImage + ';' + args, + msg : 'out=' + newTabId + ';tgt=' + tgtImage + }, + + success : function(data) { + data = decodeRsp(data); + showChdefOutput(data); + } + }); + }); + setPropsForm.append(saveBtn); + + /** + * Cancel + */ + var cancelBtn = createButton('Cancel'); + cancelBtn.bind('click', function(event) { + // Close the tab + tab.remove($(this).parent().parent().attr('id')); + }); + setPropsForm.append(cancelBtn); + + // Append to discover tab + tab.add(newTabId, 'Edit', setPropsForm, true); + + // Select new tab + tab.select(newTabId); +} + +/** + * Load copy CD page + */ +function openCopyCdDialog() { + // Create copy Linux form + var dialogId = 'imageCopyCd'; + var copyLinuxForm = $('
                                      '); + + // Create info bar + var infoBar = createInfoBar('Copy Linux distributions and service levels from CDs or DVDs to the install directory.'); + copyLinuxForm.append(infoBar); + + // Create Linux ISO input + var iso = $('
                                      '); + var isoLabel = $('').css('vertical-align', 'middle'); + var isoInput = $('').css('width', '300px'); + iso.append(isoLabel); + iso.append(isoInput); + copyLinuxForm.append(iso); + + // Create architecture input + copyLinuxForm.append('
                                      '); + // Create distribution input + copyLinuxForm.append('
                                      '); + + /** + * Browse + */ + var browseBtn = createButton('Browse'); + iso.append(browseBtn); + // Browse server directory and files + browseBtn.serverBrowser({ + onSelect : function(path) { + $('#imageCopyCd #iso').val(path); + }, + onLoad : function() { + return $('#imageCopyCd #iso').val(); + }, + knownExt : [ 'exe', 'js', 'txt' ], + knownPaths : [ { + text : 'Install', + image : 'desktop.png', + path : '/install' + } ], + imageUrl : 'images/serverbrowser/', + systemImageUrl : 'images/serverbrowser/', + handlerUrl : 'lib/getpath.php', + title : 'Browse', + requestMethod : 'POST', + width : '500', + height : '300', + basePath : '/install' // Limit user to only install directory + }); + + // Generate tooltips + copyLinuxForm.find('div input[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 copy CD + copyLinuxForm.dialog({ + title:'Copy CD', + close: function(){ + $(this).remove(); + }, + modal: true, + width: 600, + buttons: { + "Copy": function() { + // Show loader + $('.ui-dialog #imageCopyCd').append(createLoader('')); + + // Change dialog buttons + $(this).dialog('option', 'buttons', { + 'Close': function() {$(this).dialog("close");} + }); + + // Get image attributes + var iso = $(this).find('input[name="iso"]'); + var arch = $(this).find('input[name="arch"]'); + var distro = $(this).find('input[name="distro"]'); + + // Send ajax request to copy ISO + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'copycds', + tgt : '', + args : '-n;' + distro.val() + ';-a;' + arch.val() + ';' + iso.val(), + msg : dialogId + }, + + success : function(data) { + data = decodeRsp(data); + updateImageDialog(data); + } + }); + }, + "Cancel": function() { + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Use user input or select to create image + */ +function createImage() { + var osvers = $("#createImageTab #osvers").val(); + var osarch = $("#createImageTab #osarch").val(); + var profile = $("#createImageTab #profile").val(); + var bootInterface = $("#createImageTab #netbootif").val(); + var bootMethod = $("#createImageTab #bootmethod").val(); + + $('#createImageTab .ui-state-error').remove(); + // If there no input for the bootInterface + if (!bootInterface) { + var warnBar = createWarnBar('Please specify the netboot interface'); + $("#createImageTab").prepend(warnBar); + return; + } + + var createImageArgs = "createimage;" + osvers + ";" + osarch + ";" + profile + ";" + bootInterface + ";" + bootMethod + ";"; + + $("#createImageTab :checkbox:checked").each(function() { + createImageArgs += $(this).attr("name") + ","; + }); + + createImageArgs = createImageArgs.substring(0, (createImageArgs.length - 1)); + $.ajax({ + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : createImageArgs, + msg : '' + }, + success : function(data) { + data = decodeRsp(data); + } + }); } \ No newline at end of file diff --git a/xCAT-UI/js/provision/provision.js b/xCAT-UI/js/provision/provision.js index 00a059080..f3a394df5 100644 --- a/xCAT-UI/js/provision/provision.js +++ b/xCAT-UI/js/provision/provision.js @@ -1,252 +1,258 @@ -/** - * Global variables - */ -var provisionTabs; // Provision tabs - -/** - * Set the provision tab - * - * @param obj Tab object - */ -function setProvisionTab(obj) { - provisionTabs = obj; -} - -/** - * Get the provision tab - * - * @param Nothing - * @return Tab object - */ -function getProvisionTab() { - return provisionTabs; -} - -/** - * Load provision page - */ -function loadProvisionPage() { - // If the page is loaded - if ($('#content').children().length) { - // Do not load again - return; - } - - // Get OS image names - if (!$.cookie('xcat_imagenames')){ - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'tabdump', - tgt : '', - args : 'osimage', - msg : '' - }, - - success : setOSImageCookies - }); - } - - // Get groups - if (!$.cookie('xcat_groups')){ - $.ajax( { - url : 'lib/cmd.php', - dataType : 'json', - data : { - cmd : 'extnoderange', - tgt : '/.*', - args : 'subgroups', - msg : '' - }, - - success : setGroupsCookies - }); - } - - // Create info bar - var infoBar = createInfoBar('Select a platform to provision or re-provision a node on, then click Ok.'); - - // Create provision page - var provPg = $('
                                      '); - provPg.append(infoBar); - - // Create provision tab - var tab = new Tab('provisionPageTabs'); - setProvisionTab(tab); - tab.init(); - $('#content').append(tab.object()); - - // Create radio buttons for platforms - var hwList = $('
                                        Platforms available:
                                      '); - var esx = $('
                                    • ESX
                                    • '); - var kvm = $('
                                    • KVM
                                    • '); - var zvm = $('
                                    • z\/VM
                                    • '); - var ipmi = $('
                                    • iDataPlex
                                    • '); - var blade = $('
                                    • BladeCenter
                                    • '); - var hmc = $('
                                    • System p
                                    • '); - - hwList.append(esx); - hwList.append(kvm); - hwList.append(zvm); - hwList.append(blade); - hwList.append(ipmi); - hwList.append(hmc); - provPg.append(hwList); - - /** - * Ok - */ - var okBtn = createButton('Ok'); - okBtn.bind('click', function(event) { - // Get hardware that was selected - var hw = $(this).parent().find('input[name="hw"]:checked').val(); - - var inst = 0; - var newTabId = hw + 'ProvisionTab' + inst; - while ($('#' + newTabId).length) { - // If one already exists, generate another one - inst = inst + 1; - newTabId = hw + 'ProvisionTab' + inst; - } - - // Create an instance of the plugin - var title = ''; - var plugin; - switch (hw) { - case "kvm": - plugin = new kvmPlugin(); - title = 'KVM'; - break; - case "esx": - plugin = new esxPlugin(); - title = 'ESX'; - break; - case "blade": - plugin = new bladePlugin(); - title = 'BladeCenter'; - break; - case "hmc": - plugin = new hmcPlugin(); - title = 'System p'; - break; - case "ipmi": - plugin = new ipmiPlugin(); - title = 'iDataPlex'; - break; - case "zvm": - plugin = new zvmPlugin(); - title = 'z/VM'; - break; - } - - // Select tab - tab.add(newTabId, title, '', true); - tab.select(newTabId); - plugin.loadProvisionPage(newTabId); - }); - provPg.append(okBtn); - - // Create resources tab - var resrcPg = $('
                                      '); - - // Create info bar - var resrcInfoBar = createInfoBar('Select a platform to view its current resources.'); - resrcPg.append(resrcInfoBar); - - // Create radio buttons for platforms - var rsrcHwList = $('
                                        Platforms available:
                                      '); - esx = $('
                                    • ESX
                                    • '); - kvm = $('
                                    • KVM
                                    • '); - zvm = $('
                                    • z\/VM
                                    • '); - ipmi = $('
                                    • iDataPlex
                                    • '); - blade = $('
                                    • BladeCenter
                                    • '); - hmc = $('
                                    • System p
                                    • '); - - rsrcHwList.append(esx); - rsrcHwList.append(kvm); - rsrcHwList.append(zvm); - rsrcHwList.append(blade); - rsrcHwList.append(ipmi); - rsrcHwList.append(hmc); - - resrcPg.append(rsrcHwList); - - var okBtn = createButton('Ok'); - okBtn.bind('click', function(event) { - // Get hardware that was selected - var hw = $(this).parent().find('input[name="rsrcHw"]:checked').val(); - - // Generate new tab ID - var newTabId = hw + 'ResourceTab'; - if (!$('#' + newTabId).length) { - // Create loader - var loader = $('
                                      ').append(createLoader(hw + 'ResourceLoader')); - - // Create an instance of the plugin - var plugin = null; - var displayName = ""; - switch (hw) { - case "kvm": - plugin = new kvmPlugin(); - displayName = "KVM"; - break; - case "esx": - plugin = new esxPlugin(); - displayName = "ESX"; - break; - case "blade": - plugin = new bladePlugin(); - displayName = "BladeCenter"; - break; - case "hmc": - plugin = new hmcPlugin(); - displayName = "System p"; - break; - case "ipmi": - plugin = new ipmiPlugin(); - displayName = "iDataPlex"; - break; - case "zvm": - plugin = new zvmPlugin(); - displayName = "z\/VM"; - break; - } - - // Add resource tab and load resources - tab.add(newTabId, displayName, loader, true); - plugin.loadResources(); - } - - // Select tab - tab.select(newTabId); - }); - - resrcPg.append(okBtn); - - // Add provision tab - tab.add('provisionTab', 'Provision', provPg, false); - // Add image tab - tab.add('imagesTab', 'Images', '', false); - // Add resource tab - tab.add('resourceTab', 'Resources', resrcPg, false); - - // Load tabs onselect - $('#provisionPageTabs').bind('tabsselect', function(event, ui){ - // Load image page - if (!$('#imagesTab').children().length && ui.index == 1) { - $('#imagesTab').append($('
                                      ').append(createLoader(''))); - loadImagesPage(); - } - }); - - // Open the quick provision tab - if (window.location.search) { - tab.add('quickProvisionTab', 'Quick Provision', '', true); - tab.select('quickProvisionTab'); - - var provForm = $('
                                      '); - $('#quickProvisionTab').append(provForm); - appendProvisionSection('quick', provForm); - } +/** + * Global variables + */ +var provisionTabs; // Provision tabs + +/** + * Set the provision tab + * + * @param obj Tab object + */ +function setProvisionTab(obj) { + provisionTabs = obj; +} + +/** + * Get the provision tab + * + * @param Nothing + * @return Tab object + */ +function getProvisionTab() { + return provisionTabs; +} + +/** + * Load provision page + */ +function loadProvisionPage() { + // If the page is loaded + if ($('#content').children().length) { + // Do not load again + return; + } + + // Get OS image names + if (!$.cookie('xcat_imagenames')){ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'osimage', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setOSImageCookies(data); + } + }); + } + + // Get groups + if (!$.cookie('xcat_groups')){ + $.ajax( { + url : 'lib/cmd.php', + dataType : 'json', + data : { + cmd : 'extnoderange', + tgt : '/.*', + args : 'subgroups', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setGroupsCookies(data); + } + }); + } + + // Create info bar + var infoBar = createInfoBar('Select a platform to provision or re-provision a node on, then click Ok.'); + + // Create provision page + var provPg = $('
                                      '); + provPg.append(infoBar); + + // Create provision tab + var tab = new Tab('provisionPageTabs'); + setProvisionTab(tab); + tab.init(); + $('#content').append(tab.object()); + + // Create radio buttons for platforms + var hwList = $('
                                        Platforms available:
                                      '); + var esx = $('
                                    • ESX
                                    • '); + var kvm = $('
                                    • KVM
                                    • '); + var zvm = $('
                                    • z\/VM
                                    • '); + var ipmi = $('
                                    • iDataPlex
                                    • '); + var blade = $('
                                    • BladeCenter
                                    • '); + var hmc = $('
                                    • System p
                                    • '); + + hwList.append(esx); + hwList.append(kvm); + hwList.append(zvm); + hwList.append(blade); + hwList.append(ipmi); + hwList.append(hmc); + provPg.append(hwList); + + /** + * Ok + */ + var okBtn = createButton('Ok'); + okBtn.bind('click', function(event) { + // Get hardware that was selected + var hw = $(this).parent().find('input[name="hw"]:checked').val(); + + var inst = 0; + var newTabId = hw + 'ProvisionTab' + inst; + while ($('#' + newTabId).length) { + // If one already exists, generate another one + inst = inst + 1; + newTabId = hw + 'ProvisionTab' + inst; + } + + // Create an instance of the plugin + var title = ''; + var plugin; + switch (hw) { + case "kvm": + plugin = new kvmPlugin(); + title = 'KVM'; + break; + case "esx": + plugin = new esxPlugin(); + title = 'ESX'; + break; + case "blade": + plugin = new bladePlugin(); + title = 'BladeCenter'; + break; + case "hmc": + plugin = new hmcPlugin(); + title = 'System p'; + break; + case "ipmi": + plugin = new ipmiPlugin(); + title = 'iDataPlex'; + break; + case "zvm": + plugin = new zvmPlugin(); + title = 'z/VM'; + break; + } + + // Select tab + tab.add(newTabId, title, '', true); + tab.select(newTabId); + plugin.loadProvisionPage(newTabId); + }); + provPg.append(okBtn); + + // Create resources tab + var resrcPg = $('
                                      '); + + // Create info bar + var resrcInfoBar = createInfoBar('Select a platform to view its current resources.'); + resrcPg.append(resrcInfoBar); + + // Create radio buttons for platforms + var rsrcHwList = $('
                                        Platforms available:
                                      '); + esx = $('
                                    • ESX
                                    • '); + kvm = $('
                                    • KVM
                                    • '); + zvm = $('
                                    • z\/VM
                                    • '); + ipmi = $('
                                    • iDataPlex
                                    • '); + blade = $('
                                    • BladeCenter
                                    • '); + hmc = $('
                                    • System p
                                    • '); + + rsrcHwList.append(esx); + rsrcHwList.append(kvm); + rsrcHwList.append(zvm); + rsrcHwList.append(blade); + rsrcHwList.append(ipmi); + rsrcHwList.append(hmc); + + resrcPg.append(rsrcHwList); + + var okBtn = createButton('Ok'); + okBtn.bind('click', function(event) { + // Get hardware that was selected + var hw = $(this).parent().find('input[name="rsrcHw"]:checked').val(); + + // Generate new tab ID + var newTabId = hw + 'ResourceTab'; + if (!$('#' + newTabId).length) { + // Create loader + var loader = $('
                                      ').append(createLoader(hw + 'ResourceLoader')); + + // Create an instance of the plugin + var plugin = null; + var displayName = ""; + switch (hw) { + case "kvm": + plugin = new kvmPlugin(); + displayName = "KVM"; + break; + case "esx": + plugin = new esxPlugin(); + displayName = "ESX"; + break; + case "blade": + plugin = new bladePlugin(); + displayName = "BladeCenter"; + break; + case "hmc": + plugin = new hmcPlugin(); + displayName = "System p"; + break; + case "ipmi": + plugin = new ipmiPlugin(); + displayName = "iDataPlex"; + break; + case "zvm": + plugin = new zvmPlugin(); + displayName = "z\/VM"; + break; + } + + // Add resource tab and load resources + tab.add(newTabId, displayName, loader, true); + plugin.loadResources(); + } + + // Select tab + tab.select(newTabId); + }); + + resrcPg.append(okBtn); + + // Add provision tab + tab.add('provisionTab', 'Provision', provPg, false); + // Add image tab + tab.add('imagesTab', 'Images', '', false); + // Add resource tab + tab.add('resourceTab', 'Resources', resrcPg, false); + + // Load tabs onselect + $('#provisionPageTabs').bind('tabsselect', function(event, ui){ + // Load image page + if (!$('#imagesTab').children().length && ui.index == 1) { + $('#imagesTab').append($('
                                      ').append(createLoader(''))); + loadImagesPage(); + } + }); + + // Open the quick provision tab + if (window.location.search) { + tab.add('quickProvisionTab', 'Quick Provision', '', true); + tab.select('quickProvisionTab'); + + var provForm = $('
                                      '); + $('#quickProvisionTab').append(provForm); + appendProvisionSection('quick', provForm); + } } \ No newline at end of file diff --git a/xCAT-UI/js/service/service.js b/xCAT-UI/js/service/service.js index 3d49b98d9..0ffcaf7d4 100644 --- a/xCAT-UI/js/service/service.js +++ b/xCAT-UI/js/service/service.js @@ -1,2153 +1,2192 @@ -/** - * Global variables - */ -var serviceTabs; -var nodeName; -var nodePath; -var nodeStatus; -var gangliaTimer; - -/** - * Initialize service page - */ -function initServicePage() { - // Load theme - var theme = $.cookie('xcat_theme'); - if (theme) { - switch (theme) { - case 'cupertino': - includeCss("css/themes/jquery-ui-cupertino.css"); - break; - case 'dark_hive': - includeCss("css/themes/jquery-ui-dark_hive.css"); - break; - case 'redmond': - includeCss("css/themes/jquery-ui-redmond.css"); - break; - case 'start': - includeCss("css/themes/jquery-ui-start.css"); - break; - case 'sunny': - includeCss("css/themes/jquery-ui-sunny.css"); - break; - case 'ui_dark': - includeCss("css/themes/jquery-ui-ui_darkness.css"); - break; - default: - includeCss("css/themes/jquery-ui-start.css"); - } - } else { - includeCss("css/themes/jquery-ui-start.css"); - } - - // Load jQuery stylesheets - includeCss("css/jquery.dataTables.css"); - includeCss("css/superfish.css"); - includeCss("css/jstree.css"); - includeCss("css/jquery.jqplot.css"); - - // Load custom stylesheet - includeCss("css/style.css"); - - // Reuqired JQuery plugins - includeJs("js/jquery/jquery.dataTables.min.js"); - includeJs("js/jquery/jquery.cookie.min.js"); - includeJs("js/jquery/tooltip.min.js"); - includeJs("js/jquery/superfish.min.js"); - includeJs("js/jquery/jquery.jqplot.min.js"); - includeJs("js/jquery/jqplot.dateAxisRenderer.min.js"); - - // Custom plugins - includeJs("js/custom/esx.js"); - includeJs("js/custom/kvm.js"); - includeJs("js/custom/zvm.js"); - - // Enable settings link - $('#xcat_settings').click(function() { - openSettings(); - }); - - // Show service page - $("#content").children().remove(); - includeJs("js/service/utils.js"); - loadServicePage(); - - // Initialize tab index history - $.cookie('xcat_tabindex_history', '0,0', { path: '/xcat', secure:true }); -} - -/** - * Load service page - */ -function loadServicePage() { - // If the page is loaded - if ($('#content').children().length) { - // Do not load again - return; - } - - // Create manage and provision tabs - serviceTabs = new Tab(); - serviceTabs.init(); - $('#content').append(serviceTabs.object()); - - var manageTabId = 'manageTab'; - serviceTabs.add(manageTabId, 'Manage', '', false); - - // Get nodes owned by user - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'tabdump', - tgt : '', - args : 'nodetype', - msg : '' - }, - - success : function(data) { - setUserNodes(data); - setMaxVM(); - getUserNodesDef(); - getNodesCurrentLoad(); - loadManagePage(manageTabId); - } - }); - - // Get OS image names - $.ajax({ - url : 'lib/srv_cmd.php', - dataType : 'json', - async : true, - data : { - cmd : 'tabdump', - tgt : '', - args : 'osimage', - msg : '' - }, - - success : function(data) { - setOSImageCookies(data); - } - }); - - // Get contents of hosts table - $.ajax({ - url : 'lib/srv_cmd.php', - dataType : 'json', - async : true, - data : { - cmd : 'tabdump', - tgt : '', - args : 'hosts', - msg : '' - }, - - success : function(data) { - setGroupCookies(data); - } - }); - - var provTabId = 'provisionTab'; - serviceTabs.add(provTabId, 'Provision', '', false); - loadServiceProvisionPage(provTabId); - - serviceTabs.select(manageTabId); -} - -/** - * Load the service portal's provision page - * - * @param tabId Tab ID where page will reside - */ -function loadServiceProvisionPage(tabId) { - // Create info bar - var infoBar = createInfoBar('Select a platform to provision a node on, then click Ok.'); - - // Create provision page - var provPg = $('
                                      '); - $('#' + tabId).append(infoBar, provPg); - - // 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); - provPg.append(hwList); - - /** - * Ok - */ - var okBtn = createButton('Ok'); - okBtn.bind('click', function(event) { - var userName = $.cookie('xcat_username'); - var tmp = $.cookie('xcat_' + userName + '_usrnodes'); - - // Get maximun number for nodes from cookie - var nodes = ''; - var maxVM = 0; - if (tmp.length) { - nodes = tmp.split(','); - maxVM = parseInt($.cookie('xcat_' + userName + '_maxvm')); - - // Do not allow user to clone if the maximum number of VMs is reached - if (nodes.length >= maxVM) { - var warn = createWarnBar('You have reached the maximum number of virtual machines allowed (' + maxVM + '). Delete unused virtual machines or contact your system administrator request more virtual machines.'); - warn.prependTo($('#' + tabId)); - return; - } - } - - // Get hardware that was selected - var hw = $(this).parent().find('input[name="hw"]:checked').val(); - var newTabId = hw + 'ProvisionTab'; - - if ($('#' + newTabId).size() > 0){ - serviceTabs.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 "blade": - plugin = new bladePlugin(); - title = 'BladeCenter'; - break; - case "hmc": - plugin = new hmcPlugin(); - title = 'System p'; - break; - case "ipmi": - plugin = new ipmiPlugin(); - title = 'iDataPlex'; - break; - case "zvm": - plugin = new zvmPlugin(); - title = 'z/VM'; - - // Get zVM host names - $.ajax({ - url : 'lib/srv_cmd.php', - dataType : 'json', - async : false, - data : { - cmd : 'webportal', - tgt : '', - args : 'lszvm', - msg : '' - }, - - success : function(data) { - setzVMCookies(data); - } - }); - - // Get master copies for clone - $.ajax({ - url : 'lib/srv_cmd.php', - dataType : 'json', - async : false, - data : { - cmd : 'webportal', - tgt : '', - args : 'lsgoldenimages', - msg : '' - }, - - success : function(data) { - setGoldenImagesCookies(data); - } - }); - - break; - } - - // Select tab - serviceTabs.add(newTabId, title, '', true); - serviceTabs.select(newTabId); - plugin.loadServiceProvisionPage(newTabId); - } - }); - provPg.append(okBtn); -} - -/** - * Load manage page - * - * @param tabId Tab ID where page will reside - */ -function loadManagePage(tabId) { - // Create manage form - var manageForm = $('
                                      '); - - // Append to manage tab - $('#' + tabId).append(manageForm); -} - -/** - * Get the user nodes definitions - */ -function getUserNodesDef() { - var userName = $.cookie('xcat_username'); - var userNodes = $.cookie('xcat_' + userName + '_usrnodes'); - if (userNodes) { - // Get nodes definitions - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'lsdef', - tgt : '', - args : userNodes, - msg : '' - }, - - success : loadNodesTable - }); - } else { - // Clear the tab before inserting the table - $('#manageTab').append(createWarnBar('No nodes were found belonging to you!')); - } -} - -/** - * Load user nodes definitions into a table - * - * @param data Data from HTTP request - */ -function loadNodesTable(data) { - // Clear the tab before inserting the table - $('#manageTab').children().remove(); - - // Nodes datatable ID - var nodesDTId = 'userNodesDT'; - - // Hash of node attributes - var attrs = new Object(); - // Node attributes - var headers = new Object(); - var node = null, args; - // Create hash of node attributes - for (var i in data.rsp) { - // Get node name - if (data.rsp[i].indexOf('Object name:') > -1) { - var temp = data.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 = data.rsp[i].split('=', 2); - var key = jQuery.trim(args[0]); - var val = jQuery.trim(data.rsp[i].substring(data.rsp[i].indexOf('=') + 1, data.rsp[i].length)); - - // Create a hash table - attrs[node][key] = val; - headers[key] = 1; - } - - // Sort headers - var sorted = new Array(); - var attrs2show = new Array('arch', 'groups', 'hcp', 'hostnames', 'ip', 'os', 'userid', 'mgt'); - for (var key in headers) { - // Show node attributes - if (jQuery.inArray(key, attrs2show) > -1) { - sorted.push(key); - } - } - sorted.sort(); - - // Add column for check box, node, ping, power, monitor, and comments - sorted.unshift('', - 'node', - 'status', - 'power', - 'monitor', - 'comments'); - - // Create a datatable - var nodesDT = new DataTable(nodesDTId); - nodesDT.init(sorted); - - // Go through each node - for (var node in attrs) { - // Create a row - var row = new Array(); - - // Create a check box, node link, and get node status - var checkBx = $(''); - var nodeLink = $('' + node + '').bind('click', loadNode); - - // If there is no status attribute for the node, do not try to access hash table - // Else the code will break - var status = ''; - if (attrs[node]['status']) { - status = attrs[node]['status'].replace('sshd', 'ping'); - } - - // Push in checkbox, node, status, monitor, and power - row.push(checkBx, nodeLink, status, '', ''); - - // If the node attributes are known (i.e the group is known) - if (attrs[node]['groups']) { - // Put in comments - var comments = attrs[node]['usercomment']; - // If no comments exists, show 'No comments' and set icon image source - var iconSrc; - if (!comments) { - comments = 'No comments'; - iconSrc = 'images/nodes/ui-icon-no-comment.png'; - } else { - iconSrc = 'images/nodes/ui-icon-comment.png'; - } - - // Create comments icon - var tipID = node + 'Tip'; - var icon = $('').css({ - 'width': '18px', - 'height': '18px' - }); - - // Create tooltip - var tip = createCommentsToolTip(comments); - var col = $('').append(icon); - col.append(tip); - row.push(col); - - // Generate tooltips - icon.tooltip({ - position: "center right", - offset: [-2, 10], - effect: "fade", - opacity: 0.8, - relative: true, - delay: 500 - }); - } else { - // Do not put in comments if attributes are not known - row.push(''); - } - - // Go through each header - for (var i = 6; i < sorted.length; i++) { - // Add the node attributes to the row - var key = sorted[i]; - - // Do not put comments and status in twice - if (key != 'usercomment' && key != 'status' && key.indexOf('statustime') < 0) { - var val = attrs[node][key]; - if (val) { - row.push($('' + val + '')); - } else { - row.push(''); - } - } - } - - // Add the row to the table - nodesDT.add(row); - } - - // Create info bar - var infoBar = createInfoBar('Manage and monitor your virtual machines.'); - $('#manageTab').append(infoBar); - - // Insert action bar and nodes datatable - $('#manageTab').append(nodesDT.object()); - - // Turn table into a datatable - $('#' + nodesDTId).dataTable({ - 'iDisplayLength': 50, - 'bLengthChange': false, - "bScrollCollapse": true, - "sScrollY": "400px", - "sScrollX": "110%", - "bAutoWidth": true, - "oLanguage": { - "oPaginate": { - "sNext": "", - "sPrevious": "" - } - } - }); - - // Set datatable header class to add color - // $('.datatable thead').attr('class', 'ui-widget-header'); - - // Do not sort ping, power, and comment column - $('#' + nodesDTId + ' thead tr th').click(function() { - getNodeAttrs(group); - }); - var checkboxCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(0)'); - var pingCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); - var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); - var monitorCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); - var commentCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(5)'); - checkboxCol.unbind('click'); - pingCol.unbind('click'); - powerCol.unbind('click'); - monitorCol.unbind('click'); - commentCol.unbind('click'); - - // Refresh the node ping, power, and monitor status on-click - var nodes = getNodesShown(nodesDTId); - pingCol.find('span a').click(function() { - refreshNodeStatus(nodes); - }); - powerCol.find('span a').click(function() { - refreshPowerStatus(nodes); - }); - monitorCol.find('span a').click(function() { - refreshGangliaStatus(nodes); - }); - - // Create actions menu - // Power on - var powerOnLnk = $('Power on'); - powerOnLnk.click(function() { - var tgtNodes = getNodesChecked(nodesDTId); - if (tgtNodes) { - powerNode(tgtNodes, 'on'); - } - }); - - // Power off - var powerOffLnk = $('Power off'); - powerOffLnk.click(function() { - var tgtNodes = getNodesChecked(nodesDTId); - if (tgtNodes) { - powerNode(tgtNodes, 'off'); - } - }); - - // Power softoff - var powerSoftoffLnk = $('Shutdown'); - powerSoftoffLnk.click(function() { - var tgtNodes = getNodesChecked(nodesDTId); - if (tgtNodes) { - powerNode(tgtNodes, 'softoff'); - } - }); - - // Clone - var cloneLnk = $('Clone'); - cloneLnk.click(function() { - var tgtNodes = getNodesChecked(nodesDTId); - if (tgtNodes) { - cloneNode(tgtNodes); - } - }); - - // Delete - var deleteLnk = $('Delete'); - deleteLnk.click(function() { - var tgtNodes = getNodesChecked(nodesDTId); - if (tgtNodes) { - deleteNode(tgtNodes); - } - }); - - // Unlock - var unlockLnk = $('Unlock'); - unlockLnk.click(function() { - var tgtNodes = getNodesChecked(nodesDTId); - if (tgtNodes) { - unlockNode(tgtNodes); - } - }); - - // Create action bar - var actionBar = $('
                                      ').css('width', '370px'); - - // Prepend menu to datatable - var actionsLnk = $('Actions'); - var refreshLnk = $('Refresh'); - refreshLnk.click(function() { - // Get nodes owned by user - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'tabdump', - tgt : '', - args : 'nodetype', - msg : '' - }, - - success : function(data) { - // Save nodes owned by user - setUserNodes(data); - getNodesCurrentLoad(); - - // Refresh nodes table - var userName = $.cookie('xcat_username'); - var userNodes = $.cookie('xcat_' + userName + '_usrnodes'); - if (userNodes) { - // Get nodes definitions - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'lsdef', - tgt : '', - args : userNodes, - msg : '' - }, - - success : loadNodesTable - }); - } else { - // Clear the tab before inserting the table - $('#manageTab').children().remove(); - $('#manageTab').append(createWarnBar('You are not managing any node. Try to provision a node.')); - } - } - }); - }); - - var actionMenu = createMenu([cloneLnk, deleteLnk, powerOnLnk, powerOffLnk, powerSoftoffLnk, unlockLnk]); - var menu = createMenu([[actionsLnk, actionMenu], refreshLnk]); - menu.superfish(); - actionBar.append(menu); - - // Set correct theme for action menu - actionMenu.find('li').hover(function() { - setMenu2Theme($(this)); - }, function() { - setMenu2Normal($(this)); - }); - - // Create a division to hold actions menu - var menuDiv = $(''); - $('#' + nodesDTId + '_wrapper').prepend(menuDiv); - menuDiv.append(actionBar); - $('#' + nodesDTId + '_filter').appendTo(menuDiv); - - // Get power and monitor status - var nodes = getNodesShown(nodesDTId); - refreshPowerStatus(nodes); - refreshGangliaStatus(nodes); -} - -/** - * Refresh ping status for each node - * - * @param nodes Nodes to get ping status - */ -function refreshNodeStatus(nodes) { - // Show ping loader - var nodesDTId = 'userNodesDT'; - var pingCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); - pingCol.find('img').show(); - - // Get the node ping status - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'nodestat', - tgt : nodes, - args : '-u', - msg : '' - }, - - success : loadNodePing - }); -} - -/** - * Load node ping status for each node - * - * @param data Data returned from HTTP request - */ -function loadNodePing(data) { - var nodesDTId = 'userNodesDT'; - var datatable = $('#' + nodesDTId).dataTable(); - var rsp = data.rsp; - var args, rowPos, node, status; - - // Get all nodes within datatable - for (var i in rsp) { - args = rsp[i].split(':'); - - // args[0] = node and args[1] = status - node = jQuery.trim(args[0]); - status = jQuery.trim(args[1]).replace('sshd', 'ping'); - - // Get row containing node - rowPos = findRow(node, '#' + nodesDTId, 1); - - // Update ping status column - datatable.fnUpdate(status, rowPos, 2, false); - } - - // Hide status loader - var pingCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); - pingCol.find('img').hide(); - adjustColumnSize(nodesDTId); -} - -/** - * Refresh power status for each node - * - * @param nodes Nodes to get power status - */ -function refreshPowerStatus(nodes) { - // Show power loader - var nodesDTId = 'userNodesDT'; - var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); - powerCol.find('img').show(); - - // Get power status - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'rpower', - tgt : nodes, - args : 'stat', - msg : '' - }, - - success : loadPowerStatus - }); -} - -/** - * Load power status for each node - * - * @param data Data returned from HTTP request - */ -function loadPowerStatus(data) { - var nodesDTId = 'userNodesDT'; - var datatable = $('#' + nodesDTId).dataTable(); - var power = data.rsp; - var rowPos, node, status, args; - - for (var i in power) { - // power[0] = nodeName and power[1] = state - args = power[i].split(':'); - node = jQuery.trim(args[0]); - status = jQuery.trim(args[1]); - - // Get the row containing the node - rowPos = findRow(node, '#' + nodesDTId, 1); - - // Update the power status column - datatable.fnUpdate(status, rowPos, 3, false); - } - - // Hide power loader - var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); - powerCol.find('img').hide(); - adjustColumnSize(nodesDTId); -} - -/** - * Refresh the status of Ganglia for each node - * - * @param nodes Nodes to get Ganglia status - */ -function refreshGangliaStatus(nodes) { - // Show ganglia loader - var nodesDTId = 'userNodesDT'; - var gangliaCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); - gangliaCol.find('img').show(); - - // Get the status of Ganglia - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'gangliastatus;' + nodes, - msg : '' - }, - - success : loadGangliaStatus - }); -} - -/** - * Load the status of Ganglia for a given group - * - * @param data Data returned from HTTP request - */ -function loadGangliaStatus(data) { - // Get datatable - var nodesDTId = 'userNodesDT'; - var datatable = $('#' + nodesDTId).dataTable(); - var ganglia = data.rsp; - var rowNum, node, status; - - for ( var i in ganglia) { - // ganglia[0] = nodeName and ganglia[1] = state - node = jQuery.trim(ganglia[i][0]); - status = jQuery.trim(ganglia[i][1]); - - if (node) { - // Get the row containing the node - rowNum = findRow(node, '#' + nodesDTId, 1); - - // Update the power status column - datatable.fnUpdate(status, rowNum, 4); - } - } - - // Hide Ganglia loader - var gangliaCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); - gangliaCol.find('img').hide(); - adjustColumnSize(nodesDTId); -} - -/** - * Load inventory for given node - * - * @param e Windows event - */ -function loadNode(e) { - if (!e) { - e = window.event; - } - - // Get node that was clicked - var node = (e.target) ? e.target.id : e.srcElement.id; - - // Create a new tab to show inventory - var tabId = node + '_inventory'; - - if(!$('#' + tabId).length) { - // Add new tab, only if one does not exist - var loader = createLoader(node + 'Loader'); - loader = $('
                                      ').append(loader); - serviceTabs.add(tabId, node, loader, true); - - // Get node inventory - var msg = 'out=' + tabId + ',node=' + node; - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'rinv', - tgt : node, - args : 'all', - msg : msg - }, - - success : function(data) { - var args = data.msg.split(','); - - // Get node - var node = args[1].replace('node=', ''); - - // Get the management plugin - var mgt = getNodeAttr(node, 'mgt'); - - // Create an instance of the plugin - var plugin; - switch (mgt) { - case "kvm": - plugin = new kvmPlugin(); - break; - case "esx": - plugin = new esxPlugin(); - break; - case "zvm": - plugin = new zvmPlugin(); - break; - } - - // Select tab - plugin.loadServiceInventory(data); - } - }); - } - - // Select new tab - serviceTabs.select(tabId); -} - -/** - * Set a cookie for group names - * - * @param data Data from HTTP request - */ -function setGroupCookies(data) { - if (data.rsp) { - var groups = new Array(); - - // Index 0 is the table header - var cols, name, ip, hostname, desc, selectable, comments, tmp; - for (var i = 1; i < data.rsp.length; i++) { - // Set default description and selectable - selectable = "no"; - desc = "No description"; - - // Split into columns: - // node, ip, hostnames, otherinterfaces, comments, disable - cols = data.rsp[i].split(','); - name = cols[0].replace(new RegExp('"', 'g'), ''); - ip = cols[1].replace(new RegExp('"', 'g'), ''); - hostname = cols[2].replace(new RegExp('"', 'g'), ''); - - // It should return: "description: All machines; network: 10.1.100.0/24;" - comments = cols[4].replace(new RegExp('"', 'g'), ''); - 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); - } - } - - // Save groups that are selectable - if (selectable == "yes") - groups.push(name + ':' + ip + ':' + hostname + ':' + desc); - } - - // Set cookie to expire in 60 minutes - var exDate = new Date(); - exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); - $.cookie('xcat_srv_groups', groups, { expires: exDate, path: '/xcat', secure:true }); - } -} - -/** - * Set a cookie for the OS images - * - * @param data Data from HTTP request - */ -function setOSImageCookies(data) { - // Get response - var rsp = data.rsp; - - var imageNames = new Array(); - var profilesHash = new Object(); - var osVersHash = new Object(); - var osArchsHash = new Object(); - var imagePos = 0; - var profilePos = 0; - var osversPos = 0; - var osarchPos = 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 '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 osImage = 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 osComments = cols[comments].replace(new RegExp('"', 'g'), ''); - - // Only save install boot - if (provMethod.indexOf('install') > -1) { - if (osComments) { - // Only enable images where description and selectable comments exist - // Set default description and selectable - selectable = "no"; - desc = "No description"; - - 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); - } - } - - // Save images that are selectable - if (selectable == "yes") - imageNames.push(osImage + ':' + desc); - } - - profilesHash[profile] = 1; - osVersHash[osVer] = 1; - osArchsHash[osArch] = 1; - } - } - - // Save image names in a cookie - $.cookie('xcat_srv_imagenames', imageNames); - - // Save profiles in a cookie - var tmp = new Array; - for (var key in profilesHash) { - tmp.push(key); - } - $.cookie('xcat_srv_profiles', tmp); - - // Save OS versions in a cookie - tmp = new Array; - for (var key in osVersHash) { - tmp.push(key); - } - $.cookie('xcat_srv_osvers', tmp); - - // Save OS architectures in a cookie - tmp = new Array; - for (var key in osArchsHash) { - tmp.push(key); - } - $.cookie('xcat_srv_osarchs', tmp); -} - - - -/** - * Set a cookie for user nodes - * - * @param data Data from HTTP request - */ -function setUserNodes(data) { - if (data.rsp) { - // Get user name that is logged in - var userName = $.cookie('xcat_username'); - var usrNodes = new Array(); - - // Ignore first columns because it is the header - for ( var i = 1; i < data.rsp.length; i++) { - // Go through each column - // where column names are: node, os, arch, profile, provmethod, supportedarchs, nodetype, comments, disable - var cols = data.rsp[i].split(','); - var node = cols[0].replace(new RegExp('"', 'g'), ''); - - // Comments can contain the owner and description - var comments = new Array(); - if (cols[7].indexOf(';') > -1) { - comments = cols[7].replace(new RegExp('"', 'g'), '').split(';'); - } else { - comments.push(cols[7].replace(new RegExp('"', 'g'), '')); - } - - // Extract the owner - var owner; - for (var j in comments) { - if (comments[j].indexOf('owner:') > -1) { - owner = comments[j].replace('owner:', ''); - - if (owner == userName) { - usrNodes.push(node); - } - - break; - } - } - } // End of for - - // Set cookie to expire in 240 minutes - var exDate = new Date(); - exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); - $.cookie('xcat_' + userName + '_usrnodes', usrNodes, { expires: exDate, path: '/xcat', secure:true }); - } // End of if -} - -/** - * Power on a given node - * - * @param tgtNodes Node to power on or off - * @param power2 Power node to given state - */ -function powerNode(tgtNodes, power2) { - // Show power loader - var nodesDTId = 'userNodesDT'; - var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); - powerCol.find('img').show(); - - var nodes = tgtNodes.split(','); - for (var n in nodes) { - // Get hardware that was selected - var hw = getUserNodeAttr(nodes[n], 'mgt'); - - // Change to power softoff (to gracefully shutdown) - switch (hw) { - case "blade": - break; - case "hmc": - break; - case "ipmi": - break; - case "zvm": - if (power2 == 'off') { - power2 = 'softoff'; - } - - break; - } - } - - $.ajax({ - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'rpower', - tgt : tgtNodes, - args : power2, - msg : tgtNodes - }, - - success : updatePowerStatus - }); -} - -/** - * Update power status of a node in the datatable - * - * @param data Data from HTTP request - */ -function updatePowerStatus(data) { - // Get datatable - var nodesDTId = 'userNodesDT'; - var dTable = $('#' + nodesDTId).dataTable(); - - // Get xCAT response - var rsp = data.rsp; - // Loop through each line - var node, status, rowPos, strPos; - for (var i in rsp) { - // Get node name - node = rsp[i].split(":")[0]; - - // If there is no error - if (rsp[i].indexOf("Error") < 0 || rsp[i].indexOf("Failed") < 0) { - // Get the row containing the node link - rowPos = findRow(node, '#' + nodesDTId, 1); - - // If it was power on, then the data return would contain "Starting" - strPos = rsp[i].indexOf("Starting"); - if (strPos > -1) { - status = 'on'; - } else { - status = 'off'; - } - - // Update the power status column - dTable.fnUpdate(status, rowPos, 3, false); - } else { - // Power on/off failed - alert(rsp[i]); - } - } - - var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); - powerCol.find('img').hide(); - adjustColumnSize(nodesDTId); -} - -/** - * Turn on monitoring for a given node - * - * @param node Node to monitor on or off - * @param monitor Monitor state, on or off - */ -function monitorNode(node, monitor) { - // Show ganglia loader - var nodesDTId = 'userNodesDT'; - var gangliaCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); - gangliaCol.find('img').show(); - - if (monitor == 'on') { - if (node) { - // Check if ganglia RPMs are installed - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'gangliacheck;' + node, - msg : node // Node range will be passed along in data.msg - }, - - /** - * Start ganglia on a given node range - * - * @param data - * Data returned from HTTP request - * @return Nothing - */ - success : function(data) { - // Get response - var out = data.rsp[0].split(/\n/); - - // Go through each line - var warn = false; - var warningMsg = ''; - for (var i in out) { - // If an RPM is not installed - if (out[i].indexOf('not installed') > -1) { - warn = true; - - if (warningMsg) { - warningMsg += '
                                      ' + out[i]; - } else { - warningMsg = out[i]; - } - } - } - - // If there are warnings - if (warn) { - // Create warning bar - var warningBar = createWarnBar(warningMsg); - warningBar.css('margin-bottom', '10px'); - warningBar.prependTo($('#nodesTab')); - } else { - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'gangliastart;' + data.msg, - msg : data.msg - }, - - success : function(data) { - // Remove any warnings - $('#nodesTab').find('.ui-state-error').remove(); - refreshGangliaStatus(data.msg); - } - }); - } // End of if (warn) - } // End of function(data) - }); - } - } else { - var args; - if (node) { - args = 'gangliastop;' + node; - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : args, - msg : node - }, - - success : function(data) { - refreshGangliaStatus(data.msg); - } - }); - } - } -} - -/** - * Open a dialog to clone node - * - * @param tgtNodes Nodes to clone - */ -function cloneNode(tgtNodes) { - var userName = $.cookie('xcat_username'); - var nodes = tgtNodes.split(','); - var tmp = $.cookie('xcat_' + userName + '_usrnodes'); - var usrNodes = tmp.split(','); - - var maxVM = parseInt($.cookie('xcat_' + userName + '_maxvm')); - - // Do not allow user to clone if the maximum number of VMs is reached - if (usrNodes.length >= maxVM) { - var warn = createWarnBar('You have reached the maximum number of virtual machines allowed (' + maxVM + '). Delete un-used virtual machines or contact your system administrator request more virtual machines.'); - warn.prependTo($('#manageTab')); - return; - } - - for (var n in nodes) { - // Get hardware that was selected - var hw = getUserNodeAttr(nodes[n], 'mgt'); - - // Create an instance of the plugin - var plugin; - switch (hw) { - case "kvm": - plugin = new kvmPlugin(); - break; - case "esx": - plugin = new esxPlugin(); - break; - case "zvm": - plugin = new zvmPlugin(); - break; - } - - // Clone node - plugin.serviceClone(nodes[n]); - } -} - - -/** - * Open a dialog to delete node - * - * @param tgtNodes Nodes to delete - */ -function deleteNode(tgtNodes) { - var nodes = tgtNodes.split(','); - - // Loop through each node and create target nodes string - var tgtNodesStr = ''; - for (var i in nodes) { - if (i == 0 && i == nodes.length - 1) { - // If it is the 1st and only node - tgtNodesStr += nodes[i]; - } else if (i == 0 && i != nodes.length - 1) { - // If it is the 1st node of many nodes, append a comma to the string - tgtNodesStr += nodes[i] + ', '; - } else { - if (i == nodes.length - 1) { - // If it is the last node, append nothing to the string - tgtNodesStr += nodes[i]; - } else { - // Append a comma to the string - tgtNodesStr += nodes[i] + ', '; - } - } - } - - // Confirm delete of node - var dialog = $('
                                      '); - var warn = createWarnBar('Are you sure you want to delete ' + tgtNodesStr + '?'); - dialog.append(warn); - - // Open dialog - dialog.dialog({ - title: "Confirm", - modal: true, - close: function(){ - $(this).remove(); - }, - width: 400, - buttons: { - "Yes": function(){ - // Create status bar and append to tab - var instance = 0; - var statBarId = 'deleteStat' + instance; - while ($('#' + statBarId).length) { - // If one already exists, generate another one - instance = instance + 1; - statBarId = 'deleteStat' + instance; - } - - var statBar = createStatusBar(statBarId); - var loader = createLoader(''); - statBar.find('div').append(loader); - statBar.prependTo($('#manageTab')); - - // Delete the virtual server - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'rmvm', - tgt : tgtNodes, - args : '', - msg : 'out=' + statBarId + ';cmd=rmvm;tgt=' + tgtNodes - }, - - success : function(data) { - var args = data.msg.split(';'); - var statBarId = args[0].replace('out=', ''); - var tgts = args[2].replace('tgt=', '').split(','); - - // Get data table - var nodesDTId = 'userNodesDT'; - var dTable = $('#' + nodesDTId).dataTable(); - var failed = false; - - // Create an info box to show output - var output = writeRsp(data.rsp, ''); - output.css('margin', '0px'); - // Remove loader and append output - $('#' + statBarId + ' img').remove(); - $('#' + statBarId + ' div').append(output); - - // If there was an error, do not continue - if (output.html().indexOf('Error') > -1) { - failed = true; - } - - // Update data table - var rowPos; - for (var i in tgts) { - if (!failed) { - // Get row containing the node link and delete it - rowPos = findRow(tgts[i], '#' + nodesDTId, 1); - dTable.fnDeleteRow(rowPos); - } - } - - // Refresh nodes owned by user - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'tabdump', - tgt : '', - args : 'nodetype', - msg : '' - }, - - success : function(data) { - setUserNodes(data); - } - }); - } - }); - - $(this).dialog("close"); - }, - "No": function() { - $(this).dialog("close"); - } - } - }); -} - -/** - * Unlock a node by setting the ssh keys - * - * @param tgtNodes Nodes to unlock - */ -function unlockNode(tgtNodes) { - var nodes = tgtNodes.split(','); - - // Loop through each node and create target nodes string - var tgtNodesStr = ''; - for (var i in nodes) { - if (i == 0 && i == nodes.length - 1) { - // If it is the 1st and only node - tgtNodesStr += nodes[i]; - } else if (i == 0 && i != nodes.length - 1) { - // If it is the 1st node of many nodes, append a comma to the string - tgtNodesStr += nodes[i] + ', '; - } else { - if (i == nodes.length - 1) { - // If it is the last node, append nothing to the string - tgtNodesStr += nodes[i]; - } else { - // Append a comma to the string - tgtNodesStr += nodes[i] + ', '; - } - } - } - - var dialog = $('
                                      '); - var infoBar = createInfoBar('Give the root password for this node range to setup its SSH keys.'); - dialog.append(infoBar); - - var unlockForm = $('
                                      ').css('margin', '5px'); - unlockForm.append('
                                      '); - unlockForm.append('
                                      '); - dialog.append(unlockForm); - - dialog.find('div input').css('margin', '5px'); - - // Generate tooltips - unlockForm.find('div input[title]').tooltip({ - position: "center right", - offset: [-2, 10], - effect: "fade", - opacity: 0.7, - predelay: 800, - events : { - def : "mouseover,mouseout", - input : "mouseover,mouseout", - widget : "focus mouseover,blur mouseout", - tooltip : "mouseover,mouseout" - } - }); - - // Open dialog - dialog.dialog({ - title: "Confirm", - modal: true, - close: function(){ - $(this).remove(); - }, - width: 450, - buttons: { - "Ok": function(){ - // Create status bar and append to tab - var instance = 0; - var statBarId = 'unlockStat' + instance; - while ($('#' + statBarId).length) { - // If one already exists, generate another one - instance = instance + 1; - statBarId = 'unlockStat' + instance; - } - - var statBar = createStatusBar(statBarId); - var loader = createLoader(''); - statBar.find('div').append(loader); - statBar.prependTo($('#manageTab')); - - // If a password is given - var password = unlockForm.find('input[name=password]:eq(0)'); - if (password.val()) { - // Setup SSH keys - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'unlock;' + tgtNodes + ';' + password.val(), - msg : 'out=' + statBarId + ';cmd=unlock;tgt=' + tgtNodes - }, - - success : function(data) { - // Create an info box to show output - var output = writeRsp(data.rsp, ''); - output.css('margin', '0px'); - // Remove loader and append output - $('#' + statBarId + ' img').remove(); - $('#' + statBarId + ' div').append(output); - } - }); - - $(this).dialog("close"); - } - }, - "Cancel": function() { - $(this).dialog("close"); - } - } - }); -} - -/** - * Get nodes current load information - */ -function getNodesCurrentLoad(){ - var userName = $.cookie('xcat_username'); - var nodes = $.cookie('xcat_' + userName + '_usrnodes'); - - // Get nodes current status - $.ajax({ - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'gangliacurrent;node;' + nodes, - msg : '' - }, - - success: saveNodeLoad - }); -} - -/** - * Save node load data - * - * @param status Data returned from HTTP request - */ -function saveNodeLoad(status){ - // Save node path and status for future use - nodePath = new Object(); - nodeStatus = new Object(); - - // Get nodes status - var nodes = status.rsp[0].split(';'); - - var i = 0, pos = 0; - var node = '', tmpStr = ''; - var tmpArry; - - for (i = 0; i < nodes.length; i++){ - tmpStr = nodes[i]; - pos = tmpStr.indexOf(':'); - node = tmpStr.substring(0, pos); - tmpArry = tmpStr.substring(pos + 1).split(','); - - switch(tmpArry[0]){ - case 'UNKNOWN':{ - nodeStatus[node] = -2; - } - break; - case 'ERROR':{ - nodeStatus[node] = -1; - } - break; - case 'WARNING':{ - nodeStatus[node] = 0; - nodePath[node] = tmpArry[1]; - } - break; - case 'NORMAL':{ - nodeStatus[node] = 1; - nodePath[node] = tmpArry[1]; - } - break; - } - } -} - -/** - * Get monitoring metrics and load into inventory fieldset - * - * @param node Node to collect metrics - */ -function getMonitorMetrics(node) { - // Inventory tab should have this fieldset already created - // e.g.
                                      - $('#' + node + '_monitor').children('div').remove(); - - // Before trying to get the metrics, check if Ganglia is running - $.ajax({ - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'gangliastatus;' + node, - msg : '' - }, - - success: function(data) { - var ganglia = data.rsp; - var node, status; - - // Get the ganglia status - for (var i in ganglia) { - // ganglia[0] = nodeName and ganglia[1] = state - node = jQuery.trim(ganglia[i][0]); - status = jQuery.trim(ganglia[i][1]); - - if (node && status == 'on') { - // Get monitoring metrics - $.ajax({ - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'gangliashow;' + nodePath[node] + ';hour;_summary_', - msg : node - }, - - success: drawMonitoringCharts - }); - } else if (node && status == 'off') { - var info = createInfoBar('Ganglia monitoring is disabled for this node'); - $('#' + node + '_monitor').append(info.css('width', '300px')); - } - } // End of for - } // End of function - }); -} - -/** - * Draw monitoring charts based on node metrics - * - * @param data Data returned from HTTP request - */ -function drawMonitoringCharts(data){ - var nodeMetrics = new Object(); - var metricData = data.rsp[0].split(';'); - var node = data.msg; - - var metricName = ''; - var metricVal = ''; - var pos = 0; - - // Go through the metrics returned - for (var m = 0; m < metricData.length; m++){ - pos = metricData[m].indexOf(':'); - - // Get metric name - metricName = metricData[m].substr(0, pos); - nodeMetrics[metricName] = new Array(); - // Get metric values - metricVal = metricData[m].substr(pos + 1).split(','); - // Save node metrics - for (var i = 0; i < metricVal.length; i++){ - nodeMetrics[metricName].push(Number(metricVal[i])); - } - } - - drawLoadFlot(node, nodeMetrics['load_one'], nodeMetrics['cpu_num']); - drawCpuFlot(node, nodeMetrics['cpu_idle']); - drawMemFlot(node, nodeMetrics['mem_free'], nodeMetrics['mem_total']); - drawDiskFlot(node, nodeMetrics['disk_free'], nodeMetrics['disk_total']); - drawNetworkFlot(node, nodeMetrics['bytes_in'], nodeMetrics['bytes_out']); -} - -/** - * Draw load metrics flot - * - * @param node Node name - * @param loadpair Load timestamp and value pair - * @param cpupair CPU number and value pair - */ -function drawLoadFlot(node, loadPair, cpuPair){ - var load = new Array(); - var cpu = new Array(); - - var i = 0; - var yAxisMax = 0; - var interval = 1; - - // Append flot to node monitoring fieldset - var loadFlot = $('
                                      ').css({ - 'float': 'left', - 'height': '150px', - 'margin': '0 0 10px', - 'width': '300px' - }); - $('#' + node + '_monitor').append(loadFlot); - $('#' + node + '_load').empty(); - - // Parse load pair where: - // timestamp must be mutiplied by 1000 and Javascript timestamp is in ms - for (i = 0; i < loadPair.length; i += 2){ - load.push([loadPair[i] * 1000, loadPair[i + 1]]); - if (loadPair[i + 1] > yAxisMax){ - yAxisMax = loadPair[i + 1]; - } - } - - // Parse CPU pair - for (i = 0; i < cpuPair.length; i += 2){ - cpu.push([cpuPair[i] * 1000, cpuPair[i + 1]]); - if (cpuPair[i + 1] > yAxisMax){ - yAxisMax = cpuPair[i + 1]; - } - } - - interval = parseInt(yAxisMax / 3); - if (interval < 1){ - interval = 1; - } - - $.jqplot(node + '_load', [load, cpu],{ - title: ' Loads/Procs Last Hour', - axes:{ - xaxis:{ - renderer : $.jqplot.DateAxisRenderer, - numberTicks: 4, - tickOptions : { - formatString : '%R', - show : true - } - }, - yaxis: { - min : 0, - tickInterval : interval - } - }, - legend : { - show: true, - location: 'nw' - }, - series:[{label:'Load'}, {label: 'CPU Number'}], - seriesDefaults : {showMarker: false} - }); -} - -/** - * Draw CPU usage flot - * - * @param node Node name - * @param cpuPair CPU timestamp and value pair - */ -function drawCpuFlot(node, cpuPair){ - var cpu = new Array(); - - // Append flot to node monitoring fieldset - var cpuFlot = $('
                                      ').css({ - 'float': 'left', - 'height': '150px', - 'margin': '0 0 10px', - 'width': '300px' - }); - $('#' + node + '_monitor').append(cpuFlot); - $('#' + node + '_cpu').empty(); - - // Time stamp should by mutiplied by 1000 - // CPU idle comes from server, subtract 1 from idle - for(var i = 0; i < cpuPair.length; i +=2){ - cpu.push([(cpuPair[i] * 1000), (100 - cpuPair[i + 1])]); - } - - $.jqplot(node + '_cpu', [cpu],{ - title: 'CPU Use Last Hour', - axes:{ - xaxis:{ - renderer : $.jqplot.DateAxisRenderer, - numberTicks: 4, - tickOptions : { - formatString : '%R', - show : true - } - }, - yaxis: { - min : 0, - max : 100, - tickOptions:{formatString : '%d\%'} - } - }, - seriesDefaults : {showMarker: false} - }); -} - -/** - * Draw memory usage flot - * - * @param node Node name - * @param freePair Free memory timestamp and value pair - * @param totalPair Total memory timestamp and value pair - */ -function drawMemFlot(node, freePair, totalPair){ - var used = new Array(); - var total = new Array(); - var size = 0; - - // Append flot to node monitoring fieldset - var memoryFlot = $('
                                      ').css({ - 'float': 'left', - 'height': '150px', - 'margin': '0 0 10px', - 'width': '300px' - }); - $('#' + node + '_monitor').append(memoryFlot); - $('#' + node + '_memory').empty(); - - if(freePair.length < totalPair.length){ - size = freePair.length; - } else { - size = freePair.length; - } - - var tmpTotal, tmpUsed; - for(var i = 0; i < size; i+=2){ - tmpTotal = totalPair[i+1]; - tmpUsed = tmpTotal-freePair[i+1]; - tmpTotal = tmpTotal/1000000; - tmpUsed = tmpUsed/1000000; - total.push([totalPair[i]*1000, tmpTotal]); - used.push([freePair[i]*1000, tmpUsed]); - } - - $.jqplot(node + '_memory', [used, total],{ - title: 'Memory Use Last Hour', - axes:{ - xaxis:{ - renderer : $.jqplot.DateAxisRenderer, - numberTicks: 4, - tickOptions : { - formatString : '%R', - show : true - } - }, - yaxis: { - min : 0, - tickOptions:{formatString : '%.2fG'} - } - }, - legend : { - show: true, - location: 'nw' - }, - series:[{label:'Used'}, {label: 'Total'}], - seriesDefaults : {showMarker: false} - }); -} - -/** - * Draw disk usage flot - * - * @param node Node name - * @param freePair Free disk space (Ganglia only logs free data) - * @param totalPair Total disk space - */ -function drawDiskFlot(node, freePair, totalPair) { - var used = new Array(); - var total = new Array(); - var size = 0; - - // Append flot to node monitoring fieldset - var diskFlot = $('
                                      ').css({ - 'float' : 'left', - 'height' : '150px', - 'margin' : '0 0 10px', - 'width' : '300px' - }); - $('#' + node + '_monitor').append(diskFlot); - $('#' + node + '_disk').empty(); - - if (freePair.length < totalPair.length) { - size = freePair.length; - } else { - size = freePair.length; - } - - var tmpTotal, tmpUsed; - for ( var i = 0; i < size; i += 2) { - tmpTotal = totalPair[i + 1]; - tmpUsed = tmpTotal - freePair[i + 1]; - total.push([ totalPair[i] * 1000, tmpTotal ]); - used.push([ freePair[i] * 1000, tmpUsed ]); - } - - $.jqplot(node + '_disk', [ used, total ], { - title : 'Disk Use Last Hour', - axes : { - xaxis : { - renderer : $.jqplot.DateAxisRenderer, - numberTicks : 4, - tickOptions : { - formatString : '%R', - show : true - } - }, - yaxis : { - min : 0, - tickOptions : { - formatString : '%.2fG' - } - } - }, - legend : { - show : true, - location : 'nw' - }, - series : [ { - label : 'Used' - }, { - label : 'Total' - } ], - seriesDefaults : { - showMarker : false - } - }); -} - -/** - * Draw network usage flot - * - * @param node Node name - * @param freePair Free memory timestamp and value pair - * @param totalPair Total memory timestamp and value pair - */ -function drawNetworkFlot(node, inPair, outPair) { - var inArray = new Array(); - var outArray = new Array(); - var maxVal = 0; - var unitName = 'B'; - var divisor = 1; - - // Append flot to node monitoring fieldset - var diskFlot = $('
                                      ').css({ - 'float' : 'left', - 'height' : '150px', - 'margin' : '0 0 10px', - 'width' : '300px' - }); - $('#' + node + '_monitor').append(diskFlot); - $('#' + node + '_network').empty(); - - for (var i = 0; i < inPair.length; i += 2) { - if (inPair[i + 1] > maxVal) { - maxVal = inPair[i + 1]; - } - } - - for (var i = 0; i < outPair.length; i += 2) { - if (outPair[i + 1] > maxVal) { - maxVal = outPair[i + 1]; - } - } - - if (maxVal > 3000000) { - divisor = 1000000; - unitName = 'GB'; - } else if (maxVal >= 3000) { - divisor = 1000; - unitName = 'MB'; - } else { - // Do nothing - } - - for (i = 0; i < inPair.length; i += 2) { - inArray.push([ (inPair[i] * 1000), (inPair[i + 1] / divisor) ]); - } - - for (i = 0; i < outPair.length; i += 2) { - outArray.push([ (outPair[i] * 1000), (outPair[i + 1] / divisor) ]); - } - - $.jqplot(node + '_network', [ inArray, outArray ], { - title : 'Network Last Hour', - axes : { - xaxis : { - renderer : $.jqplot.DateAxisRenderer, - numberTicks : 4, - tickOptions : { - formatString : '%R', - show : true - } - }, - yaxis : { - min : 0, - tickOptions : { - formatString : '%d' + unitName - } - } - }, - legend : { - show : true, - location : 'nw' - }, - series : [ { - label : 'In' - }, { - label : 'Out' - } ], - seriesDefaults : { - showMarker : false - } - }); -} - -/** - * Get an attribute of a given node - * - * @param node The node - * @param attrName The attribute - * @return The attribute of the node - */ -function getNodeAttr(node, attrName) { - // Get the row - var row = $('[id=' + node + ']').parents('tr'); - - // Search for the column containing the attribute - var attrCol = null; - - var cols = row.parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr:eq(0) th'); - // Loop through each column - for (var i in cols) { - // Find column that matches the attribute - if (cols.eq(i).html() == attrName) { - attrCol = cols.eq(i); - break; - } - } - - // If the column containing the attribute is found - if (attrCol) { - // Get the attribute column index - var attrIndex = attrCol.index(); - - // Get the attribute for the given node - var attr = row.find('td:eq(' + attrIndex + ')'); - return attr.text(); - } else { - return ''; - } -} - -/** - * Set the maximum number of VMs a user could have - */ -function setMaxVM() { - var userName = $.cookie('xcat_username'); - - $.ajax( { - url : 'lib/srv_cmd.php', - dataType : 'json', - data : { - cmd : 'webportal', - tgt : '', - args : 'getmaxvm;' + userName, - msg : '' - }, - - success : function(data) { - // Get response - var rsp = jQuery.trim(data.rsp); - rsp = rsp.replace('Max allowed:', ''); - - // Set cookie to expire in 60 minutes - var exDate = new Date(); - exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); - $.cookie('xcat_' + userName + '_maxvm', rsp, { expires: exDate }); - } - }); +/** + * Global variables + */ +var serviceTabs; +var nodeName; +var nodePath; +var nodeStatus; +var gangliaTimer; + +/** + * Initialize service page + */ +function initServicePage() { + // Load theme + var theme = $.cookie('xcat_theme'); + if (theme) { + switch (theme) { + case 'cupertino': + includeCss("css/themes/jquery-ui-cupertino.css"); + break; + case 'dark_hive': + includeCss("css/themes/jquery-ui-dark_hive.css"); + break; + case 'redmond': + includeCss("css/themes/jquery-ui-redmond.css"); + break; + case 'start': + includeCss("css/themes/jquery-ui-start.css"); + break; + case 'sunny': + includeCss("css/themes/jquery-ui-sunny.css"); + break; + case 'ui_dark': + includeCss("css/themes/jquery-ui-ui_darkness.css"); + break; + default: + includeCss("css/themes/jquery-ui-start.css"); + } + } else { + includeCss("css/themes/jquery-ui-start.css"); + } + + // Load jQuery stylesheets + includeCss("css/jquery.dataTables.css"); + includeCss("css/superfish.css"); + includeCss("css/jstree.css"); + includeCss("css/jquery.jqplot.css"); + + // Load custom stylesheet + includeCss("css/style.css"); + + // Reuqired JQuery plugins + includeJs("js/jquery/jquery.dataTables.min.js"); + includeJs("js/jquery/jquery.cookie.min.js"); + includeJs("js/jquery/tooltip.min.js"); + includeJs("js/jquery/superfish.min.js"); + includeJs("js/jquery/jquery.jqplot.min.js"); + includeJs("js/jquery/jqplot.dateAxisRenderer.min.js"); + + // Custom plugins + includeJs("js/custom/esx.js"); + includeJs("js/custom/kvm.js"); + includeJs("js/custom/zvm.js"); + + // Enable settings link + $('#xcat_settings').click(function() { + openSettings(); + }); + + // Show service page + $("#content").children().remove(); + includeJs("js/service/utils.js"); + loadServicePage(); + + // Initialize tab index history + $.cookie('xcat_tabindex_history', '0,0', { path: '/xcat', secure:true }); +} + +/** + * Load service page + */ +function loadServicePage() { + // If the page is loaded + if ($('#content').children().length) { + // Do not load again + return; + } + + // Create manage and provision tabs + serviceTabs = new Tab(); + serviceTabs.init(); + $('#content').append(serviceTabs.object()); + + var manageTabId = 'manageTab'; + serviceTabs.add(manageTabId, 'Manage', '', false); + + // Get nodes owned by user + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'nodetype', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setUserNodes(data); + setMaxVM(); + getUserNodesDef(); + getNodesCurrentLoad(); + loadManagePage(manageTabId); + } + }); + + // Get OS image names + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + async : true, + data : { + cmd : 'tabdump', + tgt : '', + args : 'osimage', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setOSImageCookies(data); + } + }); + + // Get contents of hosts table + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + async : true, + data : { + cmd : 'tabdump', + tgt : '', + args : 'hosts', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setGroupCookies(data); + } + }); + + var provTabId = 'provisionTab'; + serviceTabs.add(provTabId, 'Provision', '', false); + loadServiceProvisionPage(provTabId); + + serviceTabs.select(manageTabId); +} + +/** + * Load the service portal's provision page + * + * @param tabId Tab ID where page will reside + */ +function loadServiceProvisionPage(tabId) { + // Create info bar + var infoBar = createInfoBar('Select a platform to provision a node on, then click Ok.'); + + // Create provision page + var provPg = $('
                                      '); + $('#' + tabId).append(infoBar, provPg); + + // 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); + provPg.append(hwList); + + /** + * Ok + */ + var okBtn = createButton('Ok'); + okBtn.bind('click', function(event) { + var userName = $.cookie('xcat_username'); + var tmp = $.cookie('xcat_' + userName + '_usrnodes'); + + // Get maximun number for nodes from cookie + var nodes = ''; + var maxVM = 0; + if (tmp.length) { + nodes = tmp.split(','); + maxVM = parseInt($.cookie('xcat_' + userName + '_maxvm')); + + // Do not allow user to clone if the maximum number of VMs is reached + if (nodes.length >= maxVM) { + var warn = createWarnBar('You have reached the maximum number of virtual machines allowed (' + maxVM + '). Delete unused virtual machines or contact your system administrator request more virtual machines.'); + warn.prependTo($('#' + tabId)); + return; + } + } + + // Get hardware that was selected + var hw = $(this).parent().find('input[name="hw"]:checked').val(); + var newTabId = hw + 'ProvisionTab'; + + if ($('#' + newTabId).size() > 0){ + serviceTabs.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 "blade": + plugin = new bladePlugin(); + title = 'BladeCenter'; + break; + case "hmc": + plugin = new hmcPlugin(); + title = 'System p'; + break; + case "ipmi": + plugin = new ipmiPlugin(); + title = 'iDataPlex'; + break; + case "zvm": + plugin = new zvmPlugin(); + title = 'z/VM'; + + // Get zVM host names + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + async : false, + data : { + cmd : 'webportal', + tgt : '', + args : 'lszvm', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setzVMCookies(data); + } + }); + + // Get master copies for clone + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + async : false, + data : { + cmd : 'webportal', + tgt : '', + args : 'lsgoldenimages', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setGoldenImagesCookies(data); + } + }); + + break; + } + + // Select tab + serviceTabs.add(newTabId, title, '', true); + serviceTabs.select(newTabId); + plugin.loadServiceProvisionPage(newTabId); + } + }); + provPg.append(okBtn); +} + +/** + * Load manage page + * + * @param tabId Tab ID where page will reside + */ +function loadManagePage(tabId) { + // Create manage form + var manageForm = $('
                                      '); + + // Append to manage tab + $('#' + tabId).append(manageForm); +} + +/** + * Get the user nodes definitions + */ +function getUserNodesDef() { + var userName = $.cookie('xcat_username'); + var userNodes = $.cookie('xcat_' + userName + '_usrnodes'); + if (userNodes) { + // Get nodes definitions + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'lsdef', + tgt : '', + args : userNodes, + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadNodesTable(data); + } + }); + } else { + // Clear the tab before inserting the table + $('#manageTab').append(createWarnBar('No nodes were found belonging to you!')); + } +} + +/** + * Load user nodes definitions into a table + * + * @param data Data from HTTP request + */ +function loadNodesTable(data) { + // Clear the tab before inserting the table + $('#manageTab').children().remove(); + + // Nodes datatable ID + var nodesDTId = 'userNodesDT'; + + // Hash of node attributes + var attrs = new Object(); + // Node attributes + var headers = new Object(); + var node = null, args; + // Create hash of node attributes + for (var i in data.rsp) { + // Get node name + if (data.rsp[i].indexOf('Object name:') > -1) { + var temp = data.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 = data.rsp[i].split('=', 2); + var key = jQuery.trim(args[0]); + var val = jQuery.trim(data.rsp[i].substring(data.rsp[i].indexOf('=') + 1, data.rsp[i].length)); + + // Create a hash table + attrs[node][key] = val; + headers[key] = 1; + } + + // Sort headers + var sorted = new Array(); + var attrs2show = new Array('arch', 'groups', 'hcp', 'hostnames', 'ip', 'os', 'userid', 'mgt'); + for (var key in headers) { + // Show node attributes + if (jQuery.inArray(key, attrs2show) > -1) { + sorted.push(key); + } + } + sorted.sort(); + + // Add column for check box, node, ping, power, monitor, and comments + sorted.unshift('', + 'node', + 'status', + 'power', + 'monitor', + 'comments'); + + // Create a datatable + var nodesDT = new DataTable(nodesDTId); + nodesDT.init(sorted); + + // Go through each node + for (var node in attrs) { + // Create a row + var row = new Array(); + + // Create a check box, node link, and get node status + var checkBx = $(''); + var nodeLink = $('' + node + '').bind('click', loadNode); + + // If there is no status attribute for the node, do not try to access hash table + // Else the code will break + var status = ''; + if (attrs[node]['status']) { + status = attrs[node]['status'].replace('sshd', 'ping'); + } + + // Push in checkbox, node, status, monitor, and power + row.push(checkBx, nodeLink, status, '', ''); + + // If the node attributes are known (i.e the group is known) + if (attrs[node]['groups']) { + // Put in comments + var comments = attrs[node]['usercomment']; + // If no comments exists, show 'No comments' and set icon image source + var iconSrc; + if (!comments) { + comments = 'No comments'; + iconSrc = 'images/nodes/ui-icon-no-comment.png'; + } else { + iconSrc = 'images/nodes/ui-icon-comment.png'; + } + + // Create comments icon + var tipID = node + 'Tip'; + var icon = $('').css({ + 'width': '18px', + 'height': '18px' + }); + + // Create tooltip + var tip = createCommentsToolTip(comments); + var col = $('').append(icon); + col.append(tip); + row.push(col); + + // Generate tooltips + icon.tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.8, + relative: true, + delay: 500 + }); + } else { + // Do not put in comments if attributes are not known + row.push(''); + } + + // Go through each header + for (var i = 6; i < sorted.length; i++) { + // Add the node attributes to the row + var key = sorted[i]; + + // Do not put comments and status in twice + if (key != 'usercomment' && key != 'status' && key.indexOf('statustime') < 0) { + var val = attrs[node][key]; + if (val) { + row.push($('' + val + '')); + } else { + row.push(''); + } + } + } + + // Add the row to the table + nodesDT.add(row); + } + + // Create info bar + var infoBar = createInfoBar('Manage and monitor your virtual machines.'); + $('#manageTab').append(infoBar); + + // Insert action bar and nodes datatable + $('#manageTab').append(nodesDT.object()); + + // Turn table into a datatable + $('#' + nodesDTId).dataTable({ + 'iDisplayLength': 50, + 'bLengthChange': false, + "bScrollCollapse": true, + "sScrollY": "400px", + "sScrollX": "110%", + "bAutoWidth": true, + "oLanguage": { + "oPaginate": { + "sNext": "", + "sPrevious": "" + } + } + }); + + // Set datatable header class to add color + // $('.datatable thead').attr('class', 'ui-widget-header'); + + // Do not sort ping, power, and comment column + $('#' + nodesDTId + ' thead tr th').click(function() { + getNodeAttrs(group); + }); + var checkboxCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(0)'); + var pingCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); + var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + var monitorCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + var commentCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(5)'); + checkboxCol.unbind('click'); + pingCol.unbind('click'); + powerCol.unbind('click'); + monitorCol.unbind('click'); + commentCol.unbind('click'); + + // Refresh the node ping, power, and monitor status on-click + var nodes = getNodesShown(nodesDTId); + pingCol.find('span a').click(function() { + refreshNodeStatus(nodes); + }); + powerCol.find('span a').click(function() { + refreshPowerStatus(nodes); + }); + monitorCol.find('span a').click(function() { + refreshGangliaStatus(nodes); + }); + + // Create actions menu + // Power on + var powerOnLnk = $('Power on'); + powerOnLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + powerNode(tgtNodes, 'on'); + } + }); + + // Power off + var powerOffLnk = $('Power off'); + powerOffLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + powerNode(tgtNodes, 'off'); + } + }); + + // Power softoff + var powerSoftoffLnk = $('Shutdown'); + powerSoftoffLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + powerNode(tgtNodes, 'softoff'); + } + }); + + // Clone + var cloneLnk = $('Clone'); + cloneLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + cloneNode(tgtNodes); + } + }); + + // Delete + var deleteLnk = $('Delete'); + deleteLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + deleteNode(tgtNodes); + } + }); + + // Unlock + var unlockLnk = $('Unlock'); + unlockLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + unlockNode(tgtNodes); + } + }); + + // Create action bar + var actionBar = $('
                                      ').css('width', '370px'); + + // Prepend menu to datatable + var actionsLnk = $('Actions'); + var refreshLnk = $('Refresh'); + refreshLnk.click(function() { + // Get nodes owned by user + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'nodetype', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + // Save nodes owned by user + setUserNodes(data); + getNodesCurrentLoad(); + + // Refresh nodes table + var userName = $.cookie('xcat_username'); + var userNodes = $.cookie('xcat_' + userName + '_usrnodes'); + if (userNodes) { + // Get nodes definitions + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'lsdef', + tgt : '', + args : userNodes, + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadNodesTable(data); + } + }); + } else { + // Clear the tab before inserting the table + $('#manageTab').children().remove(); + $('#manageTab').append(createWarnBar('You are not managing any node. Try to provision a node.')); + } + } + }); + }); + + var actionMenu = createMenu([cloneLnk, deleteLnk, powerOnLnk, powerOffLnk, powerSoftoffLnk, unlockLnk]); + var menu = createMenu([[actionsLnk, actionMenu], refreshLnk]); + menu.superfish(); + actionBar.append(menu); + + // Set correct theme for action menu + actionMenu.find('li').hover(function() { + setMenu2Theme($(this)); + }, function() { + setMenu2Normal($(this)); + }); + + // Create a division to hold actions menu + var menuDiv = $(''); + $('#' + nodesDTId + '_wrapper').prepend(menuDiv); + menuDiv.append(actionBar); + $('#' + nodesDTId + '_filter').appendTo(menuDiv); + + // Get power and monitor status + var nodes = getNodesShown(nodesDTId); + refreshPowerStatus(nodes); + refreshGangliaStatus(nodes); +} + +/** + * Refresh ping status for each node + * + * @param nodes Nodes to get ping status + */ +function refreshNodeStatus(nodes) { + // Show ping loader + var nodesDTId = 'userNodesDT'; + var pingCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); + pingCol.find('img').show(); + + // Get the node ping status + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'nodestat', + tgt : nodes, + args : '-u', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadNodePing(data); + } + }); +} + +/** + * Load node ping status for each node + * + * @param data Data returned from HTTP request + */ +function loadNodePing(data) { + var nodesDTId = 'userNodesDT'; + var datatable = $('#' + nodesDTId).dataTable(); + var rsp = data.rsp; + var args, rowPos, node, status; + + // Get all nodes within datatable + for (var i in rsp) { + args = rsp[i].split(':'); + + // args[0] = node and args[1] = status + node = jQuery.trim(args[0]); + status = jQuery.trim(args[1]).replace('sshd', 'ping'); + + // Get row containing node + rowPos = findRow(node, '#' + nodesDTId, 1); + + // Update ping status column + datatable.fnUpdate(status, rowPos, 2, false); + } + + // Hide status loader + var pingCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(2)'); + pingCol.find('img').hide(); + adjustColumnSize(nodesDTId); +} + +/** + * Refresh power status for each node + * + * @param nodes Nodes to get power status + */ +function refreshPowerStatus(nodes) { + // Show power loader + var nodesDTId = 'userNodesDT'; + var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + powerCol.find('img').show(); + + // Get power status + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'rpower', + tgt : nodes, + args : 'stat', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadPowerStatus(data); + } + }); +} + +/** + * Load power status for each node + * + * @param data Data returned from HTTP request + */ +function loadPowerStatus(data) { + var nodesDTId = 'userNodesDT'; + var datatable = $('#' + nodesDTId).dataTable(); + var power = data.rsp; + var rowPos, node, status, args; + + for (var i in power) { + // power[0] = nodeName and power[1] = state + args = power[i].split(':'); + node = jQuery.trim(args[0]); + status = jQuery.trim(args[1]); + + // Get the row containing the node + rowPos = findRow(node, '#' + nodesDTId, 1); + + // Update the power status column + datatable.fnUpdate(status, rowPos, 3, false); + } + + // Hide power loader + var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + powerCol.find('img').hide(); + adjustColumnSize(nodesDTId); +} + +/** + * Refresh the status of Ganglia for each node + * + * @param nodes Nodes to get Ganglia status + */ +function refreshGangliaStatus(nodes) { + // Show ganglia loader + var nodesDTId = 'userNodesDT'; + var gangliaCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + gangliaCol.find('img').show(); + + // Get the status of Ganglia + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliastatus;' + nodes, + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + loadGangliaStatus(data); + } + }); +} + +/** + * Load the status of Ganglia for a given group + * + * @param data Data returned from HTTP request + */ +function loadGangliaStatus(data) { + // Get datatable + var nodesDTId = 'userNodesDT'; + var datatable = $('#' + nodesDTId).dataTable(); + var ganglia = data.rsp; + var rowNum, node, status; + + for ( var i in ganglia) { + // ganglia[0] = nodeName and ganglia[1] = state + node = jQuery.trim(ganglia[i][0]); + status = jQuery.trim(ganglia[i][1]); + + if (node) { + // Get the row containing the node + rowNum = findRow(node, '#' + nodesDTId, 1); + + // Update the power status column + datatable.fnUpdate(status, rowNum, 4); + } + } + + // Hide Ganglia loader + var gangliaCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + gangliaCol.find('img').hide(); + adjustColumnSize(nodesDTId); +} + +/** + * Load inventory for given node + * + * @param e Windows event + */ +function loadNode(e) { + if (!e) { + e = window.event; + } + + // Get node that was clicked + var node = (e.target) ? e.target.id : e.srcElement.id; + + // Create a new tab to show inventory + var tabId = node + '_inventory'; + + if(!$('#' + tabId).length) { + // Add new tab, only if one does not exist + var loader = createLoader(node + 'Loader'); + loader = $('
                                      ').append(loader); + serviceTabs.add(tabId, node, loader, true); + + // Get node inventory + var msg = 'out=' + tabId + ',node=' + node; + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'rinv', + tgt : node, + args : 'all', + msg : msg + }, + + success : function(data) { + data = decodeRsp(data); + var args = data.msg.split(','); + + // Get node + var node = args[1].replace('node=', ''); + + // Get the management plugin + var mgt = getNodeAttr(node, 'mgt'); + + // Create an instance of the plugin + var plugin; + switch (mgt) { + case "kvm": + plugin = new kvmPlugin(); + break; + case "esx": + plugin = new esxPlugin(); + break; + case "zvm": + plugin = new zvmPlugin(); + break; + } + + // Select tab + plugin.loadServiceInventory(data); + } + }); + } + + // Select new tab + serviceTabs.select(tabId); +} + +/** + * Set a cookie for group names + * + * @param data Data from HTTP request + */ +function setGroupCookies(data) { + if (data.rsp) { + var groups = new Array(); + + // Index 0 is the table header + var cols, name, ip, hostname, desc, selectable, comments, tmp; + for (var i = 1; i < data.rsp.length; i++) { + // Set default description and selectable + selectable = "no"; + desc = "No description"; + + // Split into columns: + // node, ip, hostnames, otherinterfaces, comments, disable + cols = data.rsp[i].split(','); + name = cols[0].replace(new RegExp('"', 'g'), ''); + ip = cols[1].replace(new RegExp('"', 'g'), ''); + hostname = cols[2].replace(new RegExp('"', 'g'), ''); + + // It should return: "description: All machines; network: 10.1.100.0/24;" + comments = cols[4].replace(new RegExp('"', 'g'), ''); + 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); + } + } + + // Save groups that are selectable + if (selectable == "yes") + groups.push(name + ':' + ip + ':' + hostname + ':' + desc); + } + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); + $.cookie('xcat_srv_groups', groups, { expires: exDate, path: '/xcat', secure:true }); + } +} + +/** + * Set a cookie for the OS images + * + * @param data Data from HTTP request + */ +function setOSImageCookies(data) { + // Get response + var rsp = data.rsp; + + var imageNames = new Array(); + var profilesHash = new Object(); + var osVersHash = new Object(); + var osArchsHash = new Object(); + var imagePos = 0; + var profilePos = 0; + var osversPos = 0; + var osarchPos = 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 '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 osImage = 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 osComments = cols[comments].replace(new RegExp('"', 'g'), ''); + + // Only save install boot + if (provMethod.indexOf('install') > -1) { + if (osComments) { + // Only enable images where description and selectable comments exist + // Set default description and selectable + selectable = "no"; + desc = "No description"; + + 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); + } + } + + // Save images that are selectable + if (selectable == "yes") + imageNames.push(osImage + ':' + desc); + } + + profilesHash[profile] = 1; + osVersHash[osVer] = 1; + osArchsHash[osArch] = 1; + } + } + + // Save image names in a cookie + $.cookie('xcat_srv_imagenames', imageNames); + + // Save profiles in a cookie + var tmp = new Array; + for (var key in profilesHash) { + tmp.push(key); + } + $.cookie('xcat_srv_profiles', tmp); + + // Save OS versions in a cookie + tmp = new Array; + for (var key in osVersHash) { + tmp.push(key); + } + $.cookie('xcat_srv_osvers', tmp); + + // Save OS architectures in a cookie + tmp = new Array; + for (var key in osArchsHash) { + tmp.push(key); + } + $.cookie('xcat_srv_osarchs', tmp); +} + + + +/** + * Set a cookie for user nodes + * + * @param data Data from HTTP request + */ +function setUserNodes(data) { + if (data.rsp) { + // Get user name that is logged in + var userName = $.cookie('xcat_username'); + var usrNodes = new Array(); + + // Ignore first columns because it is the header + for ( var i = 1; i < data.rsp.length; i++) { + // Go through each column + // where column names are: node, os, arch, profile, provmethod, supportedarchs, nodetype, comments, disable + var cols = data.rsp[i].split(','); + var node = cols[0].replace(new RegExp('"', 'g'), ''); + + // Comments can contain the owner and description + var comments = new Array(); + if (cols[7].indexOf(';') > -1) { + comments = cols[7].replace(new RegExp('"', 'g'), '').split(';'); + } else { + comments.push(cols[7].replace(new RegExp('"', 'g'), '')); + } + + // Extract the owner + var owner; + for (var j in comments) { + if (comments[j].indexOf('owner:') > -1) { + owner = comments[j].replace('owner:', ''); + + if (owner == userName) { + usrNodes.push(node); + } + + break; + } + } + } // End of for + + // Set cookie to expire in 240 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); + $.cookie('xcat_' + userName + '_usrnodes', usrNodes, { expires: exDate, path: '/xcat', secure:true }); + } // End of if +} + +/** + * Power on a given node + * + * @param tgtNodes Node to power on or off + * @param power2 Power node to given state + */ +function powerNode(tgtNodes, power2) { + // Show power loader + var nodesDTId = 'userNodesDT'; + var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + powerCol.find('img').show(); + + var nodes = tgtNodes.split(','); + for (var n in nodes) { + // Get hardware that was selected + var hw = getUserNodeAttr(nodes[n], 'mgt'); + + // Change to power softoff (to gracefully shutdown) + switch (hw) { + case "blade": + break; + case "hmc": + break; + case "ipmi": + break; + case "zvm": + if (power2 == 'off') { + power2 = 'softoff'; + } + + break; + } + } + + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'rpower', + tgt : tgtNodes, + args : power2, + msg : tgtNodes + }, + + success : function(data) { + data = decodeRsp(data); + updatePowerStatus(data); + } + }); +} + +/** + * Update power status of a node in the datatable + * + * @param data Data from HTTP request + */ +function updatePowerStatus(data) { + // Get datatable + var nodesDTId = 'userNodesDT'; + var dTable = $('#' + nodesDTId).dataTable(); + + // Get xCAT response + var rsp = data.rsp; + // Loop through each line + var node, status, rowPos, strPos; + for (var i in rsp) { + // Get node name + node = rsp[i].split(":")[0]; + + // If there is no error + if (rsp[i].indexOf("Error") < 0 || rsp[i].indexOf("Failed") < 0) { + // Get the row containing the node link + rowPos = findRow(node, '#' + nodesDTId, 1); + + // If it was power on, then the data return would contain "Starting" + strPos = rsp[i].indexOf("Starting"); + if (strPos > -1) { + status = 'on'; + } else { + status = 'off'; + } + + // Update the power status column + dTable.fnUpdate(status, rowPos, 3, false); + } else { + // Power on/off failed + alert(rsp[i]); + } + } + + var powerCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(3)'); + powerCol.find('img').hide(); + adjustColumnSize(nodesDTId); +} + +/** + * Turn on monitoring for a given node + * + * @param node Node to monitor on or off + * @param monitor Monitor state, on or off + */ +function monitorNode(node, monitor) { + // Show ganglia loader + var nodesDTId = 'userNodesDT'; + var gangliaCol = $('#' + nodesDTId + '_wrapper .dataTables_scrollHead .datatable thead tr th:eq(4)'); + gangliaCol.find('img').show(); + + if (monitor == 'on') { + if (node) { + // Check if ganglia RPMs are installed + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliacheck;' + node, + msg : node // Node range will be passed along in data.msg + }, + + /** + * Start ganglia on a given node range + * + * @param data + * Data returned from HTTP request + * @return Nothing + */ + success : function(data) { + data = decodeRsp(data); + // Get response + var out = data.rsp[0].split(/\n/); + + // Go through each line + var warn = false; + var warningMsg = ''; + for (var i in out) { + // If an RPM is not installed + if (out[i].indexOf('not installed') > -1) { + warn = true; + + if (warningMsg) { + warningMsg += '
                                      ' + out[i]; + } else { + warningMsg = out[i]; + } + } + } + + // If there are warnings + if (warn) { + // Create warning bar + var warningBar = createWarnBar(warningMsg); + warningBar.css('margin-bottom', '10px'); + warningBar.prependTo($('#nodesTab')); + } else { + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliastart;' + data.msg, + msg : data.msg + }, + + success : function(data) { + data = decodeRsp(data); + // Remove any warnings + $('#nodesTab').find('.ui-state-error').remove(); + refreshGangliaStatus(data.msg); + } + }); + } // End of if (warn) + } // End of function(data) + }); + } + } else { + var args; + if (node) { + args = 'gangliastop;' + node; + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : args, + msg : node + }, + + success : function(data) { + data = decodeRsp(data); + refreshGangliaStatus(data.msg); + } + }); + } + } +} + +/** + * Open a dialog to clone node + * + * @param tgtNodes Nodes to clone + */ +function cloneNode(tgtNodes) { + var userName = $.cookie('xcat_username'); + var nodes = tgtNodes.split(','); + var tmp = $.cookie('xcat_' + userName + '_usrnodes'); + var usrNodes = tmp.split(','); + + var maxVM = parseInt($.cookie('xcat_' + userName + '_maxvm')); + + // Do not allow user to clone if the maximum number of VMs is reached + if (usrNodes.length >= maxVM) { + var warn = createWarnBar('You have reached the maximum number of virtual machines allowed (' + maxVM + '). Delete un-used virtual machines or contact your system administrator request more virtual machines.'); + warn.prependTo($('#manageTab')); + return; + } + + for (var n in nodes) { + // Get hardware that was selected + var hw = getUserNodeAttr(nodes[n], 'mgt'); + + // Create an instance of the plugin + var plugin; + switch (hw) { + case "kvm": + plugin = new kvmPlugin(); + break; + case "esx": + plugin = new esxPlugin(); + break; + case "zvm": + plugin = new zvmPlugin(); + break; + } + + // Clone node + plugin.serviceClone(nodes[n]); + } +} + + +/** + * Open a dialog to delete node + * + * @param tgtNodes Nodes to delete + */ +function deleteNode(tgtNodes) { + var nodes = tgtNodes.split(','); + + // Loop through each node and create target nodes string + var tgtNodesStr = ''; + for (var i in nodes) { + if (i == 0 && i == nodes.length - 1) { + // If it is the 1st and only node + tgtNodesStr += nodes[i]; + } else if (i == 0 && i != nodes.length - 1) { + // If it is the 1st node of many nodes, append a comma to the string + tgtNodesStr += nodes[i] + ', '; + } else { + if (i == nodes.length - 1) { + // If it is the last node, append nothing to the string + tgtNodesStr += nodes[i]; + } else { + // Append a comma to the string + tgtNodesStr += nodes[i] + ', '; + } + } + } + + // Confirm delete of node + var dialog = $('
                                      '); + var warn = createWarnBar('Are you sure you want to delete ' + tgtNodesStr + '?'); + dialog.append(warn); + + // Open dialog + dialog.dialog({ + title: "Confirm", + modal: true, + close: function(){ + $(this).remove(); + }, + width: 400, + buttons: { + "Yes": function(){ + // Create status bar and append to tab + var instance = 0; + var statBarId = 'deleteStat' + instance; + while ($('#' + statBarId).length) { + // If one already exists, generate another one + instance = instance + 1; + statBarId = 'deleteStat' + instance; + } + + var statBar = createStatusBar(statBarId); + var loader = createLoader(''); + statBar.find('div').append(loader); + statBar.prependTo($('#manageTab')); + + // Delete the virtual server + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'rmvm', + tgt : tgtNodes, + args : '', + msg : 'out=' + statBarId + ';cmd=rmvm;tgt=' + tgtNodes + }, + + success : function(data) { + data = decodeRsp(data); + var args = data.msg.split(';'); + var statBarId = args[0].replace('out=', ''); + var tgts = args[2].replace('tgt=', '').split(','); + + // Get data table + var nodesDTId = 'userNodesDT'; + var dTable = $('#' + nodesDTId).dataTable(); + var failed = false; + + // Create an info box to show output + var output = writeRsp(data.rsp, ''); + output.css('margin', '0px'); + // Remove loader and append output + $('#' + statBarId + ' img').remove(); + $('#' + statBarId + ' div').append(output); + + // If there was an error, do not continue + if (output.html().indexOf('Error') > -1) { + failed = true; + } + + // Update data table + var rowPos; + for (var i in tgts) { + if (!failed) { + // Get row containing the node link and delete it + rowPos = findRow(tgts[i], '#' + nodesDTId, 1); + dTable.fnDeleteRow(rowPos); + } + } + + // Refresh nodes owned by user + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'tabdump', + tgt : '', + args : 'nodetype', + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + setUserNodes(data); + } + }); + } + }); + + $(this).dialog("close"); + }, + "No": function() { + $(this).dialog("close"); + } + } + }); +} + +/** + * Unlock a node by setting the ssh keys + * + * @param tgtNodes Nodes to unlock + */ +function unlockNode(tgtNodes) { + var nodes = tgtNodes.split(','); + + // Loop through each node and create target nodes string + var tgtNodesStr = ''; + for (var i in nodes) { + if (i == 0 && i == nodes.length - 1) { + // If it is the 1st and only node + tgtNodesStr += nodes[i]; + } else if (i == 0 && i != nodes.length - 1) { + // If it is the 1st node of many nodes, append a comma to the string + tgtNodesStr += nodes[i] + ', '; + } else { + if (i == nodes.length - 1) { + // If it is the last node, append nothing to the string + tgtNodesStr += nodes[i]; + } else { + // Append a comma to the string + tgtNodesStr += nodes[i] + ', '; + } + } + } + + var dialog = $('
                                      '); + var infoBar = createInfoBar('Give the root password for this node range to setup its SSH keys.'); + dialog.append(infoBar); + + var unlockForm = $('
                                      ').css('margin', '5px'); + unlockForm.append('
                                      '); + unlockForm.append('
                                      '); + dialog.append(unlockForm); + + dialog.find('div input').css('margin', '5px'); + + // Generate tooltips + unlockForm.find('div input[title]').tooltip({ + position: "center right", + offset: [-2, 10], + effect: "fade", + opacity: 0.7, + predelay: 800, + events : { + def : "mouseover,mouseout", + input : "mouseover,mouseout", + widget : "focus mouseover,blur mouseout", + tooltip : "mouseover,mouseout" + } + }); + + // Open dialog + dialog.dialog({ + title: "Confirm", + modal: true, + close: function(){ + $(this).remove(); + }, + width: 450, + buttons: { + "Ok": function(){ + // Create status bar and append to tab + var instance = 0; + var statBarId = 'unlockStat' + instance; + while ($('#' + statBarId).length) { + // If one already exists, generate another one + instance = instance + 1; + statBarId = 'unlockStat' + instance; + } + + var statBar = createStatusBar(statBarId); + var loader = createLoader(''); + statBar.find('div').append(loader); + statBar.prependTo($('#manageTab')); + + // If a password is given + var password = unlockForm.find('input[name=password]:eq(0)'); + if (password.val()) { + // Setup SSH keys + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'unlock;' + tgtNodes + ';' + password.val(), + msg : 'out=' + statBarId + ';cmd=unlock;tgt=' + tgtNodes + }, + + success : function(data) { + data = decodeRsp(data); + // Create an info box to show output + var output = writeRsp(data.rsp, ''); + output.css('margin', '0px'); + // Remove loader and append output + $('#' + statBarId + ' img').remove(); + $('#' + statBarId + ' div').append(output); + } + }); + + $(this).dialog("close"); + } + }, + "Cancel": function() { + $(this).dialog("close"); + } + } + }); +} + +/** + * Get nodes current load information + */ +function getNodesCurrentLoad(){ + var userName = $.cookie('xcat_username'); + var nodes = $.cookie('xcat_' + userName + '_usrnodes'); + + // Get nodes current status + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliacurrent;node;' + nodes, + msg : '' + }, + + success: function(data) { + data = decodeRsp(data); + saveNodeLoad(data); + } + }); +} + +/** + * Save node load data + * + * @param status Data returned from HTTP request + */ +function saveNodeLoad(status){ + // Save node path and status for future use + nodePath = new Object(); + nodeStatus = new Object(); + + // Get nodes status + var nodes = status.rsp[0].split(';'); + + var i = 0, pos = 0; + var node = '', tmpStr = ''; + var tmpArry; + + for (i = 0; i < nodes.length; i++){ + tmpStr = nodes[i]; + pos = tmpStr.indexOf(':'); + node = tmpStr.substring(0, pos); + tmpArry = tmpStr.substring(pos + 1).split(','); + + switch(tmpArry[0]){ + case 'UNKNOWN':{ + nodeStatus[node] = -2; + } + break; + case 'ERROR':{ + nodeStatus[node] = -1; + } + break; + case 'WARNING':{ + nodeStatus[node] = 0; + nodePath[node] = tmpArry[1]; + } + break; + case 'NORMAL':{ + nodeStatus[node] = 1; + nodePath[node] = tmpArry[1]; + } + break; + } + } +} + +/** + * Get monitoring metrics and load into inventory fieldset + * + * @param node Node to collect metrics + */ +function getMonitorMetrics(node) { + // Inventory tab should have this fieldset already created + // e.g.
                                      + $('#' + node + '_monitor').children('div').remove(); + + // Before trying to get the metrics, check if Ganglia is running + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliastatus;' + node, + msg : '' + }, + + success: function(data) { + data = decodeRsp(data); + var ganglia = data.rsp; + var node, status; + + // Get the ganglia status + for (var i in ganglia) { + // ganglia[0] = nodeName and ganglia[1] = state + node = jQuery.trim(ganglia[i][0]); + status = jQuery.trim(ganglia[i][1]); + + if (node && status == 'on') { + // Get monitoring metrics + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'gangliashow;' + nodePath[node] + ';hour;_summary_', + msg : node + }, + + success: function(data) { + data = decodeRsp(data); + drawMonitoringCharts(data); + } + }); + } else if (node && status == 'off') { + var info = createInfoBar('Ganglia monitoring is disabled for this node'); + $('#' + node + '_monitor').append(info.css('width', '300px')); + } + } // End of for + } // End of function + }); +} + +/** + * Draw monitoring charts based on node metrics + * + * @param data Data returned from HTTP request + */ +function drawMonitoringCharts(data){ + var nodeMetrics = new Object(); + var metricData = data.rsp[0].split(';'); + var node = data.msg; + + var metricName = ''; + var metricVal = ''; + var pos = 0; + + // Go through the metrics returned + for (var m = 0; m < metricData.length; m++){ + pos = metricData[m].indexOf(':'); + + // Get metric name + metricName = metricData[m].substr(0, pos); + nodeMetrics[metricName] = new Array(); + // Get metric values + metricVal = metricData[m].substr(pos + 1).split(','); + // Save node metrics + for (var i = 0; i < metricVal.length; i++){ + nodeMetrics[metricName].push(Number(metricVal[i])); + } + } + + drawLoadFlot(node, nodeMetrics['load_one'], nodeMetrics['cpu_num']); + drawCpuFlot(node, nodeMetrics['cpu_idle']); + drawMemFlot(node, nodeMetrics['mem_free'], nodeMetrics['mem_total']); + drawDiskFlot(node, nodeMetrics['disk_free'], nodeMetrics['disk_total']); + drawNetworkFlot(node, nodeMetrics['bytes_in'], nodeMetrics['bytes_out']); +} + +/** + * Draw load metrics flot + * + * @param node Node name + * @param loadpair Load timestamp and value pair + * @param cpupair CPU number and value pair + */ +function drawLoadFlot(node, loadPair, cpuPair){ + var load = new Array(); + var cpu = new Array(); + + var i = 0; + var yAxisMax = 0; + var interval = 1; + + // Append flot to node monitoring fieldset + var loadFlot = $('
                                      ').css({ + 'float': 'left', + 'height': '150px', + 'margin': '0 0 10px', + 'width': '300px' + }); + $('#' + node + '_monitor').append(loadFlot); + $('#' + node + '_load').empty(); + + // Parse load pair where: + // timestamp must be mutiplied by 1000 and Javascript timestamp is in ms + for (i = 0; i < loadPair.length; i += 2){ + load.push([loadPair[i] * 1000, loadPair[i + 1]]); + if (loadPair[i + 1] > yAxisMax){ + yAxisMax = loadPair[i + 1]; + } + } + + // Parse CPU pair + for (i = 0; i < cpuPair.length; i += 2){ + cpu.push([cpuPair[i] * 1000, cpuPair[i + 1]]); + if (cpuPair[i + 1] > yAxisMax){ + yAxisMax = cpuPair[i + 1]; + } + } + + interval = parseInt(yAxisMax / 3); + if (interval < 1){ + interval = 1; + } + + $.jqplot(node + '_load', [load, cpu],{ + title: ' Loads/Procs Last Hour', + axes:{ + xaxis:{ + renderer : $.jqplot.DateAxisRenderer, + numberTicks: 4, + tickOptions : { + formatString : '%R', + show : true + } + }, + yaxis: { + min : 0, + tickInterval : interval + } + }, + legend : { + show: true, + location: 'nw' + }, + series:[{label:'Load'}, {label: 'CPU Number'}], + seriesDefaults : {showMarker: false} + }); +} + +/** + * Draw CPU usage flot + * + * @param node Node name + * @param cpuPair CPU timestamp and value pair + */ +function drawCpuFlot(node, cpuPair){ + var cpu = new Array(); + + // Append flot to node monitoring fieldset + var cpuFlot = $('
                                      ').css({ + 'float': 'left', + 'height': '150px', + 'margin': '0 0 10px', + 'width': '300px' + }); + $('#' + node + '_monitor').append(cpuFlot); + $('#' + node + '_cpu').empty(); + + // Time stamp should by mutiplied by 1000 + // CPU idle comes from server, subtract 1 from idle + for(var i = 0; i < cpuPair.length; i +=2){ + cpu.push([(cpuPair[i] * 1000), (100 - cpuPair[i + 1])]); + } + + $.jqplot(node + '_cpu', [cpu],{ + title: 'CPU Use Last Hour', + axes:{ + xaxis:{ + renderer : $.jqplot.DateAxisRenderer, + numberTicks: 4, + tickOptions : { + formatString : '%R', + show : true + } + }, + yaxis: { + min : 0, + max : 100, + tickOptions:{formatString : '%d\%'} + } + }, + seriesDefaults : {showMarker: false} + }); +} + +/** + * Draw memory usage flot + * + * @param node Node name + * @param freePair Free memory timestamp and value pair + * @param totalPair Total memory timestamp and value pair + */ +function drawMemFlot(node, freePair, totalPair){ + var used = new Array(); + var total = new Array(); + var size = 0; + + // Append flot to node monitoring fieldset + var memoryFlot = $('
                                      ').css({ + 'float': 'left', + 'height': '150px', + 'margin': '0 0 10px', + 'width': '300px' + }); + $('#' + node + '_monitor').append(memoryFlot); + $('#' + node + '_memory').empty(); + + if(freePair.length < totalPair.length){ + size = freePair.length; + } else { + size = freePair.length; + } + + var tmpTotal, tmpUsed; + for(var i = 0; i < size; i+=2){ + tmpTotal = totalPair[i+1]; + tmpUsed = tmpTotal-freePair[i+1]; + tmpTotal = tmpTotal/1000000; + tmpUsed = tmpUsed/1000000; + total.push([totalPair[i]*1000, tmpTotal]); + used.push([freePair[i]*1000, tmpUsed]); + } + + $.jqplot(node + '_memory', [used, total],{ + title: 'Memory Use Last Hour', + axes:{ + xaxis:{ + renderer : $.jqplot.DateAxisRenderer, + numberTicks: 4, + tickOptions : { + formatString : '%R', + show : true + } + }, + yaxis: { + min : 0, + tickOptions:{formatString : '%.2fG'} + } + }, + legend : { + show: true, + location: 'nw' + }, + series:[{label:'Used'}, {label: 'Total'}], + seriesDefaults : {showMarker: false} + }); +} + +/** + * Draw disk usage flot + * + * @param node Node name + * @param freePair Free disk space (Ganglia only logs free data) + * @param totalPair Total disk space + */ +function drawDiskFlot(node, freePair, totalPair) { + var used = new Array(); + var total = new Array(); + var size = 0; + + // Append flot to node monitoring fieldset + var diskFlot = $('
                                      ').css({ + 'float' : 'left', + 'height' : '150px', + 'margin' : '0 0 10px', + 'width' : '300px' + }); + $('#' + node + '_monitor').append(diskFlot); + $('#' + node + '_disk').empty(); + + if (freePair.length < totalPair.length) { + size = freePair.length; + } else { + size = freePair.length; + } + + var tmpTotal, tmpUsed; + for ( var i = 0; i < size; i += 2) { + tmpTotal = totalPair[i + 1]; + tmpUsed = tmpTotal - freePair[i + 1]; + total.push([ totalPair[i] * 1000, tmpTotal ]); + used.push([ freePair[i] * 1000, tmpUsed ]); + } + + $.jqplot(node + '_disk', [ used, total ], { + title : 'Disk Use Last Hour', + axes : { + xaxis : { + renderer : $.jqplot.DateAxisRenderer, + numberTicks : 4, + tickOptions : { + formatString : '%R', + show : true + } + }, + yaxis : { + min : 0, + tickOptions : { + formatString : '%.2fG' + } + } + }, + legend : { + show : true, + location : 'nw' + }, + series : [ { + label : 'Used' + }, { + label : 'Total' + } ], + seriesDefaults : { + showMarker : false + } + }); +} + +/** + * Draw network usage flot + * + * @param node Node name + * @param freePair Free memory timestamp and value pair + * @param totalPair Total memory timestamp and value pair + */ +function drawNetworkFlot(node, inPair, outPair) { + var inArray = new Array(); + var outArray = new Array(); + var maxVal = 0; + var unitName = 'B'; + var divisor = 1; + + // Append flot to node monitoring fieldset + var diskFlot = $('
                                      ').css({ + 'float' : 'left', + 'height' : '150px', + 'margin' : '0 0 10px', + 'width' : '300px' + }); + $('#' + node + '_monitor').append(diskFlot); + $('#' + node + '_network').empty(); + + for (var i = 0; i < inPair.length; i += 2) { + if (inPair[i + 1] > maxVal) { + maxVal = inPair[i + 1]; + } + } + + for (var i = 0; i < outPair.length; i += 2) { + if (outPair[i + 1] > maxVal) { + maxVal = outPair[i + 1]; + } + } + + if (maxVal > 3000000) { + divisor = 1000000; + unitName = 'GB'; + } else if (maxVal >= 3000) { + divisor = 1000; + unitName = 'MB'; + } else { + // Do nothing + } + + for (i = 0; i < inPair.length; i += 2) { + inArray.push([ (inPair[i] * 1000), (inPair[i + 1] / divisor) ]); + } + + for (i = 0; i < outPair.length; i += 2) { + outArray.push([ (outPair[i] * 1000), (outPair[i + 1] / divisor) ]); + } + + $.jqplot(node + '_network', [ inArray, outArray ], { + title : 'Network Last Hour', + axes : { + xaxis : { + renderer : $.jqplot.DateAxisRenderer, + numberTicks : 4, + tickOptions : { + formatString : '%R', + show : true + } + }, + yaxis : { + min : 0, + tickOptions : { + formatString : '%d' + unitName + } + } + }, + legend : { + show : true, + location : 'nw' + }, + series : [ { + label : 'In' + }, { + label : 'Out' + } ], + seriesDefaults : { + showMarker : false + } + }); +} + +/** + * Get an attribute of a given node + * + * @param node The node + * @param attrName The attribute + * @return The attribute of the node + */ +function getNodeAttr(node, attrName) { + // Get the row + var row = $('[id=' + node + ']').parents('tr'); + + // Search for the column containing the attribute + var attrCol = null; + + var cols = row.parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr:eq(0) th'); + // Loop through each column + for (var i in cols) { + // Find column that matches the attribute + if (cols.eq(i).html() == attrName) { + attrCol = cols.eq(i); + break; + } + } + + // If the column containing the attribute is found + if (attrCol) { + // Get the attribute column index + var attrIndex = attrCol.index(); + + // Get the attribute for the given node + var attr = row.find('td:eq(' + attrIndex + ')'); + return attr.text(); + } else { + return ''; + } +} + +/** + * Set the maximum number of VMs a user could have + */ +function setMaxVM() { + var userName = $.cookie('xcat_username'); + + $.ajax( { + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webportal', + tgt : '', + args : 'getmaxvm;' + userName, + msg : '' + }, + + success : function(data) { + data = decodeRsp(data); + // Get response + var rsp = jQuery.trim(data.rsp); + rsp = rsp.replace('Max allowed:', ''); + + // Set cookie to expire in 60 minutes + var exDate = new Date(); + exDate.setTime(exDate.getTime() + (240 * 60 * 1000)); + $.cookie('xcat_' + userName + '_maxvm', rsp, { expires: exDate }); + } + }); } \ No newline at end of file diff --git a/xCAT-UI/js/ui.js b/xCAT-UI/js/ui.js index 771fa5d65..3b5da6ba2 100644 --- a/xCAT-UI/js/ui.js +++ b/xCAT-UI/js/ui.js @@ -1,1068 +1,1101 @@ -/** - * Tab constructor - * - * @param tabId - * Tab ID - * @param tabName - * Tab name - * @return Nothing - */ -var Tab = function(tabId) { - this.tabId = tabId; - this.tabName = null; - this.tab = null; -}; - -/** - * Initialize the tab - * - * @param tabName Tab name to initialize - */ -Tab.prototype.init = function() { - // Create a division containing the tab - this.tab = $('
                                      '); - var tabList = $('
                                        '); - var tabItem = $('
                                      • Dummy tab item
                                      • '); - tabList.append(tabItem); - this.tab.append(tabList); - - // Create a template with close button - var tabs = this.tab.tabs(); - - tabs.bind('tabsselect', function(event, ui){ - // Save the order tabs were selected - var order; - if ($.cookie('xcat_tabindex_history')) { - order = $.cookie('xcat_tabindex_history').split(','); - order[1] = order[0]; // Set index 1 to last selected tab - order[0] = ui.index; // Set index 0 to currently selected tab - } else { - // Create an array to track the tab selected - order = new Array; - order[0] = ui.index; - order[1] = ui.index; - } - - $.cookie('xcat_tabindex_history', order, { path: '/xcat', secure:true }); - }); - - // Remove dummy tab - this.tab.tabs("remove", 0); - - // Hide tab - this.tab.hide(); -}; - -/** - * Return the tab object - * - * @return Object representing the tab - */ -Tab.prototype.object = function() { - return this.tab; -}; - -/** - * Add a new tab - * - * @param tabId Tab ID - * @param tabName Tab name - * @param tabCont Tab content - * @param closeable Is tab closeable - */ -Tab.prototype.add = function(tabId, tabName, tabCont, closeable) { - // Show tab - if (this.tab.css("display") == "none") { - this.tab.show(); - } - - var newTab = $('
                                        '); - newTab.append(tabCont); - this.tab.append(newTab); - this.tab.tabs("add", "#" + tabId, tabName); - - // Append close button - if (closeable) { - var header = this.tab.find('ul.ui-tabs-nav a[href="#' + tabId +'"]').parent(); - header.append(''); - - // Get this tab - var tabs = this.tab; - var tabLink = 'a[href="\#' + tabId + '"]'; - var thisTab = $(tabLink, tabs).parent(); - - // Close tab when close button is clicked - thisTab.find('span.tab-close').bind('click', function(event) { - var tabIndex = ($('li', tabs).index(thisTab)); - - // Do not remove first tab - if (tabIndex != 0) { - // Go back to last tab if user is trying to close currently selected tab - if (tabs.tabs('option', 'selected') == tabIndex) { - // Get last selected tab from history - var order = $.cookie('xcat_tabindex_history').split(','); - if (order[1]) { - tabs.tabs('select', parseInt(order[1])); - } else { - tabs.tabs('select', 0); - } - } - - tabs.tabs('remove', tabIndex); - } - }); - } -}; - -/** - * Select a tab - * - * @param id Tab ID to select - */ -Tab.prototype.select = function(id) { - this.tab.tabs("select", "#" + id); -}; - -/** - * Remove a tab - * - * @param id Tab ID to remove - */ -Tab.prototype.remove = function(id) { - var selectorStr = 'a[href="\#' + id + '"]'; - var selectTab = $(selectorStr, this.tab).parent(); - var index = ($('li', this.tab).index(selectTab)); - this.tab.tabs("remove", index); -}; - -/** - * Table constructor - * - * @param tabId Tab ID - * @param tabName Tab name - */ -var Table = function(tableId) { - if ($('#' + tableId).length) { - this.tableId = tableId; - this.table = $('#' + tableId); - } else { - this.tableId = tableId; - this.table = null; - } -}; - -/** - * Initialize the table - * - * @param Headers Array of table headers - */ -Table.prototype.init = function(headers) { - // Create a table - this.table = $('
                                        '); - var thead = $(''); - var headRow = $(''); - - // Append headers - for (var i in headers) { - headRow.append('' + headers[i] + ''); - } - - thead.append(headRow); - this.table.append(thead); - - // Append table body - var tableBody = $(''); - this.table.append(tableBody); -}; - -/** - * Return the table object - * - * @return Object representing the table - */ -Table.prototype.object = function() { - return this.table; -}; - -/** - * Add a row to the table - * - * @param rowCont Array of table row contents - */ -Table.prototype.add = function(rowCont) { - // Create table row - var tableRow = $(''); - - // Create a column for each content - var tableCol; - for (var i in rowCont) { - tableCol = $(''); - tableCol.append(rowCont[i]); - tableRow.append(tableCol); - } - - // Append table row to table - this.table.find('tbody').append(tableRow); -}; - -/** - * Add a footer to the table - * - * @param rowCont Array of table row contents - */ -Table.prototype.addFooter = function(rowCont) { - // Create table row - var tableFoot = $(''); - tableFoot.append(rowCont); - - // Append table row to table - this.table.append(tableFoot); -}; - -/** - * Remove a row from the table - */ -Table.prototype.remove = function(id) { - // To be continued -}; - -/** - * Datatable class constructor - * - * @param tabId Tab ID - * @param tabName Tab name - */ -var DataTable = function(tableId) { - this.dataTableId = tableId; - this.dataTable = null; -}; - -/** - * Initialize the datatable - * - * @param Headers Array of table headers - */ -DataTable.prototype.init = function(headers) { - // Create a table - this.dataTable = $('
                                        '); - var thead = $(''); - var headRow = $(''); - - // Append headers - for (var i in headers) { - headRow.append('' + headers[i] + ''); - } - - thead.append(headRow); - this.dataTable.append(thead); - - // Append table body - var tableBody = $(''); - this.dataTable.append(tableBody); -}; - -/** - * Return the datatable object - * - * @return Object representing the table - */ -DataTable.prototype.object = function() { - return this.dataTable; -}; - -/** - * Add a row to the datatable - * - * @param rowCont Array of table row contents - */ -DataTable.prototype.add = function(rowCont) { - // Create table row - var tableRow = $(''); - - // Create a column for each content - var tableCol; - for (var i in rowCont) { - tableCol = $(''); - tableCol.append(rowCont[i]); - tableRow.append(tableCol); - } - - // Append table row to table - this.dataTable.find('tbody').append(tableRow); -}; - -/** - * Create status bar - * - * @param barId Status bar ID - */ -function createStatusBar(barId) { - // Do not change the background color or color! This is handled by the theme - // the user selects. - var statusBar = $('
                                        ').css({ - 'margin-bottom': '5px', - 'min-height': '30px', - 'max-height': '150px', - 'overflow': 'auto' - }); - - // Create info icon - var icon = $('').css({ - 'display': 'inline-block', - 'margin': '10px 5px', - 'vertical-align': 'top' - }); - - // Create message section - var msg = $('
                                        ').css({ - 'display': 'inline-block', - 'margin': '10px 0px', - 'width': '90%' - }); - - // Create hide button - var hide = $('').css({ - 'display': 'inline-block', - 'float': 'right', - 'cursor': 'pointer' - }).click(function() { - // Remove info box on-click - $(this).parent().hide(); - }); - - statusBar.append(icon); - statusBar.append(msg); - statusBar.append(hide); - return statusBar; -} - -/** - * Create info bar - * - * @param msg Info message - * @return Info bar - */ -function createInfoBar(msg) { - // Do not change the background color or color! This is handled by the theme - // the user selects. - var infoBar = $('
                                        ').css({ - 'margin': '5px 0px' - }); - var icon = $('').css({ - 'display': 'inline-block', - 'margin': '10px 5px' - }); - var barMsg = $('

                                        ' + msg + '

                                        ').css({ - 'display': 'inline-block', - 'width': '90%' - }); - - infoBar.append(icon); - infoBar.append(barMsg); - return infoBar; -} - -/** - * Create warning bar - * - * @param msg Warning message - * @return Warning bar - */ -function createWarnBar(msg) { - var warnBar = $('
                                        '); - var icon = $('').css({ - 'display': 'inline-block', - 'margin': '10px 5px' - }); - var barMsg = $('

                                        ' + msg + '

                                        ').css({ - 'display': 'inline-block', - 'width': '90%' - }); - - warnBar.append(icon); - warnBar.append(barMsg); - return warnBar; -} - -/** - * Create a loader - * - * @param loaderId Loader ID - */ -function createLoader(loaderId) { - var loader = $(''); - return loader; -} - -/** - * Create a button - * - * @param name Name of the button - */ -function createButton(name) { - var button = $('').button(); - return button; -} - -/** - * Create a menu - * - * @param items An array of items to go into the menu - * @return A division containing the menu - */ -function createMenu(items) { - var menu = $('
                                          '); - - // Loop through each item - for ( var i in items) { - // Append item to menu - var item = $('
                                        • '); - - // If it is a sub menu - if (items[i] instanceof Array) { - // 1st index = Sub menu title - item.append(items[i][0]); - // 2nd index = Sub menu - item.append(items[i][1]); - } else { - item.append(items[i]); - } - - menu.append(item); - } - - return menu; -} - -/** - * Initialize the page - */ -function initPage() { - // Load theme - var theme = $.cookie('xcat_theme'); - if (theme) { - switch (theme) { - case 'cupertino': - includeCss("css/themes/jquery-ui-cupertino.css"); - break; - case 'dark_hive': - includeCss("css/themes/jquery-ui-dark_hive.css"); - break; - case 'redmond': - includeCss("css/themes/jquery-ui-redmond.css"); - break; - case 'start': - includeCss("css/themes/jquery-ui-start.css"); - break; - case 'sunny': - includeCss("css/themes/jquery-ui-sunny.css"); - break; - case 'ui_dark': - includeCss("css/themes/jquery-ui-ui_darkness.css"); - break; - default: - includeCss("css/themes/jquery-ui-start.css"); - } - } else { - includeCss("css/themes/jquery-ui-start.css"); - } - - // Load jQuery stylesheets - includeCss("css/jquery.dataTables.css"); - includeCss("css/superfish.css"); - // includeCss("css/jstree.css"); - includeCss("css/jquery.jqplot.css"); - - // Load custom stylesheet - includeCss("css/style.css"); - - // JQuery plugins - includeJs("js/jquery/jquery.dataTables.min.js"); - includeJs("js/jquery/jquery.form.min.js"); - includeJs("js/jquery/jquery.jeditable.min.js"); - includeJs("js/jquery/jquery.contextmenu.min.js"); - includeJs("js/jquery/superfish.min.js"); - includeJs("js/jquery/hoverIntent.min.js"); - // includeJs("js/jquery/jquery.jstree.min.js"); - includeJs("js/jquery/tooltip.min.js"); - includeJs("js/jquery/jquery.serverBrowser.min.js"); - includeJs("js/jquery/jquery.jqplot.min.js"); - includeJs("js/jquery/jqplot.pieRenderer.min.js"); - includeJs("js/jquery/jqplot.barRenderer.min.js"); - includeJs("js/jquery/jqplot.pointLabels.min.js"); - includeJs("js/jquery/jqplot.categoryAxisRenderer.min.js"); - includeJs("js/jquery/jqplot.dateAxisRenderer.min.js"); - includeJs("js/jquery/jquery.topzindex.min.js"); - - // Page plugins - includeJs("js/configure/configure.js"); - includeJs("js/monitor/monitor.js"); - includeJs("js/nodes/nodes.js"); - includeJs("js/provision/provision.js"); - - // Custom plugins - includeJs("js/custom/esx.js"); - includeJs("js/custom/kvm.js"); - includeJs("js/custom/blade.js"); - includeJs("js/custom/ipmi.js"); - includeJs("js/custom/zvm.js"); - includeJs("js/custom/hmc.js"); - includeJs("js/custom/customUtils.js"); - - // Enable settings link - $('#xcat_settings').click(function() { - openSettings(); - }); - - // Set header to theme - var background = '', color = ''; - var theme = $.cookie('xcat_theme'); - if (theme) { - switch (theme) { - case 'cupertino': - background = '#3BAAE3'; - color = 'white'; - break; - case 'dark_hive': - background = '#0972A5'; - break; - case 'redmond': - background = '#F5F8F9'; - color = '#E17009'; - break; - case 'start': - background = '#6EAC2C'; - break; - case 'sunny': - background = 'white'; - color = '#0074C7'; - break; - case 'ui_dark': - background = '#F58400'; - break; - default: - background = '#6EAC2C'; - } - } else { - background = '#6EAC2C'; - } - - $('#header').addClass('ui-state-default'); - $('#header').css('border', '0px'); - - // Set theme to user span - $('#login_user').css('color', color); - - // Style for selected page - var style = { - 'background-color': background, - 'color': color - }; - - // Get the page being loaded - var url = window.location.pathname; - var page = url.replace('/xcat/', ''); - var headers = $('#header ul li a'); - - // Show the page - $("#content").children().remove(); - if (page == 'configure.php') { - includeJs("js/configure/update.js"); - includeJs("js/configure/service.js"); - includeJs("js/configure/users.js"); - includeJs("js/configure/files.js"); - headers.eq(1).css(style); - loadConfigPage(); - } else if (page == 'provision.php') { - includeJs("js/provision/images.js"); - headers.eq(2).css(style); - loadProvisionPage(); - } else if (page == 'help.php') { - includeJs("js/help/help.js"); - headers.eq(4).css(style); - loadHelpPage(); - } else { - // Load nodes page by default - includeJs("js/nodes/nodeset.js"); - includeJs("js/nodes/rnetboot.js"); - includeJs("js/nodes/updatenode.js"); - includeJs("js/nodes/rscan.js"); - headers.eq(0).css(style); - loadNodesPage(); - } -} - -/** - * Include javascript file in - * - * @param file File to include - */ -function includeJs(file) { - var script = $("head script[src='" + file + "']"); - - // If does not contain the javascript - if (!script.length) { - // Append the javascript to - var script = $(''); - script.attr( { - type : 'text/javascript', - src : file - }); - - $('head').append(script); - } -} - -/** - * Include CSS link in - * - * @param file File to include - */ -function includeCss(file) { - var link = $("head link[href='" + file + "']"); - - // If does not contain the link - if (!link.length) { - // Append the CSS link to - var link = $(''); - link.attr( { - type : 'text/css', - rel : 'stylesheet', - href : file - }); - - $('head').append(link); - } -} - -/** - * Write ajax response to a paragraph - * - * @param rsp Ajax response - * @param pattern Pattern to replace with a break - * @return Paragraph containing ajax response - */ -function writeRsp(rsp, pattern) { - // Create paragraph to hold ajax response - var prg = $('
                                          ');
                                          -
                                          -    for ( var i in rsp) {
                                          -        if (rsp[i]) {
                                          -            // Create regular expression for given pattern
                                          -            // Replace pattern with break
                                          -            if (pattern) {
                                          -                rsp[i] = rsp[i].replace(new RegExp(pattern, 'g'), '
                                          '); - prg.append(rsp[i]); - } else { - prg.append(rsp[i]); - prg.append('
                                          '); - } - } - } - - return prg; -} - -/** - * Open a dialog and show given message - * - * @param type Type of dialog, i.e. warn or info - * @param msg Message to show - */ -function openDialog(type, msg) { - var msgDialog = $('
                                          '); - var title = ""; - if (type == "warn") { - // Create warning message - msgDialog.append(createWarnBar(msg)); - title = "Warning"; - } else { - // Create info message - msgDialog.append(createInfoBar(msg)); - title = "Info"; - } - - // Open dialog - msgDialog.dialog({ - title: title, - modal: true, - close: function(){ - $(this).remove(); - }, - width: 500, - buttons: { - "Ok": function(){ - $(this).dialog("close"); - } - } - }); -} - -/** - * Create an iframe to hold the output of an xCAT command - * - * @param src The URL of the document to show in the iframe - * @return Info box containing the iframe - */ -function createIFrame(src) { - // Put an iframe inside an info box - var infoBar = $('
                                          ').css({ - 'margin-bottom': '5px' - }); - - // Create info and close icons - var icon = $('').css({ - 'display': 'inline-block', - 'margin': '10px 5px' - }); - var close = $('').css({ - 'display': 'inline-block', - 'float': 'right', - 'margin': '10px 5px' - }).click(function() { - // Remove info box on-click - $(this).parent().remove(); - }); - - var iframe = $('').attr('src', src).css({ - 'display': 'block', - 'border': '0px', - 'margin': '10px', - 'width': '100%' - }); - - var loader = createLoader('iLoader').css({ - 'display': 'block', - 'margin': '10px 0px' - }); - - infoBar.append(icon); - infoBar.append($('
                                          ').append(loader, iframe)); - infoBar.append(close); - - // Remove loader when done - iframe.load(function() { - loader.remove(); - }); - - return infoBar; -} - - -/** - * Open dialog to set xCAT UI settings - */ -function openSettings() { - // Create form to add node range - var dialog = $('
                                          '); - var info = createInfoBar('Select from the following options'); - dialog.append(info); - - var style = { - 'color': 'blue', - 'cursor': 'pointer', - 'padding': '5px' - }; - - var changeThemeOption = $('').css(style); - dialog.append(changeThemeOption); - - var changePasswordOption = $('').css(style); - dialog.append(changePasswordOption); - - // Open form as a dialog - dialog.dialog({ - modal: true, - close: function(){ - $(this).remove(); - }, - title: 'Settings', - width: 400, - buttons: { - "Cancel": function(){ - $(this).dialog("close"); - } - } - }); - - // Bind to click event - changeThemeOption.click(function() { - dialog.dialog("close"); - changeTheme(); - }); - - changePasswordOption.click(function() { - dialog.dialog("close"); - changePassword(); - }); -} - -/** - * Open dialog to change xCAT theme - */ -function changeTheme() { - // Create form to add node range - var dialog = $('
                                          '); - var info = createInfoBar('Select the xCAT theme you desire'); - dialog.append(info); - - // Create select drop down for themes - var oList = $('
                                            '); - oList.append($('
                                          1. Cupertino
                                          2. ')); - oList.append($('
                                          3. Dark Hive
                                          4. ')); - oList.append($('
                                          5. Redmond
                                          6. ')); - oList.append($('
                                          7. Start (default)
                                          8. ')); - oList.append($('
                                          9. Sunny
                                          10. ')); - oList.append($('
                                          11. UI Darkness
                                          12. ')); - dialog.append(oList); - - if ($.cookie('xcat_theme')) { - // Select theme - oList.find('input[value="' + $.cookie('xcat_theme') + '"]').attr('checked', true); - } else { - oList.find('input[value="start"]').attr('checked', true); - } - - // Open form as a dialog - dialog.dialog({ - modal: true, - close: function(){ - $(this).remove(); - }, - title: 'xCAT Theme', - width: 400, - buttons: { - "Ok": function(){ - // Save selected theme - var theme = $(this).find('input[name="theme"]:checked').val(); - $.cookie('xcat_theme', theme); // Do not expire cookie, keep it as long as possible - - // Show instructions to apply theme - $(this).empty(); - var info = createInfoBar('You will need to reload this page in order for changes to take effect'); - $(this).append(info); - - // Only show close button - $(this).dialog("option", "buttons", { - "Close" : function() { - $(this).dialog( "close" ); - } - }); - }, - "Cancel": function(){ - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Open dialog to change user password - */ -function changePassword() { - // Create form to add node range - var dialog = $('
                                            '); - var info = createInfoBar('Change your password'); - dialog.append(info); - - dialog.append('
                                            '); - dialog.append('
                                            '); - - // Open form as a dialog - dialog.dialog({ - modal: true, - close: function(){ - $(this).remove(); - }, - title: 'Change Password', - width: 400, - buttons: { - "Ok": function(){ - // Remove any warning messages - $(this).find('.ui-state-error').remove(); - - var errorMessage = ""; - - // Check each input is provided - $('#changePassword input').each(function() { - if (!$(this).val()) { - errorMessage = "Please provide a value for each missing input!"; - } - }); - - // Do not continue if error found - if (errorMessage) { - dialog.prepend(createWarnBar(errorMessage)); - return; - } - - // Check new and confirm passwords match - var user = $.cookie('xcat_username'); - var newPassword = $('#changePassword input[name="newPassword"]').val(); - var confirmPassword = $('#changePassword input[name="confirmPassword"]').val(); - if (newPassword != confirmPassword) { - dialog.prepend(createWarnBar("Please confirm new password!")); - return; - } - - // Change dialog buttons - $('#changePassword').dialog('option', 'buttons', { - 'Close':function(){ - $('#changePassword').dialog('destroy').remove(); - } - }); - - // Send request to change password - var url = window.location.pathname; - var page = url.replace('/xcat/', ''); - var url = 'lib/cmd.php'; - // Service portal does not have access to cmd.php - if (page == 'service.php') - url = 'lib/srv_cmd.php'; - $.ajax( { - url : url, - dataType : 'json', - data : { - cmd : 'webrun', - tgt : '', - args : 'passwd;' + user + ';' + newPassword, - msg : '' - }, - - success : function (data) { - // Show response message - var rspMessage = ""; - for (var i in data.rsp) - rspMessage += data.rsp[i] + "
                                            "; - - $('#changePassword').prepend(createInfoBar(rspMessage)); - } - }); - }, - "Cancel": function(){ - $(this).dialog( "close" ); - } - } - }); -} - -/** - * Adjust datatable column size - * - * @param tableId Table ID - */ -function adjustColumnSize(tableId) { - var dTable = $('#' + tableId).dataTable(); - dTable.fnAdjustColumnSizing(); -} - -/** - * Set menu theme - * - * @param menu Menu object - */ -function setMenu2Theme(menu) { - // On hover - var background = '', color = ''; - var theme = $.cookie('xcat_theme'); - if (theme) { - switch (theme) { - case 'cupertino': - background = '#3BAAE3'; - color = 'white'; - break; - case 'dark_hive': - background = '#0972A5'; - break; - case 'redmond': - background = '#F5F8F9'; - color = '#E17009'; - break; - case 'start': - background = '#6EAC2C'; - break; - case 'sunny': - background = 'white'; - color = '#0074C7'; - break; - case 'ui_dark': - background = '#F58400'; - break; - default: - background = '#6EAC2C'; - } - } else { - background = '#6EAC2C'; - } - - menu.css('background', background); - menu.find('a:eq(0)').css('color', color); -} - -/** - * Set menu back to normal before applying theme - * - * @param menu Menu object - */ -function setMenu2Normal(menu) { - // Change back to normal - menu.css('background', ''); - menu.find('a:eq(0)').css('color', ''); -} - -/** - * Get nodes that are checked in a given datatable - * - * @param datatableId The datatable ID - * @return Nodes that were checked - */ -function getNodesChecked(datatableId) { - var tgts = ''; - - // Get nodes that were checked - var nodes = $('#' + datatableId + ' input[type=checkbox]:checked'); - for (var i in nodes) { - var tgtNode = nodes.eq(i).attr('name'); - - if (tgtNode) { - tgts += tgtNode; - - // Add a comma at the end - if (i < nodes.length - 1) { - tgts += ','; - } - } - } - - return tgts; -} - -/** - * Check if return message contains errors - * - * @param msg Return message - * @return 0 If return message contains no errors - * -1 If return message contains errors - */ -function containErrors(msg) { - if (msg.indexOf('Failed') > -1 || msg.indexOf('Error') > -1) { - return -1; - } else { - return 0; - } -} - -/** - * Check if a value is an integer - * - * @param value Value to be checked - * @returns true If value is an integer - false If value is not an integer - */ -function isInteger(value){ - if ((parseFloat(value) == parseInt(value)) && !isNaN(value)) { - return true; - } else { - return false; - } -} +/** + * Tab constructor + * + * @param tabId + * Tab ID + * @param tabName + * Tab name + * @return Nothing + */ +var Tab = function(tabId) { + this.tabId = tabId; + this.tabName = null; + this.tab = null; +}; + +/** + * Initialize the tab + * + * @param tabName Tab name to initialize + */ +Tab.prototype.init = function() { + // Create a division containing the tab + this.tab = $('
                                            '); + var tabList = $('
                                              '); + var tabItem = $('
                                            • Dummy tab item
                                            • '); + tabList.append(tabItem); + this.tab.append(tabList); + + // Create a template with close button + var tabs = this.tab.tabs(); + + tabs.bind('tabsselect', function(event, ui){ + // Save the order tabs were selected + var order; + if ($.cookie('xcat_tabindex_history')) { + order = $.cookie('xcat_tabindex_history').split(','); + order[1] = order[0]; // Set index 1 to last selected tab + order[0] = ui.index; // Set index 0 to currently selected tab + } else { + // Create an array to track the tab selected + order = new Array; + order[0] = ui.index; + order[1] = ui.index; + } + + $.cookie('xcat_tabindex_history', order, { path: '/xcat', secure:true }); + }); + + // Remove dummy tab + this.tab.tabs("remove", 0); + + // Hide tab + this.tab.hide(); +}; + +/** + * Return the tab object + * + * @return Object representing the tab + */ +Tab.prototype.object = function() { + return this.tab; +}; + +/** + * Add a new tab + * + * @param tabId Tab ID + * @param tabName Tab name + * @param tabCont Tab content + * @param closeable Is tab closeable + */ +Tab.prototype.add = function(tabId, tabName, tabCont, closeable) { + // Show tab + if (this.tab.css("display") == "none") { + this.tab.show(); + } + + var newTab = $('
                                              '); + newTab.append(tabCont); + this.tab.append(newTab); + this.tab.tabs("add", "#" + tabId, tabName); + + // Append close button + if (closeable) { + var header = this.tab.find('ul.ui-tabs-nav a[href="#' + tabId +'"]').parent(); + header.append(''); + + // Get this tab + var tabs = this.tab; + var tabLink = 'a[href="\#' + tabId + '"]'; + var thisTab = $(tabLink, tabs).parent(); + + // Close tab when close button is clicked + thisTab.find('span.tab-close').bind('click', function(event) { + var tabIndex = ($('li', tabs).index(thisTab)); + + // Do not remove first tab + if (tabIndex != 0) { + // Go back to last tab if user is trying to close currently selected tab + if (tabs.tabs('option', 'selected') == tabIndex) { + // Get last selected tab from history + var order = $.cookie('xcat_tabindex_history').split(','); + if (order[1]) { + tabs.tabs('select', parseInt(order[1])); + } else { + tabs.tabs('select', 0); + } + } + + tabs.tabs('remove', tabIndex); + } + }); + } +}; + +/** + * Select a tab + * + * @param id Tab ID to select + */ +Tab.prototype.select = function(id) { + this.tab.tabs("select", "#" + id); +}; + +/** + * Remove a tab + * + * @param id Tab ID to remove + */ +Tab.prototype.remove = function(id) { + var selectorStr = 'a[href="\#' + id + '"]'; + var selectTab = $(selectorStr, this.tab).parent(); + var index = ($('li', this.tab).index(selectTab)); + this.tab.tabs("remove", index); +}; + +/** + * Table constructor + * + * @param tabId Tab ID + * @param tabName Tab name + */ +var Table = function(tableId) { + if ($('#' + tableId).length) { + this.tableId = tableId; + this.table = $('#' + tableId); + } else { + this.tableId = tableId; + this.table = null; + } +}; + +/** + * Initialize the table + * + * @param Headers Array of table headers + */ +Table.prototype.init = function(headers) { + // Create a table + this.table = $('
                                              '); + var thead = $(''); + var headRow = $(''); + + // Append headers + for ( var i in headers) { + headRow.append('' + headers[i] + ''); + } + + thead.append(headRow); + this.table.append(thead); + + // Append table body + var tableBody = $(''); + this.table.append(tableBody); +}; + +/** + * Return the table object + * + * @return Object representing the table + */ +Table.prototype.object = function() { + return this.table; +}; + +/** + * Add a row to the table + * + * @param rowCont Array of table row contents + */ +Table.prototype.add = function(rowCont) { + // Create table row + var tableRow = $(''); + + // Create a column for each content + var tableCol; + for ( var i in rowCont) { + tableCol = $(''); + tableCol.append(rowCont[i]); + tableRow.append(tableCol); + } + + // Append table row to table + this.table.find('tbody').append(tableRow); +}; + +/** + * Add a footer to the table + * + * @param rowCont Array of table row contents + */ +Table.prototype.addFooter = function(rowCont) { + // Create table row + var tableFoot = $(''); + tableFoot.append(rowCont); + + // Append table row to table + this.table.append(tableFoot); +}; + +/** + * Remove a row from the table + */ +Table.prototype.remove = function(id) { + // To be continued +}; + +/** + * Datatable class constructor + * + * @param tabId Tab ID + * @param tabName Tab name + */ +var DataTable = function(tableId) { + this.dataTableId = tableId; + this.dataTable = null; +}; + +/** + * Initialize the datatable + * + * @param Headers Array of table headers + */ +DataTable.prototype.init = function(headers) { + // Create a table + this.dataTable = $('
                                              '); + var thead = $(''); + var headRow = $(''); + + // Append headers + for ( var i in headers) { + headRow.append('' + headers[i] + ''); + } + + thead.append(headRow); + this.dataTable.append(thead); + + // Append table body + var tableBody = $(''); + this.dataTable.append(tableBody); +}; + +/** + * Return the datatable object + * + * @return Object representing the table + */ +DataTable.prototype.object = function() { + return this.dataTable; +}; + +/** + * Add a row to the datatable + * + * @param rowCont Array of table row contents + */ +DataTable.prototype.add = function(rowCont) { + // Create table row + var tableRow = $(''); + + // Create a column for each content + var tableCol; + for ( var i in rowCont) { + tableCol = $(''); + tableCol.append(rowCont[i]); + tableRow.append(tableCol); + } + + // Append table row to table + this.dataTable.find('tbody').append(tableRow); +}; + +/** + * Create status bar + * + * @param barId Status bar ID + */ +function createStatusBar(barId) { + // Do not change the background color or color! This is handled by the theme + // the user selects. + var statusBar = $('
                                              ').css({ + 'margin-bottom': '5px', + 'min-height': '30px', + 'max-height': '150px', + 'overflow': 'auto' + }); + + // Create info icon + var icon = $('').css({ + 'display': 'inline-block', + 'margin': '10px 5px', + 'vertical-align': 'top' + }); + + // Create message section + var msg = $('
                                              ').css({ + 'display': 'inline-block', + 'margin': '10px 0px', + 'width': '90%' + }); + + // Create hide button + var hide = $('').css({ + 'display': 'inline-block', + 'float': 'right', + 'cursor': 'pointer' + }).click(function() { + // Remove info box on-click + $(this).parent().hide(); + }); + + statusBar.append(icon); + statusBar.append(msg); + statusBar.append(hide); + return statusBar; +} + +/** + * Create info bar + * + * @param msg Info message + * @return Info bar + */ +function createInfoBar(msg) { + // Do not change the background color or color! This is handled by the theme + // the user selects. + var infoBar = $('
                                              ').css({ + 'margin': '5px 0px' + }); + var icon = $('').css({ + 'display': 'inline-block', + 'margin': '10px 5px' + }); + var barMsg = $('

                                              ' + msg + '

                                              ').css({ + 'display': 'inline-block', + 'width': '90%' + }); + + infoBar.append(icon); + infoBar.append(barMsg); + return infoBar; +} + +/** + * Create warning bar + * + * @param msg Warning message + * @return Warning bar + */ +function createWarnBar(msg) { + var warnBar = $('
                                              '); + var icon = $('').css({ + 'display': 'inline-block', + 'margin': '10px 5px' + }); + var barMsg = $('

                                              ' + msg + '

                                              ').css({ + 'display': 'inline-block', + 'width': '90%' + }); + + warnBar.append(icon); + warnBar.append(barMsg); + return warnBar; +} + +/** + * Create a loader + * + * @param loaderId Loader ID + */ +function createLoader(loaderId) { + var loader = $(''); + return loader; +} + +/** + * Create a button + * + * @param name Name of the button + */ +function createButton(name) { + var button = $('').button(); + return button; +} + +/** + * Create a menu + * + * @param items An array of items to go into the menu + * @return A division containing the menu + */ +function createMenu(items) { + var menu = $('
                                                '); + + // Loop through each item + for ( var i in items) { + // Append item to menu + var item = $('
                                              • '); + + // If it is a sub menu + if (items[i] instanceof Array) { + // 1st index = Sub menu title + item.append(items[i][0]); + // 2nd index = Sub menu + item.append(items[i][1]); + } else { + item.append(items[i]); + } + + menu.append(item); + } + + return menu; +} + +/** + * Initialize the page + */ +function initPage() { + // Load theme + var theme = $.cookie('xcat_theme'); + if (theme) { + switch (theme) { + case 'cupertino': + includeCss("css/themes/jquery-ui-cupertino.css"); + break; + case 'dark_hive': + includeCss("css/themes/jquery-ui-dark_hive.css"); + break; + case 'redmond': + includeCss("css/themes/jquery-ui-redmond.css"); + break; + case 'start': + includeCss("css/themes/jquery-ui-start.css"); + break; + case 'sunny': + includeCss("css/themes/jquery-ui-sunny.css"); + break; + case 'ui_dark': + includeCss("css/themes/jquery-ui-ui_darkness.css"); + break; + default: + includeCss("css/themes/jquery-ui-start.css"); + } + } else { + includeCss("css/themes/jquery-ui-start.css"); + } + + // Load jQuery stylesheets + includeCss("css/jquery.dataTables.css"); + includeCss("css/superfish.css"); + includeCss("css/jstree.css"); + includeCss("css/jquery.jqplot.css"); + + // Load custom stylesheet + includeCss("css/style.css"); + + // JQuery plugins + includeJs("js/jquery/jquery.dataTables.min.js"); + includeJs("js/jquery/jquery.form.min.js"); + includeJs("js/jquery/jquery.jeditable.min.js"); + includeJs("js/jquery/jquery.contextmenu.min.js"); + includeJs("js/jquery/superfish.min.js"); + includeJs("js/jquery/hoverIntent.min.js"); + includeJs("js/jquery/jquery.jstree.min.js"); + includeJs("js/jquery/tooltip.min.js"); + includeJs("js/jquery/jquery.serverBrowser.min.js"); + includeJs("js/jquery/jquery.jqplot.min.js"); + includeJs("js/jquery/jqplot.pieRenderer.min.js"); + includeJs("js/jquery/jqplot.dateAxisRenderer.min.js"); + includeJs("js/jquery/jquery.topzindex.min.js"); + + // Page plugins + includeJs("js/configure/configure.js"); + includeJs("js/monitor/monitor.js"); + includeJs("js/nodes/nodes.js"); + includeJs("js/provision/provision.js"); + + // Custom plugins + includeJs("js/custom/zvm.js"); + includeJs("js/custom/customUtils.js"); + + // Enable settings link + $('#xcat_settings').click(function() { + openSettings(); + }); + + // Set header to theme + var background = '', color = ''; + var theme = $.cookie('xcat_theme'); + if (theme) { + switch (theme) { + case 'cupertino': + background = '#3BAAE3'; + color = 'white'; + break; + case 'dark_hive': + background = '#0972A5'; + break; + case 'redmond': + background = '#F5F8F9'; + color = '#E17009'; + break; + case 'start': + background = '#6EAC2C'; + break; + case 'sunny': + background = 'white'; + color = '#0074C7'; + break; + case 'ui_dark': + background = '#F58400'; + break; + default: + background = '#6EAC2C'; + } + } else { + background = '#6EAC2C'; + } + + $('#header').addClass('ui-state-default'); + $('#header').css('border', '0px'); + + // Set theme to user span + $('#login_user').css('color', color); + + // Style for selected page + var style = { + 'background-color': background, + 'color': color + }; + + // Get the page being loaded + var url = window.location.pathname; + var page = url.replace('/xcat/', ''); + var headers = $('#header ul li a'); + + // Show the page + $("#content").children().remove(); + if (page == 'configure.php') { + includeJs("js/configure/update.js"); + includeJs("js/configure/service.js"); + includeJs("js/configure/users.js"); + includeJs("js/configure/files.js"); + headers.eq(1).css(style); + loadConfigPage(); + } else if (page == 'provision.php') { + includeJs("js/provision/images.js"); + headers.eq(2).css(style); + loadProvisionPage(); + } else if (page == 'help.php') { + includeJs("js/help/help.js"); + headers.eq(4).css(style); + loadHelpPage(); + } else { + // Load nodes page by default + includeJs("js/nodes/nodeset.js"); + includeJs("js/nodes/rnetboot.js"); + includeJs("js/nodes/updatenode.js"); + includeJs("js/nodes/rscan.js"); + headers.eq(0).css(style); + loadNodesPage(); + } +} + +/** + * Include javascript file in + * + * @param file File to include + */ +function includeJs(file) { + var script = $("head script[src='" + file + "']"); + + // If does not contain the javascript + if (!script.length) { + // Append the javascript to + var script = $(''); + script.attr( { + type : 'text/javascript', + src : file + }); + + $('head').append(script); + } +} + +/** + * Include CSS link in + * + * @param file File to include + */ +function includeCss(file) { + var link = $("head link[href='" + file + "']"); + + // If does not contain the link + if (!link.length) { + // Append the CSS link to + var link = $(''); + link.attr( { + type : 'text/css', + rel : 'stylesheet', + href : file + }); + + $('head').append(link); + } +} + +/** + * Write ajax response to a paragraph + * + * @param rsp Ajax response + * @param pattern Pattern to replace with a break + * @return Paragraph containing ajax response + */ +function writeRsp(rsp, pattern) { + // Create paragraph to hold ajax response + var prg = $('
                                                ');
                                                +
                                                +    for ( var i in rsp) {
                                                +        if (rsp[i]) {
                                                +            // Create regular expression for given pattern
                                                +            // Replace pattern with break
                                                +            if (pattern) {
                                                +                rsp[i] = rsp[i].replace(new RegExp(pattern, 'g'), '
                                                '); + prg.append(rsp[i]); + } else { + prg.append(rsp[i]); + prg.append('
                                                '); + } + } + } + + return prg; +} + +/** + * Open a dialog and show given message + * + * @param type Type of dialog, i.e. warn or info + * @param msg Message to show + */ +function openDialog(type, msg) { + var msgDialog = $('
                                                '); + var title = ""; + if (type == "warn") { + // Create warning message + msgDialog.append(createWarnBar(msg)); + title = "Warning"; + } else { + // Create info message + msgDialog.append(createInfoBar(msg)); + title = "Info"; + } + + // Open dialog + msgDialog.dialog({ + title: title, + modal: true, + close: function(){ + $(this).remove(); + }, + width: 500, + buttons: { + "Ok": function(){ + $(this).dialog("close"); + } + } + }); +} + +/** + * Create an iframe to hold the output of an xCAT command + * + * @param src The URL of the document to show in the iframe + * @return Info box containing the iframe + */ +function createIFrame(src) { + // Put an iframe inside an info box + var infoBar = $('
                                                ').css({ + 'margin-bottom': '5px' + }); + + // Create info and close icons + var icon = $('').css({ + 'display': 'inline-block', + 'margin': '10px 5px' + }); + var close = $('').css({ + 'display': 'inline-block', + 'float': 'right', + 'margin': '10px 5px' + }).click(function() { + // Remove info box on-click + $(this).parent().remove(); + }); + + var iframe = $('').attr('src', src).css({ + 'display': 'block', + 'border': '0px', + 'margin': '10px', + 'width': '100%' + }); + + var loader = createLoader('iLoader').css({ + 'display': 'block', + 'margin': '10px 0px' + }); + + infoBar.append(icon); + infoBar.append($('
                                                ').append(loader, iframe)); + infoBar.append(close); + + // Remove loader when done + iframe.load(function() { + loader.remove(); + }); + + return infoBar; +} + + +/** + * Open dialog to set xCAT UI settings + */ +function openSettings() { + // Create form to add node range + var dialog = $('
                                                '); + var info = createInfoBar('Select from the following options'); + dialog.append(info); + + var style = { + 'color': 'blue', + 'cursor': 'pointer', + 'padding': '5px' + }; + + var changeThemeOption = $('').css(style); + dialog.append(changeThemeOption); + + var changePasswordOption = $('').css(style); + dialog.append(changePasswordOption); + + // Open form as a dialog + dialog.dialog({ + modal: true, + close: function(){ + $(this).remove(); + }, + title: 'Settings', + width: 400, + buttons: { + "Cancel": function(){ + $(this).dialog("close"); + } + } + }); + + // Bind to click event + changeThemeOption.click(function() { + dialog.dialog("close"); + changeTheme(); + }); + + changePasswordOption.click(function() { + dialog.dialog("close"); + changePassword(); + }); +} + +/** + * Open dialog to change xCAT theme + */ +function changeTheme() { + // Create form to add node range + var dialog = $('
                                                '); + var info = createInfoBar('Select the xCAT theme you desire'); + dialog.append(info); + + // Create select drop down for themes + var oList = $('
                                                  '); + oList.append($('
                                                1. Cupertino
                                                2. ')); + oList.append($('
                                                3. Dark Hive
                                                4. ')); + oList.append($('
                                                5. Redmond
                                                6. ')); + oList.append($('
                                                7. Start (default)
                                                8. ')); + oList.append($('
                                                9. Sunny
                                                10. ')); + oList.append($('
                                                11. UI Darkness
                                                12. ')); + dialog.append(oList); + + if ($.cookie('xcat_theme')) { + // Select theme + oList.find('input[value="' + $.cookie('xcat_theme') + '"]').attr('checked', true); + } else { + oList.find('input[value="start"]').attr('checked', true); + } + + // Open form as a dialog + dialog.dialog({ + modal: true, + close: function(){ + $(this).remove(); + }, + title: 'xCAT Theme', + width: 400, + buttons: { + "Ok": function(){ + // Save selected theme + var theme = $(this).find('input[name="theme"]:checked').val(); + $.cookie('xcat_theme', theme); // Do not expire cookie, keep it as long as possible + + // Show instructions to apply theme + $(this).empty(); + var info = createInfoBar('You will need to reload this page in order for changes to take effect'); + $(this).append(info); + + // Only show close button + $(this).dialog("option", "buttons", { + "Close" : function() { + $(this).dialog( "close" ); + } + }); + }, + "Cancel": function(){ + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Open dialog to change user password + */ +function changePassword() { + // Create form to add node range + var dialog = $('
                                                  '); + var info = createInfoBar('Change your password'); + dialog.append(info); + + dialog.append('
                                                  '); + dialog.append('
                                                  '); + + // Open form as a dialog + dialog.dialog({ + modal: true, + close: function(){ + $(this).remove(); + }, + title: 'Change Password', + width: 400, + buttons: { + "Ok": function(){ + // Remove any warning messages + $(this).find('.ui-state-error').remove(); + + var errorMessage = ""; + + // Check each input is provided + $('#changePassword input').each(function() { + if (!$(this).val()) { + errorMessage = "Please provide a value for each missing input!"; + } + }); + + // Do not continue if error found + if (errorMessage) { + dialog.prepend(createWarnBar(errorMessage)); + return; + } + + // Check new and confirm passwords match + var user = $.cookie('xcat_username'); + var newPassword = $('#changePassword input[name="newPassword"]').val(); + var confirmPassword = $('#changePassword input[name="confirmPassword"]').val(); + if (newPassword != confirmPassword) { + dialog.prepend(createWarnBar("Please confirm new password!")); + return; + } + + // Change dialog buttons + $('#changePassword').dialog('option', 'buttons', { + 'Close':function(){ + $('#changePassword').dialog('destroy').remove(); + } + }); + + // Send request to change password + var url = window.location.pathname; + var page = url.replace('/xcat/', ''); + var url = 'lib/cmd.php'; + // Service portal does not have access to cmd.php + if (page == 'service.php') + url = 'lib/srv_cmd.php'; + $.ajax( { + url : url, + dataType : 'json', + data : { + cmd : 'webrun', + tgt : '', + args : 'passwd;' + user + ';' + newPassword, + msg : '' + }, + + success : function (data) { + // Show response message + var rspMessage = ""; + for (var i in data.rsp) + rspMessage += data.rsp[i] + "
                                                  "; + + $('#changePassword').prepend(createInfoBar(rspMessage)); + } + }); + }, + "Cancel": function(){ + $(this).dialog( "close" ); + } + } + }); +} + +/** + * Adjust datatable column size + * + * @param tableId Table ID + */ +function adjustColumnSize(tableId) { + var dTable = $('#' + tableId).dataTable(); + dTable.fnAdjustColumnSizing(); +} + +/** + * Set menu theme + * + * @param menu Menu object + */ +function setMenu2Theme(menu) { + // On hover + var background = '', color = ''; + var theme = $.cookie('xcat_theme'); + if (theme) { + switch (theme) { + case 'cupertino': + background = '#3BAAE3'; + color = 'white'; + break; + case 'dark_hive': + background = '#0972A5'; + break; + case 'redmond': + background = '#F5F8F9'; + color = '#E17009'; + break; + case 'start': + background = '#6EAC2C'; + break; + case 'sunny': + background = 'white'; + color = '#0074C7'; + break; + case 'ui_dark': + background = '#F58400'; + break; + default: + background = '#6EAC2C'; + } + } else { + background = '#6EAC2C'; + } + + menu.css('background', background); + menu.find('a:eq(0)').css('color', color); +} + +/** + * Set menu back to normal before applying theme + * + * @param menu Menu object + */ +function setMenu2Normal(menu) { + // Change back to normal + menu.css('background', ''); + menu.find('a:eq(0)').css('color', ''); +} + +/** + * Get nodes that are checked in a given datatable + * + * @param datatableId The datatable ID + * @return Nodes that were checked + */ +function getNodesChecked(datatableId) { + var tgts = ''; + + // Get nodes that were checked + var nodes = $('#' + datatableId + ' input[type=checkbox]:checked'); + for (var i in nodes) { + var tgtNode = nodes.eq(i).attr('name'); + + if (tgtNode) { + tgts += tgtNode; + + // Add a comma at the end + if (i < nodes.length - 1) { + tgts += ','; + } + } + } + + return tgts; +} + +/** + * Check if return message contains errors + * + * @param msg Return message + * @return 0 If return message contains no errors + * -1 If return message contains errors + */ +function containErrors(msg) { + if (msg.indexOf('Failed') > -1 || msg.indexOf('Error') > -1) { + return -1; + } else { + return 0; + } +} + +/** + * Check if a value is an integer + * + * @param value Value to be checked + * @returns true If value is an integer + false If value is not an integer + */ +function isInteger(value){ + if ((parseFloat(value) == parseInt(value)) && !isNaN(value)) { + return true; + } else { + return false; + } +} + +/** + * Remove html encoding from php htmlentities() conversion + * + * @param encodedString + */ +function decodeHTML(encodedString) { + var txt = document.createElement("textarea"); + txt.innerHTML = encodedString; + return txt.value; +} + +/** + * Remove html encoding from rsp.data array and rsp.msg + * + * @param encodedData from server response + */ +function decodeRsp(encodedData) { + /* response data has rsp and msg. msg is a string. + rsp is a string, or array of strings or array of arrays with strings*/ + if ( (typeof encodedData.rsp != "undefined") && (encodedData.rsp.length > 0) ) { + if (encodedData.rsp.constructor === Array) { + for (var i in encodedData.rsp) { + if (encodedData.rsp[i].constructor === Array) { + for (var j in encodedData.rsp[i]) { + encodedData.rsp[i][j] = decodeHTML(encodedData.rsp[i][j]); + } + } else { + encodedData.rsp[i] = decodeHTML(encodedData.rsp[i]); + } + } + } else { + encodedData.rsp = decodeHTML(encodedData.rsp); + } + } + /* msg is a string */ + if ( (typeof encodedData.msg != "undefined") && (encodedData.msg.length > 0) ){ + encodedData.msg = decodeHTML(encodedData.msg); + } + return encodedData; +} diff --git a/xCAT-UI/lib/cmd.php b/xCAT-UI/lib/cmd.php index f63f83000..db9a3a23b 100644 --- a/xCAT-UI/lib/cmd.php +++ b/xCAT-UI/lib/cmd.php @@ -1,225 +1,241 @@ -children() as $child) { - foreach ($child->children() as $data) { - if($data->name) { - $node = $data->name; - - if ($data->data->contents) { - $cont = $data->data->contents; - } else { - $cont = $data->data; - } - - if ($data->data->desc) { - $cont = $data->data->desc . ": " . $cont; - } - - $cont = str_replace(":|:", "\n", $cont); - array_push($rsp, "$node: $cont"); - } else if (strlen("$data") > 2) { - $data = str_replace(":|:", "\n", $data); - array_push($rsp, "$data"); - } - } - } - } - - // Reply in the form of JSON - $rtn = array("rsp" => $rsp, "msg" => $msg); - echo json_encode($rtn); -} - -/** - * Extract the output for a webrun command - * - * @param $xml The XML output from docmd() - * @return An array containing the output - */ -function extractWebrun($xml) { - $rsp = array(); - $i = 0; - - // Extract data returned - foreach($xml->children() as $nodes){ - foreach($nodes->children() as $node){ - // Get the node name - $name = $node->name; - - // Get the content - $status = $node->data; - $status = str_replace(":|:", "\n", $status); - - // Add to return array - $rsp[$i] = array("$name", "$status"); - $i++; - } - } - - return $rsp; -} - -/** - * Extract the output for a nodels command - * - * @param $xml The XML output from docmd() - * @return An array containing the output - */ -function extractNodels($xml) { - $rsp = array(); - $i = 0; - - // Extract data returned - foreach($xml->children() as $nodes){ - foreach($nodes->children() as $node){ - // Get the node name - $name = $node->name; - // Get the content - $status = $node->data->contents; - $status = str_replace(":|:", "\n", $status); - - $description = $node->data->desc; - // Add to return array - $rsp[$i] = array("$name", "$status", "$description"); - $i++; - } - } - - return $rsp; -} - -/** - * Extract the output for a extnoderange command - * - * @param $xml The XML output from docmd() - * @return The nodes and groups - */ -function extractExtnoderange($xml) { - $rsp = array(); - - // Extract data returned - foreach ($xml->xcatresponse->intersectinggroups as $group) { - array_push($rsp, "$group"); - } - - return $rsp; -} +children() as $child) { + foreach ($child->children() as $data) { + if($data->name) { + $node = $data->name; + + if ($data->data->contents) { + $cont = $data->data->contents; + } else { + $cont = $data->data; + } + + if ($data->data->desc) { + $cont = $data->data->desc . ": " . $cont; + } + + $cont = str_replace(":|:", "\n", $cont); + array_push($rsp, "$node: $cont"); + } else if (strlen("$data") > 2) { + $data = str_replace(":|:", "\n", $data); + array_push($rsp, "$data"); + } + } + } + } + // Remove any HTML that could be used for XSS attacks + foreach ($rsp as $key => &$value) { + $whatami = gettype($value); + if ("string" != $whatami) { + //echo "found a non string in rsp array \n"; + foreach ($value as $key2 => $value2){ + //echo "Key2:$key2 Value2 type:",gettype($value2)," value2 data: $value2 \n"; + $value[$key2] = htmlentities($value2, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + } + } else { + //echo "Key:$key Value type:",gettype($value)," value data: $value \n"; + $rsp[$key] = htmlentities($value, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + //echo "New value: $rsp[$key] \n"; + } + } + $msg = htmlentities($msg, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + + // Reply in the form of JSON + $rtn = array("rsp" => $rsp, "msg" => $msg); + echo json_encode($rtn); +} + +/** + * Extract the output for a webrun command + * + * @param $xml The XML output from docmd() + * @return An array containing the output + */ +function extractWebrun($xml) { + $rsp = array(); + $i = 0; + + // Extract data returned + foreach($xml->children() as $nodes){ + foreach($nodes->children() as $node){ + // Get the node name + $name = $node->name; + + // Get the content + $status = $node->data; + $status = str_replace(":|:", "\n", $status); + + // Add to return array + $rsp[$i] = array("$name", "$status"); + $i++; + } + } + + return $rsp; +} + +/** + * Extract the output for a nodels command + * + * @param $xml The XML output from docmd() + * @return An array containing the output + */ +function extractNodels($xml) { + $rsp = array(); + $i = 0; + + // Extract data returned + foreach($xml->children() as $nodes){ + foreach($nodes->children() as $node){ + // Get the node name + $name = $node->name; + // Get the content + $status = $node->data->contents; + $status = str_replace(":|:", "\n", $status); + + $description = $node->data->desc; + // Add to return array + $rsp[$i] = array("$name", "$status", "$description"); + $i++; + } + } + + return $rsp; +} + +/** + * Extract the output for a extnoderange command + * + * @param $xml The XML output from docmd() + * @return The nodes and groups + */ +function extractExtnoderange($xml) { + $rsp = array(); + + // Extract data returned + foreach ($xml->xcatresponse->intersectinggroups as $group) { + array_push($rsp, "$group"); + } + + return $rsp; +} ?> \ No newline at end of file diff --git a/xCAT-UI/lib/functions.php b/xCAT-UI/lib/functions.php index 20c27efa6..f46a7554c 100644 --- a/xCAT-UI/lib/functions.php +++ b/xCAT-UI/lib/functions.php @@ -299,7 +299,7 @@ function isAuthenticated() { */ function isRootAcess() { if (is_logged() && $_SESSION["xcatpassvalid"]) { - $testacc = docmd('tabdump', '', array('policy', '-w', "name==" . $_SESSION["username"]), array()); + $testacc = docmd('tabdump', '', array('-w', "name==" . $_SESSION["username"],'policy' ), array()); if (isset($testacc->{'xcatresponse'}->{'data'}->{1})) { $result = $testacc->{'xcatresponse'}->{'data'}->{1}; $result = str_replace('"', '', $result); diff --git a/xCAT-UI/lib/srv_cmd.php b/xCAT-UI/lib/srv_cmd.php index c1b226369..ecb4fc1a4 100644 --- a/xCAT-UI/lib/srv_cmd.php +++ b/xCAT-UI/lib/srv_cmd.php @@ -1,190 +1,206 @@ -children() as $child) { - foreach ($child->children() as $data) { - if($data->name) { - $node = $data->name; - - if($data->data->contents){ - $cont = $data->data->contents; - } else { - $cont = $data->data; - } - - $cont = str_replace(":|:", "\n", $cont); - array_push($rsp, "$node: $cont"); - } else if (strlen("$data") > 2) { - $data = str_replace(":|:", "\n", $data); - array_push($rsp, "$data"); - } - } - } - } - - // Reply in the form of JSON - $rtn = array("rsp" => $rsp, "msg" => $msg); - echo json_encode($rtn); -} - -/** - * Extract the output for a webrun command - * - * @param $xml The XML output from docmd() - * @return An array containing the output - */ -function extractWebrun($xml) { - $rsp = array(); - $i = 0; - - // Extract data returned - foreach($xml->children() as $nodes){ - foreach($nodes->children() as $node){ - // Get the node name - $name = $node->name; - - // Get the content - $status = $node->data; - $status = str_replace(":|:", "\n", $status); - - // Add to return array - $rsp[$i] = array("$name", "$status"); - $i++; - } - } - - return $rsp; -} - -/** - * Extract the output for a nodels command - * - * @param $xml The XML output from docmd() - * @return An array containing the output - */ -function extractNodels($xml) { - $rsp = array(); - $i = 0; - - // Extract data returned - foreach($xml->children() as $nodes){ - foreach($nodes->children() as $node){ - // Get the node name - $name = $node->name; - // Get the content - $status = $node->data->contents; - $status = str_replace(":|:", "\n", $status); - - $description = $node->data->desc; - // Add to return array - $rsp[$i] = array("$name", "$status", "$description"); - $i++; - } - } - - return $rsp; -} - -/** - * Extract the output for a extnoderange command - * - * @param $xml The XML output from docmd() - * @return The nodes and groups - */ -function extractExtnoderange($xml) { - $rsp = array(); - - // Extract data returned - foreach ($xml->xcatresponse->intersectinggroups as $group) { - array_push($rsp, "$group"); - } - - return $rsp; -} +children() as $child) { + foreach ($child->children() as $data) { + if($data->name) { + $node = $data->name; + + if($data->data->contents){ + $cont = $data->data->contents; + } else { + $cont = $data->data; + } + + $cont = str_replace(":|:", "\n", $cont); + array_push($rsp, "$node: $cont"); + } else if (strlen("$data") > 2) { + $data = str_replace(":|:", "\n", $data); + array_push($rsp, "$data"); + } + } + } + } + // Remove any HTML that could be used for XSS attacks + foreach ($rsp as $key => &$value) { + $whatami = gettype($value); + if ("string" != $whatami) { + //echo "found a non string in rsp array \n"; + foreach ($value as $key2 => $value2){ + //echo "Key2:$key2 Value2 type:",gettype($value2)," value2 data: $value2 \n"; + $value[$key2] = htmlentities($value2, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + } + } else { + //echo "Key:$key Value type:",gettype($value)," value data: $value \n"; + $rsp[$key] = htmlentities($value, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + //echo "New value: $rsp[$key] \n"; + } + } + $msg = htmlentities($msg, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + + // Reply in the form of JSON + $rtn = array("rsp" => $rsp, "msg" => $msg); + echo json_encode($rtn); +} + +/** + * Extract the output for a webrun command + * + * @param $xml The XML output from docmd() + * @return An array containing the output + */ +function extractWebrun($xml) { + $rsp = array(); + $i = 0; + + // Extract data returned + foreach($xml->children() as $nodes){ + foreach($nodes->children() as $node){ + // Get the node name + $name = $node->name; + + // Get the content + $status = $node->data; + $status = str_replace(":|:", "\n", $status); + + // Add to return array + $rsp[$i] = array("$name", "$status"); + $i++; + } + } + + return $rsp; +} + +/** + * Extract the output for a nodels command + * + * @param $xml The XML output from docmd() + * @return An array containing the output + */ +function extractNodels($xml) { + $rsp = array(); + $i = 0; + + // Extract data returned + foreach($xml->children() as $nodes){ + foreach($nodes->children() as $node){ + // Get the node name + $name = $node->name; + // Get the content + $status = $node->data->contents; + $status = str_replace(":|:", "\n", $status); + + $description = $node->data->desc; + // Add to return array + $rsp[$i] = array("$name", "$status", "$description"); + $i++; + } + } + + return $rsp; +} + +/** + * Extract the output for a extnoderange command + * + * @param $xml The XML output from docmd() + * @return The nodes and groups + */ +function extractExtnoderange($xml) { + $rsp = array(); + + // Extract data returned + foreach ($xml->xcatresponse->intersectinggroups as $group) { + array_push($rsp, "$group"); + } + + return $rsp; +} ?> \ No newline at end of file diff --git a/xCAT-UI/lib/systemcmd.php b/xCAT-UI/lib/systemcmd.php index 7990aa035..94bbc4444 100644 --- a/xCAT-UI/lib/systemcmd.php +++ b/xCAT-UI/lib/systemcmd.php @@ -1,36 +1,39 @@ -Please login before continuing!"); - exit; -} - -if (isset($_GET["cmd"])) { - // HTTP GET requests - $cmd = $_GET["cmd"]; - $msg = NULL; - $ret = ""; - - if (isset($_GET["msg"])) { - $msg = $_GET["msg"]; - } - - if ($cmd == "ostype") { - $ret = strtolower(PHP_OS); - } else { - $ret = shell_exec($cmd); - } - - echo json_encode(array("rsp"=>$ret, "msg" => $msg)); -} +Please login before continuing!"); + exit; +} + +if (isset($_GET["cmd"])) { + // HTTP GET requests + $cmd = $_GET["cmd"]; + $msg = NULL; + $ret = ""; + + if (isset($_GET["msg"])) { + $msg = $_GET["msg"]; + } + + if ($cmd == "ostype") { + $ret = strtolower(PHP_OS); + } else { + $ret = shell_exec($cmd); + } + + // Remove any HTML that could be used for XSS attacks + $ret = htmlentities($ret, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + $msg = htmlentities($msg, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + echo json_encode(array("rsp"=>$ret, "msg" => $msg)); +} ?> \ No newline at end of file diff --git a/xCAT-UI/lib/uploadfile.php b/xCAT-UI/lib/uploadfile.php new file mode 100644 index 000000000..fa382c587 --- /dev/null +++ b/xCAT-UI/lib/uploadfile.php @@ -0,0 +1,63 @@ + \ No newline at end of file diff --git a/xCAT-UI/lib/zCmd.php b/xCAT-UI/lib/zCmd.php index c2a21eebf..c77f4b5fe 100644 --- a/xCAT-UI/lib/zCmd.php +++ b/xCAT-UI/lib/zCmd.php @@ -1,142 +1,159 @@ -children() as $child) { - foreach ($child->children() as $data) { - $data = str_replace(":|:", "\n", $data); - array_push($rsp, "$data"); - } - } - } - - // Create virtual server - else if (strncasecmp($cmd, "mkvm", 4) == 0) { - // Directory /var/tmp permissions = 777 - // You can write anything to that directory - $userEntry = "/var/tmp/$tgt.txt"; - $handle = fopen($userEntry, 'w') or die("Cannot open $userEntry"); - fwrite($handle, $att); - fclose($handle); - - // CLI command: mkvm gpok3 /tmp/gpok3.txt - // Create user entry - array_unshift($arr, $userEntry); - $xml = docmd($cmd, $tgt, $arr, NULL); - foreach ($xml->children() as $child) { - foreach ($child->children() as $data) { - $data = str_replace(":|:", "\n", $data); - array_push($rsp, "$data"); - } - } - } - - // Run shell script - // This is a typical command used by all platforms. It is put here because - // most of the code needed are already here - else if (strncasecmp($cmd, "xdsh", 4) == 0) { - // Directory /var/tmp permissions = 777 - // You can write anything to that directory - $msgArgs = explode(";", $msg); - $inst = str_replace("out=scriptStatusBar", "", $msgArgs[0]); - $script = "/var/tmp/script$inst.sh"; - - // Write to file - $handle = fopen($script, 'w') or die("Cannot open $script"); - fwrite($handle, $att); - fclose($handle); - - // Change it to executable - chmod($script, 0777); - - // CLI command: xdsh gpok3 -e /var/tmp/gpok3.sh - // Create user entry - array_push($arr, $script); - $xml = docmd($cmd, $tgt, $arr, NULL); - foreach ($xml->children() as $child) { - foreach ($child->children() as $data) { - $data = str_replace(":|:", "\n", $data); - array_push($rsp, "$data"); - } - } - - // Remove this file - unlink($script); - } - - // Reply in the form of JSON - $rtn = array("rsp" => $rsp, "msg" => $msg); - echo json_encode($rtn); -} +children() as $child) { + foreach ($child->children() as $data) { + $data = str_replace(":|:", "\n", $data); + array_push($rsp, "$data"); + } + } + } + + // Create virtual server + else if (strncasecmp($cmd, "mkvm", 4) == 0) { + // Directory /var/tmp permissions = 777 + // You can write anything to that directory + $userEntry = "/var/tmp/$tgt.txt"; + $handle = fopen($userEntry, 'w') or die("Cannot open $userEntry"); + fwrite($handle, $att); + fclose($handle); + + // CLI command: mkvm gpok3 /tmp/gpok3.txt + // Create user entry + array_unshift($arr, $userEntry); + $xml = docmd($cmd, $tgt, $arr, NULL); + foreach ($xml->children() as $child) { + foreach ($child->children() as $data) { + $data = str_replace(":|:", "\n", $data); + array_push($rsp, "$data"); + } + } + } + + // Run shell script + // This is a typical command used by all platforms. It is put here because + // most of the code needed are already here + else if (strncasecmp($cmd, "xdsh", 4) == 0) { + // Directory /var/tmp permissions = 777 + // You can write anything to that directory + $msgArgs = explode(";", $msg); + $inst = str_replace("out=scriptStatusBar", "", $msgArgs[0]); + $script = "/var/tmp/script$inst.sh"; + + // Write to file + $handle = fopen($script, 'w') or die("Cannot open $script"); + fwrite($handle, $att); + fclose($handle); + + // Change it to executable + chmod($script, 0777); + + // CLI command: xdsh gpok3 -e /var/tmp/gpok3.sh + // Create user entry + array_push($arr, $script); + $xml = docmd($cmd, $tgt, $arr, NULL); + foreach ($xml->children() as $child) { + foreach ($child->children() as $data) { + $data = str_replace(":|:", "\n", $data); + array_push($rsp, "$data"); + } + } + + // Remove this file + unlink($script); + } + + // Remove any HTML that could be used for XSS attacks + foreach ($rsp as $key => &$value) { + $whatami = gettype($value); + if ("string" != $whatami) { + //echo "found a non string in rsp array \n"; + foreach ($value as $key2 => $value2){ + //echo "Key2:$key2 Value2 type:",gettype($value2)," value2 data: $value2 \n"; + $value[$key2] = htmlentities($value2, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + } + } else { + //echo "Key:$key Value type:",gettype($value)," value data: $value \n"; + $rsp[$key] = htmlentities($value, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + //echo "New value: $rsp[$key] \n"; + } + } + $msg = htmlentities($msg, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + + // Reply in the form of JSON + $rtn = array("rsp" => $rsp, "msg" => $msg); + echo json_encode($rtn); +} ?> \ No newline at end of file diff --git a/xCAT-UI/xcat/plugins/web.pm b/xCAT-UI/xcat/plugins/web.pm index cd74bde6b..bf0a65b14 100644 --- a/xCAT-UI/xcat/plugins/web.pm +++ b/xCAT-UI/xcat/plugins/web.pm @@ -83,7 +83,8 @@ sub process_request { 'cecsetup' => \&web_cecsetup, 'deletefile' => \&web_deletefile, 'createfolder' => \&web_createfolder, - 'getrepospace' => \&web_getrepospace + 'getrepospace' => \&web_getrepospace, + 'verifynode' => \&web_verifynode, ); # Check whether the request is authorized or not @@ -1982,8 +1983,8 @@ sub web_summary { while (my ($key, $value) = each(%{$attrs})) { web_attrcount($value->[0]->{'os'}, \%oshash); web_attrcount($value->[0]->{'arch'}, \%archhash); - web_attrcount($value->[0]->{'provmethod'}, \%provhash); - web_attrcount($value->[0]->{'nodetype'}, \%typehash); + web_attrcount($value->[0]->{'provmethod'},, \%provhash); + web_attrcount($value->[0]->{'nodetype'},, \%typehash); } $attrs = $nodelistTab->getNodesAttribs(\@nodes, ['status']); @@ -2716,4 +2717,27 @@ sub web_getrepospace() { $callback->({ info => $space }); } +sub web_verifynode() { + my ( $request, $callback, $sub_req ) = @_; + my $cmdOpts = ''; + my $out; + + # Loop to handle all options passed. We don't know how many they will pass + # so we look for 'end' to signify the end. We set a loop variable to 500 which + # we know is much larger than the expected number of arguments. This prevents + # the loop from going on forever should there be an error on the javascript side + # an the 'end' was not passed. + for ( my $i = 0 ; $i < 500 ; $i++ ) { + if ( $request->{arg}->[$i] ne 'end' ) { + $cmdOpts = "$cmdOpts $request->{arg}->[$i]"; + } else { + last; + } + } + + $out = `/opt/xcat/bin/verifynode $cmdOpts`; + + $callback->( { info => $out }); +} + 1; diff --git a/xCAT-client/bin/mkdummyimage b/xCAT-client/bin/mkdummyimage new file mode 100644 index 000000000..facf511c9 --- /dev/null +++ b/xCAT-client/bin/mkdummyimage @@ -0,0 +1,286 @@ +#!/usr/bin/perl +############################################################################### +# IBM(c) 2015 EPL license http://www.eclipse.org/legal/epl-v10.html +############################################################################### +# COMPONENT: mkdummyimage +# +# This script creates a dummy image. +############################################################################### + +use strict; +use warnings; + +use File::Basename; +use File::Path; +use File::Spec; +use File::Temp; +use Getopt::Long; +use MIME::Base64; +use Sys::Hostname; +use Socket; + +my $version = "1.0"; + +my $defaultName = 'dummy.img'; # Default image file name +my $dest = ''; # Target destination (filespec) +my $displayHelp = 0; # Display help information +my $eckdImage = 0; # ECKD image is wanted +my $fbaImage = 0; # FBA image is wanted +my $remoteHost = ''; # Remote host transfer information +my $remoteUser = ''; # Remote user transfer information +my $verbose = 0; # Verbose flag - 0: quiet, 1: verbose +my $versionOpt = 0; # Show version information flag + +# set the usage message +my $usage_string = "Usage:\n + $0 [ --eckd | --fba ] [ -V | --verbose ] + [ -d | --destination ] [-R | --remotehost ]\n + or\n + $0 -v | --version\n + or\n + $0 -h | --help\n + The following options are supported:\n + -d | --destination + File specification of the image file to be created. + Either the filename only or a fully qualified name. + If the destination is within the xCAT MN then + it must be within the directory specified by + the installdir property in the xCAT site table. + The default file name is $defaultName.\n + --eckd Create an empty ECKD disk image. This is the + default image type if neither --eckd or --fba + is specifed.\n + --fba Create an empty FBA disk image\n + -h | --help Display help information\n + -R | --remotehost + Indicates that the destination specified on the + command invocation is the file specification on a + host other than the management node. + The 'host' operand is the IP address or DNS host + name of the target server. A user may be specified + in a similar way as it is specified with the SCP + command using the format 'user\@host' where 'user' + is the name of the user on the remote system and + 'host' operand is as previously stated. The image + is created in the directory specified by the + tmpdir property in the site table and then moved + to the remote host using SCP. After moving the + image off the xCAT MN, the image is removed + from the xCAT MN. Prior to specifying the command, + the keystore on the remote host must be set up with + the public key of the xCAT MN.\n + -v | --version Display the version of this script.\n + -V | --verbose Display verbose processing messages.\n"; + + +#------------------------------------------------------- + +=head3 createImage + + Description : Create the dummy image file. + Arguments : None + Returns : 0 - No error + non-zero - Error detected. + Example : $rc = createImage(); + +=cut + +#------------------------------------------------------- +sub createImage{ + my $rc = 0; + my $buildDir = ''; + my $header; + + # Create a temporary directory in which to create the image. + my $tmpDir = `/opt/xcat/sbin/tabdump site| grep '^"tmpdir",' | sed s/'^"tmpdir","'//g| sed s/'".*'//g`; + chomp $tmpDir; + if ( $tmpDir eq '' ) { + print "Error: The 'tmpdir' value is missing from the site table.\n"; + $rc = 11; + goto FINISH_createImage; + } + $buildDir = mkdtemp( "$tmpDir/image.$$.XXXXXX" ); + + # Create the image + my $imageFile = $defaultName; + open( my $fh, '>', "$buildDir/$imageFile" ) or die "Could not open file '$buildDir/$imageFile'"; + if ( $verbose ) { + print "Creating the image in $buildDir as $imageFile.\n"; + } + + if ( $eckdImage ) { + $header = "xCAT CKD Disk Image:"; + $header = "$header 0 CYL"; + } + elsif ( $fbaImage ) { + $header = "xCAT FBA Disk Image:"; + $header = "$header 0 BLK"; + } + $header = "$header HLen: 0055"; # Header size increased by x from 0055 + $header = "$header GZIP: 0"; + printf $fh "%-512s", "$header"; + close( $fh ); + + # Move the image to the target location. + if ( $remoteHost ne '' ) { + # Do a remote transfer + my $remoteTarget = $remoteHost . ':' . $dest; + if ( $remoteUser ne '' ) { + $remoteTarget = "$remoteUser\@$remoteTarget"; + } + my $scpVerbose = ''; + if ( $verbose ) { + print "Moving the image $imageFile to the remote system $remoteHost as $dest.\n"; + $scpVerbose = '-v' + } + $rc = system( "/usr/bin/scp $scpVerbose -B $buildDir/$imageFile $remoteTarget" ); + if ( $rc ) { + $rc = $rc >> 8; + print "Error: Unable to copy the image $buildDir/$imageFile to the remote host: $remoteHost, rc: $rc\n"; + $rc = 30; + goto FINISH_createImage; + } + } else { + # Move the file to a local directory + $rc = system( "cp $buildDir/$imageFile $dest" ); + if ( $rc ) { + $rc = $rc >> 8; + print "Error: Unable to copy the image $buildDir/$imageFile to the destination: $dest, rc: $rc\n"; + $rc = 40; + goto FINISH_createImage; + } + } + + if ( $remoteHost ne '' ) { + print "Image created on $remoteHost: $dest\n"; + } else { + print "Image created: $dest\n"; + } + +FINISH_createImage: + if ( -d $buildDir ) { + rmtree $buildDir; + } + return $rc; +} + + +#------------------------------------------------------- + +=head3 showHelp + + Description : Show the help inforamtion. + Arguments : None. + Returns : None. + Example : showHelp(); + +=cut + +#------------------------------------------------------- +sub showHelp{ + print "$0 prepares a special image file that contains no disk\ncontents.\n\n"; + print $usage_string; + return; +} + + +#***************************************************************************** +# Main routine +#***************************************************************************** +my $rc = 0; +my $out; + +# Parse the arguments +$Getopt::Long::ignorecase = 0; +Getopt::Long::Configure( "bundling" ); +if (!GetOptions( + 'eckd' => \$eckdImage, + 'd|destination=s' => \$dest, + 'fba' => \$fbaImage, + 'h|help' => \$displayHelp, + 'R|remotehost=s' => \$remoteHost, + 'v|version' => \$versionOpt, + 'V|verbose' => \$verbose )) { + print $usage_string; + goto FINISH_main; +} + +if ( $versionOpt ) { + print "Version: $version\n"; +} + +if ( $displayHelp ) { + showHelp(); +} + +if ( $displayHelp or $versionOpt ) { + goto FINISH_main; +} + +if ( !$eckdImage and !$fbaImage ) { + $eckdImage = 1; +} + +if ( $remoteHost ne '' ) { + $remoteHost =~ s/^\s+|\s+$//g; # trim blanks from both ends of the value + my $spaceCnt = scalar( () = $remoteHost =~ /\s+/g ); + if ( $spaceCnt != 0 ) { + print "Error: Remote host value is not a single word.\n"; + $rc = 1; + goto FINISH_main; + } + if ( $remoteHost =~ /@/ ) { + my @parts = split( /@/, $remoteHost ); + if ( substr( $remoteHost, -1) eq '@' or + @parts > 2 or + !defined $parts[0] or $parts[0] eq '' or + !defined $parts[1] or $parts[1] eq '' ) { + print "Error: Remote host value is not valid.\n" . + " It should be in the form of 'hostname' or 'user\@hostname'.\n"; + $rc = 2; + goto FINISH_main; + } + $remoteUser = $parts[0]; + $remoteHost = $parts[1]; + } else { + $remoteUser = 'root'; + } +} + +# Determine the destination and make certain it is valid. +my $installDir = `/opt/xcat/sbin/tabdump site| grep '^"installdir",' | sed s/'^"installdir","'//g| sed s/'".*'//g`; +chomp $installDir; +if ( $installDir eq '' ) { + print "Error: The 'installDir' value is missing from the site table.\n"; + $rc = 10; + goto FINISH_main; +} + +if ( $dest eq '' ){ + # Set default destination for either a local or remote location. + if ( $remoteHost eq '' ) { + $dest = "$installDir/$defaultName"; + } else { + $dest = "$defaultName"; + } +} else { + # Can only verify local destination here. SCP will verify the remote destination. + if ( $remoteHost eq '' ) { + if ( $dest !~ /\// ) { + $dest = "$installDir/$dest"; + } else { + if ( $dest !~ /^$installDir/ ) { + print "Error: The destination is not within the install directory specified in the site table.\n"; + $rc = 20; + goto FINISH_main; + } + } + } +} + +# Create the image file. +createImage(); + +FINISH_main: +exit $rc; + diff --git a/xCAT-client/bin/pasu b/xCAT-client/bin/pasu index 4139f00de..08b77e746 100755 --- a/xCAT-client/bin/pasu +++ b/xCAT-client/bin/pasu @@ -23,13 +23,24 @@ use Getopt::Long; use POSIX qw(:signal_h :errno_h :sys_wait_h); use Thread qw(yield); + +$::onecli = 0; if ($iam =~ /pasu/) { - $::utilcmd = '/opt/lenovo/toolscenter/asu/asu64'; + $::utilcmd = '/opt/lenovo/onecli/asu'; + $::onecli = 1; + if (!-x $::utilcmd) { + $::onecli = 0; + $::utilcmd = '/opt/lenovo/toolscenter/asu/asu64'; + } if (!-x $::utilcmd) { $::utilcmd = '/opt/ibm/toolscenter/asu/asu64'; } } elsif ($iam =~ /piflash/) { - $::utilcmd = '/opt/xcat/sbin/iflash64 --unattended'; + $::utilcmd = '/opt/lenovo/onecli/iflash64'; + if (!-x $::utilcmd) { + $::utilcmd = '/opt/xcat/sbin/iflash64'; + } + $::utilcmd .= ' --unattended' } my $interface; my $username; @@ -198,7 +209,17 @@ sub processoutput { #This way, one arbiter handles output, no interrupting $line !~ /Licensed Materials - Property of Lenovo/i && $line !~ /\(C\) Copyright IBM Corp. \d+-\d+ All Rights Reserved/i && $line !~ /\(C\) Copyright Lenovo Corp. \d+-\d+ All Rights Reserved/i && - $line !~ /Connected to IMM at IP address/i)) { + $line !~ /Connected to IMM at IP address/i && + $line !~ /Lenovo ASU/i && + $line !~ /^\s*$/i && + $line !~ /Lenovo ToolsCenterSuite CLI/i && + $line !~ /Lenovo XClarity Essentials OneCLI/i && + $line !~ /Invoking SHOW command .../i && + $line !~ /Invoking SET command .../i && + $line !~ /Connected to BMC by IP address/i && + $line !~ /Succeeded running the command /i && + $line !~ /Based on module version /i && + $line !~ /Succeed running command /i)) { print $nodehdl{$readyh} . ": " . $line . "\n"; } } @@ -225,6 +246,9 @@ sub utilnode { } else { foreach my $a (@_) { $args .= ' ' . xCAT::Utils->quote($a); } } + if ($::onecli and $bmc =~ /:/) { + $bmc = "[$bmc]"; + } my $cmd = "$::utilcmd $args --host '$bmc' --user '$username' --password '$passwd' 2>&1 |"; if ($::VERBOSE) { print "forking $cmd\n"; } my $pid = open($$out, $cmd); diff --git a/xCAT-client/bin/pping b/xCAT-client/bin/pping index af13369d4..4bc3af11b 100755 --- a/xCAT-client/bin/pping +++ b/xCAT-client/bin/pping @@ -162,7 +162,7 @@ sub fping_pping { } else { - if (!-x '/usr/bin/fping') + if (!-x '/usr/bin/fping' and !-x '/usr/sbin/fping') { print "fping is not available, please install missing package fping.\n"; exit 1; @@ -199,7 +199,7 @@ sub nmap_pping { @nmap_options = xCAT::TableUtils->get_site_attribute("nmapoptions"); $more_options = $nmap_options[0]; } - open(FPING, "nmap -PE --system-dns --send-ip -sP $more_options " . join(' ', @$nodes) . " 2> /dev/null|") or die("Cannot open nmap pipe: $!"); + open(FPING, "nmap -PE --system-dns --unprivileged --send-ip -sP $more_options " . join(' ', @$nodes) . " 2> /dev/null|") or die("Cannot open nmap pipe: $!"); my $node; while () { if (/Host (.*) \(.*\) appears to be up/) { diff --git a/xCAT-client/bin/verifynode b/xCAT-client/bin/verifynode new file mode 100644 index 000000000..b031ba968 --- /dev/null +++ b/xCAT-client/bin/verifynode @@ -0,0 +1,3025 @@ +#!/usr/bin/perl +############################################################################### +# IBM (C) Copyright 2016 Eclipse Public License +# http://www.eclipse.org/org/documents/epl-v10.html +############################################################################### +# COMPONENT: verifynode +# +# Verify the capabilities of a node. +############################################################################### + +package xCAT_plugin::verifynode; +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} + +$XML::Simple::PREFERRED_PARSER='XML::Parser'; + +use strict; +use warnings; + +use Data::Dumper qw(Dumper); +use File::Basename; +use File::Path; +use File::Spec; +use File::Temp; +use Getopt::Long; +use Getopt::Long qw(GetOptionsFromString); +use lib "$::XCATROOT/lib/perl"; +use MIME::Base64; +use POSIX qw/strftime/; +use Scalar::Util qw( looks_like_number ); +use Sys::Hostname; +use Sys::Syslog qw( :DEFAULT setlogsock ); +use Socket; +use Text::Wrap; +use Time::HiRes qw( gettimeofday sleep ); +use Unicode::UCD qw(charinfo); + +use xCAT::zvmCPUtils; +use xCAT::zvmMsgs; +use xCAT::zvmUtils; + +my $version = "1"; + +my $comments = ''; # Comments for the IVP run +my $dataFile = ''; # Input data file +my $decode = ''; # String specified by the --decode operand. +my $disable = ''; # Disable scheduled IVP from running. +my $displayHelp = 0; # Display help information +my $driver = ''; # Name of driver script +my $driverLoc = '/var/opt/xcat/ivp'; # Local directory containing the driver script, if it exists +my $encode = ''; # String specified by the --encode operand. +my $enable = ''; # Enable scheduled IVP to run. +my $endTime = ''; # Human readable end time +my %hosts; # Information on host nodes known by xCAT MN +my $id = ''; # Id of the IVP run +my %ignored; # List of ignored messages +my $ignoreCnt = 0; # Number of times we ignored a message +my $issueCmdOverIUCV = ''; # Issue a command to a node over IUCV +my $issueCmdToNode = ''; # Issue a command to a node using IUCV or SSH +my %localIPs; # Hash of the Local IP addresses for the xCAT MN system +my $logDir = '/var/log/xcat/ivp'; # Log location +my $logFile = ''; # Log file name and location +my $logFileHandle; # File handle for the log file. +my @ivpSummary; # Summary output lines for an IVP run. +my $locApplSystemRole = '/var/lib/sspmod/appliance_system_role'; +my %mnInfo; # Managed node environment information +my %msgsToIgnore; # Hash of messages to ignore +my $needToFinishLogFile = 0; # If 1 then finishLogFile() needs to be called +my $nodeName = ''; # Name of node to be verified +my $notify = 0; # Notify a user +my $notifyOnErrorOrWarning = 0; # Indicates a log file should be sent if the need to notify + # a user was determined. +my $openstackIP = ''; # IP address of the OpenStack node +my $openstackUser = 'root'; # User on the OpenStack system that can access the + # OpenStack configuration files +my $orchParms = ''; # Orchestrator parms to be stored in the zvmivp table +my $prepParms = ''; # Parameters to pass to the preparation script +my $remove = 0; # Remove a scheduled IVP +my $runBasicIVP = 0; # Run the basic xCAT IVP +my $runCron = 0; # Cron job invocation to run a possible set of IVPs + # on a periodic basis. +my $runFullIVP = 0; # Run the full end to end IVP (compute node and xCAT) +my $schedule = ''; # Hours to schedule an automated IVP +my $scheduledType = ''; # Type of IVP to schedule ('fullivp' or 'basicivp') +my $startTime = ''; # Human readable start time +my $tgtOS = ''; # Target Node's distro & version +my $todayDate = ''; # Today's date in the form 'yyyy-mm-dd' +my $verifyAccess = 0; # Verify system can be accessed +my $verifyCaptureReqs = 0; # Verify systems meets capture requirements +my $verifyCloudInit = 0; # Verify cloud-init installed +my $verifyXcatconf4z = 0; # Verify xcatconf4z +my $versionOpt = 0; # Show version information flag +my $warnErrCnt = 0; # Count of warnings and error messages for a verify set +my $zhcpTarget = ''; # ZHCP server that is related to this verification +my $zvmHost = ''; # z/VM host related to this verification +my $zxcatParms = ''; # Parmeters to pass to zxcatIVP + +# Routines to drive based on the selected test. +my %verifySets = ( + '$decode ne \'\'' => + [ '', # Do not show a function banner. + 'encodeDecodeString()', + ], + '$disable and ! $remove and $schedule eq \'\'' => + [ 'Disabling an IVP run', + 'enableDisableRun( $id )', + ], + '$enable and ! $remove and $schedule eq \'\'' => + [ 'Enabling an IVP run', + 'enableDisableRun( $id )', + ], + '$encode ne \'\'' => + [ 'Encoding a string', + 'encodeDecodeString()', + ], + '$issueCmdOverIUCV ne \'\'' => + [ 'Issue a command to a node using IUCV', + 'cmdOnVM( \'onlyIUCV\' )', + ], + '$issueCmdToNode ne \'\'' => + [ 'Issue a command to a node using IUCV or SSH', + 'cmdOnVM( \'either\' )', + ], + '$remove' => + [ 'Remove an automated periodic IVP', + 'removeIVP( $id )', + ], + '$runBasicIVP' => + [ 'Verifying the basic general setup of xCAT', + 'addLogHeader( \'basicivp\' )', + 'verifyBasicXCAT()', + ], + '$runCron' => + [ 'Cron job for automated verification', + 'driveCronList()', + ], + '$runFullIVP' => + [ 'Verifying the full end-to-end setup of the xCAT and the compute node', + 'addLogHeader( \'fullivp\' )', + 'checkForDefault( \'openstackIP\', \'--openstackIP was not specified\', \'xCAT_master\' )', + 'verifyAccess( $openstackIP ); $rc = 0', + 'getDistro( $openstackIP )', + 'runPrepScript()', + 'runDriverScript()', + ], + '$schedule ne \'\'' => + [ 'Scheduling an automated periodic IVP', + 'scheduleIVP()', + ], + '$verifyAccess' => + [ 'Verifying access to the system', + 'verifyPower( $nodeName )', + 'verifyAccess( $nodeName )' + ], + '$verifyCaptureReqs' => + [ 'Verifying system meets the image requirements', + 'verifyPower( $nodeName )', + 'verifyAccess( $nodeName )', + 'getDistro( $nodeName )', + 'verifyDistro()', + ], + '$verifyCloudInit' => + [ 'Verifying cloud-init is installed and configured', + 'verifyPower( $nodeName )', + 'verifyAccess( $nodeName )', + 'getDistro( $nodeName )', + 'verifyService($nodeName, "cloud-config,2,3,4,5 cloud-final,2,3,4,5 cloud-init,2,3,4,5 cloud-init-local,2,3,4,5")', + 'showCILevel()', + ], + '$verifyXcatconf4z' => + [ 'Verifying xcatconf4z is installed and configured', + 'verifyPower( $nodeName )', + 'verifyAccess( $nodeName )', + 'getDistro( $nodeName )', + 'verifyXcatconf4z( $nodeName )', + ], + '$test' => + [ 'Script test functon.', + 'verifyLogResponse()', + ], + ); + + +# set the usage message +my $usage_string = "Usage:\n + $0 -n \n + or\n + $0 \n + or\n + $0 -v\n + or\n + $0 [ -h | --help ]\n + The following options are supported:\n + -a | --access + Verify access from xCAT MN to node. + --basicivp + Run the basic xCAT IVP. + --capturereqs + Verify that node meets system capture + requirements for OpenStack. + --cmdoveriucv + Issue a command to a node using IUCV. + Specify a period for when combining this + option with the --file option. + --cmdtonode Issue a command to a node using IUCV or SSH + if IUCV is not available. + Specify a period for when combining this + option with the --file option. + -c | --cloudinit + Verify that node has cloud-init installed. + --comments + Comments to specify on the IVP run. + --cron + Driven as a cron job to run a set of periodic + IVPs. + --decode + Decode an encoded string. This is used to + view encoded values in the zvmivp table. + --disable Indicates that the IVP being scheduled should + be disabled from running. + --enable Indicates that the IVP being scheduled should + be enabled to run. This is the default when + neither --disable or --enable is specified. + --encode + Encode a string. This used for debug in order + to create a string to compare to an encoded + string from the zvmivp table. The must be + an ASCII string. This function does not support + encoding a UTF-8 character string. + --file File location containing additional input. + When used with the --cmdoveriucv or --cmdtonode + operands, this file contains the command to issue. + --fullivp + Run the full end-to-end IVP. This + verification checks the compute node and builds + a driver script which is then used to check + the xCAT environment based on the values + gathered in the driver script. + -h | --help + Display help information. + -i | --id + ID to associate with the IVP run. + --ignore + Blank or comma separated list of message ids or + message severities to ignore. Ignored messages are + not counted as failures and do not produce messages. + Instead the number of ignored messages and their + message numbers are displayed at the end of + processing. Recognized message severities: + 'bypass', 'info', 'warning', 'error'. + --notify + Notification of IVP failures should be sent + to a z/VM userid. + -n | --node + Node name of system to verify. + --openstackip + IP address of the OpenStack compute node. + --openstackuser + User to use to access the compute node. + The user defaults to 'root'. + --orchparms + Parameters to be stored in the zvmivp table. These + parameters are passed to this routine when a + scheduled IVP is driven. + --prepparms + Parameters to pass to the preparation script as + part of a full IVP. + --remove + Indicates that an IVP in the zvmivp table should be + removed. The id is specified with the --id + operand. + --schedule + List of hours (in 24 hour format) to periodically + run the IVP. Multiple hours are separated by blanks. + For example, \'0 6 12 18 20\'. + --type < basicivp | fullivp > + Type of IVP to be scheduled. + -v + Display the version of this script. + -x | --xcatconf4z + Verify that node has xcatconf4z installed. + --zxcatparms + Parameters to pass to the zxcatIVP script.\n"; + + +#------------------------------------------------------- + +=head3 addLogHeader + + Description : Add a header to the log file. + Arguments : None + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = addLogHeader(); + +=cut + +#------------------------------------------------------- +sub addLogHeader { + my ( $hType ) = @_; + + logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' ); + + # Generate the header based on the header type. + if ( $hType eq 'basicivp' ) { + logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "This log file was created for a basic xCAT IVP. It consists of output from ". + "zxcatIVP that validates the xCAT management node (MN) and the ZHCP Agents that are used by ". + "the xCAT MN node to manage the z/VM hosts." ); + } elsif ( $hType eq 'fullivp' ) { + logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "This log file was created for a full xCAT IVP which validates the z/VM OpenStack ". + "configuration files, the xCAT management node (MN) and the ZHCP Agents that are used by ". + "the xCAT MN node to manage the z/VM host. The log file contains the following output: output ". + "from the preparation script that validated the OpenStack properties, the contents of the ". + "driver script created by the preparation script to drive the second part of the IVP, output ". + "of the zxcatIVP run that is driven by the driver script to complete the full IVP." ); + } else { + logResponse( 'DF', 'GENERIC_RESPONSE', "VerifyNode log file." ); + } + + logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' ); + + return 0; +} + + +#------------------------------------------------------- + +=head3 checkForDefault + + Description : Determine if a default is needed for + the specified property and set it if + it is needed. Currently, this routine + is only used for the master IP address. + Arguments : Name of property + String to use in a DFLT01 message. + Default or function to perform. + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = checkForDefault( 'openStackIP', '--ip was not specified', 'xCAT_master' ); + +=cut + +#------------------------------------------------------- +sub checkForDefault { + my ( $prop, $reasonString, $default ) = @_; + my $additionalInfo = ''; + my $rc = 0; + my $val; + + eval( "\$val = \$$prop" ); + if ( $val eq '' ) { + if ( $default eq 'xCAT_master' ) { + $default = ''; + if ( exists $mnInfo{'ip'} ) { + $default = $mnInfo{'ip'}; + $additionalInfo = 'The value came from the IP address used as the xCAT MN\'s ' . + 'master IP address that was specified in the site table.'; + } else { + # Use one of the local IPv4 IPs. We don't support IPv6. + if ( keys %localIPs > 0 ) { + # Can't find the MN IP so use the first local IPv4 IP. + foreach my $ip ( keys %localIPs ) { + if ( $ip =~ /:/ ) { + next; + } else { + $default = $ip; + $additionalInfo = 'The function could not determine the master IP address for ' . + 'the xCAT MN so the first local IPv4 address was used.'; + last; + } + } + if ( $default eq '' ) { + $default = '127.0.0.1'; + $additionalInfo = 'The function could not determine the IP address for the xCAT MN ' . + 'and could not find any IPv4 addresses on the system so \'127.0.0.1\' will be used ' . + 'in the hope that it will work.'; + } + } else { + # Don't know the local IPs. + # Default to the IPv4 loopback and let it fail. + $default = '127.0.0.1'; + $additionalInfo = 'The function cound not determine the IP addresses on the ' . + 'xCAT MN system so \'127.0.0.1\' was used.'; + } + } + } + + if ( $rc == 0 ) { + # Found a default, set it in the property. + eval( "\$$prop = \'$default\'" ); + logResponse( 'DF', 'DFLT01', $reasonString, $default, $additionalInfo ); + } + } + + return $rc; +} + + +#------------------------------------------------------- + +=head3 cmdOnVM + + Description : Send a command to a node and show the result. + Arguments : Target function, either 'onlyIUCV' or 'either'. + Returns : Return code: + 0 - Normal Linux success + 255 - Unable to SSH to system + non-zero - command error + Output from the command or a error string on an SSH failure. + Example : $rc = cmdOnVM( 'onlyIUCV' ); + $rc = cmdOnVM( 'either' ); + +=cut + +#------------------------------------------------------- +sub cmdOnVM { + my ( $targetFunc ) = @_; + my $cmd = ''; + my $hcp = ''; + my @lines; + my $rc = 0; + my $out = ''; + my $sudo; + my $user; + my $userid = ''; + + # Get the command to issue. + if ( $targetFunc eq 'onlyIUCV' ) { + if ( $issueCmdOverIUCV ne '.' ) { + $cmd = $issueCmdOverIUCV; + } + } else { + if ( $issueCmdToNode ne '.' ) { + $cmd = $issueCmdToNode; + } + } + + # Use the data file if it was specified. + if ( $dataFile ne '' ) { + if ( -e $dataFile ) { + open my $handle, '<', $dataFile; + chomp( @lines = <$handle> ); + close $handle; + if ( $lines[0] ne '' ) { + $cmd = $lines[0]; + } else { + logResponse( 'DF', 'GENERIC_RESPONSE', "$dataFile does not have anything in the first line."); + goto FINISH_cmdUsingIUCV; + } + } else { + logResponse( 'DF', 'GENERIC_RESPONSE', "$dataFile does not exist."); + goto FINISH_cmdUsingIUCV; + } + } + + # Verify that we have a command to issue. + if ( $cmd eq '' ) { + logResponse( 'DF', 'GENERIC_RESPONSE', "A command to issue was not specified."); + goto FINISH_cmdUsingIUCV; + } + + ($user, $sudo) = xCAT::zvmUtils->getSudoer(); + + # Get the required properties (hcp, userid, user) from the node + $out = `/opt/xcat/bin/lsdef $nodeName -i hcp,userid`; + $rc = $?; + if ( $rc eq 0 ) { + my $fndNode = 0; + @lines = split( '\n', $out ); + my $host = ''; + foreach my $line ( @lines ) { + $line =~ s/^\s+|\s+$//g; # trim blanks from both ends of the string + if ( $line =~ /Object name:/ ) { + $fndNode = 1; + next; + } elsif ( $line =~ /hcp\=/ ) { + ($hcp) = $line =~ m/hcp\=(.*)/; + next; + } elsif ( $line =~ /userid\=/ ) { + ($userid) = $line =~ m/userid\=(.*)/; + next; + } + } + if ( $fndNode != 1 ) { + logResponse( 'DF', 'GENERIC_RESPONSE', "'$nodeName' is not an xCAT node." ); + goto FINISH_cmdUsingIUCV; + } + } else { + $rc = logResponse( 'DFS', 'GNRL01', "$cmd", $rc, $out ); + goto FINISH_cmdUsingIUCV; + } + + # Send the command through IUCV + logResponse( 'DF', '*NONFORMATTED*', "\n**************************\nData for the function call\n**************************" ); + logResponse( 'DF', '*NONFORMATTED*', " Node: $nodeName" ); + if ( $targetFunc eq 'onlyIUCV' ) { + logResponse( 'DF', '*NONFORMATTED*', "z/VM userid: $userid" ); + logResponse( 'DF', '*NONFORMATTED*', " HCP: $hcp" ); + logResponse( 'DF', '*NONFORMATTED*', " User: $user" ); + logResponse( 'DF', '*NONFORMATTED*', " Function: xCAT::zvmUtils->execcmdthroughIUCV" ); + } else { + logResponse( 'DF', '*NONFORMATTED*', " User: $user" ); + logResponse( 'DF', '*NONFORMATTED*', " Function: xCAT::zvmUtils->execcmdonVM" ); + } + logResponse( 'DF', '*NONFORMATTED*', " Cmd: $cmd" ); + + logResponse( 'DF', '*NONFORMATTED*', "\n*********************\nInvoking the function\n*********************" ); + if ( $targetFunc eq 'onlyIUCV' ) { + $out = xCAT::zvmUtils->execcmdthroughIUCV( $user, $hcp, $userid, $cmd ); + } else { + $out = xCAT::zvmUtils->execcmdonVM( $user, $nodeName, $cmd ); + } + logResponse( 'DF', '*NONFORMATTED*', "\n******\nResult\n******\n$out" ); + +FINISH_cmdUsingIUCV: + return $rc; +} + + +#------------------------------------------------------- + +=head3 driveCronList + + Description : Run thru the list of IVPs and run any that + are due to be run. + Arguments : None. + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = driveCronList(); + +=cut + +#------------------------------------------------------- +sub driveCronList { + my $attemptedRuns = 0; + my $disabledRuns = 0; + my @ivps; + my $out = ''; + my $rc = 0; + my $totalRunsInTable = 0; + + # Determine the timestamp and other time related information. + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); + $year = $year + 1900; + $todayDate = sprintf( "%04d-%02d-%02d", $year, $mon + 1, $mday ); + $startTime = sprintf( "%02d:%02d:%02d on %04d-%02d-%02d", + $hour, $min, $sec, $year, $mon + 1, $mday ); + my $currTime = sprintf( "%04d-%02d-%02d_%02d:%02d:%02d", + $year, $mon + 1, $mday, $hour, $min, $sec); + my $newLastRun = "$year $yday $hour"; + + logResponse( 'DFS', '*NONFORMATTED*', "CRON job run started at $startTime." ); + + # Read the z/VM IVP table to get the list of known IVP runs. + $out = `/opt/xcat/sbin/tabdump zvmivp | grep -v "^#"`; + $rc = $?; + my @lines = split( '\n', $out ); + $totalRunsInTable = scalar( @lines ); + if ( $totalRunsInTable != 0 ) { + my $row = 0; + my $nowTotalHours = ( ( $year ) * 8784 ) + ( $yday * 24 ) + $hour; + foreach my $line ( @lines ) { + $row++; + chomp( $line ); + my @field = split( ',', $line ); + for ( my $i=0; $i < scalar( @field ); $i++ ) { + $field[$i] =~ s/^\"|\"$//g; # trim quotes from both ends of the string + } + + # Process the fields from the zvmIVP table. Each row is related to a + # scheduled run. + # Field 0 - Unique IVP ID + # 1 - IP property for the OpenStack system + # 2 - Schedule, hours to run the IVP + # 3 - Last time IVP was run, ( year day hour ) + # 4 - Type of run, e.g. basicivp, fullivp + # 5 - OpenStack user to access the config files + # 6 - Parameters to pass to the orchestrator, verifynode + # 7 - Parameters to pass to the preparator script, prep_zxcatIVP + # 8 - Parameters to pass to the main IVP script, zxcatIVP.pl + # 9 - Comments related to the IVP run + # 10 - Disabled, 1 or YES equals disabled + my %ivpRun; + if ( defined $field[0] and $field[0] ne '' ) { + $ivpRun{'id'} = $field[0]; + } else { + logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row in the ivp table missing a ". + "required property, \'id\'. The row will be treated as disabled." ); + $disabledRuns++; + next; + } + + if ( defined $field[10] and ($field[10] eq '1' or uc( $field[10] ) eq 'YES') ) { + # IVP run is disabled + logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table is ". + "disabled and will not be processed." ); + $disabledRuns++; + next; + } + + if ( defined $field[1] and $field[1] ne '' ) { + $ivpRun{'ip'} = $field[1]; + } else { + # Assume this is a local xCAT IVP run + $ivpRun{'ip'} = 'xcat'; + logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table " . + "has no value specified for the \'ip\' property. " . + "The IVP run will be against the system which is " . + "running the xCAT management node." ); + } + + if ( defined $field[2] and $field[2] ne '' ) { + $ivpRun{'schedule'} = hexDecode( $field[2] ); + } else { + # Default run time is 1 AM + $ivpRun{'schedule'} = '1'; + } + + my $lRYear; + my $lRYDay; + my $lRHour; + + if ( defined $field[3] and $field[3] ne '' ) { + $ivpRun{'last_run'} = $field[3]; + my @parts = split ( '\s', $ivpRun{'last_run'} ); + if ( defined $parts[0] and $parts[0] ne '' ) { + $lRYear = $parts[0]; + } else { + # Missing year, set default to immediately, 0. + $lRYear = 0; + } + if ( defined $parts[1] and $parts[1] ne '' ) { + $lRYDay = $parts[1]; + } else { + # Missing day number, set default to immediately, 0. + $lRYDay = 0; + } + if ( defined $parts[2] and $parts[2] ne '' ) { + $lRHour = $parts[2]; + } else { + # Missing hour, set default to immediately, -1. + $lRHour = 0; + } + } else { + # Force a schedule run + $lRYear = 0; + $lRYDay = 0; + $lRHour = -1; + } + $ivpRun{'last_run'} = "$lRYear $lRYDay $lRHour"; + + # Weed out any runs that are not due to be run. + # Calculate the difference (since 2000) between the last run hour and the current hour, + # ignoring leap years by saying every year is a leap year. + my $totalHourDiff = $nowTotalHours - (( ( $lRYear ) * 8784 ) + ( $lRYDay * 24 ) + $lRHour); + + if ( $totalHourDiff == 0 ) { + # Same hour of the same day of the same year for some reason so ignore this IVP row. + logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table ". + "is being ignored because it was already run this hour." ); + next; + } else { + # Determine the range of hours that are of interest within a 24 hour time period. Anything + # that is more than 24 hours old is automatically overdue and should be run. + if ( $totalHourDiff < 24) { + my $todayStartHour; + my $yesterdayStartHour; + if ( $yday > $lRYDay ) { + # Last run yesterday + $todayStartHour = 0; + $yesterdayStartHour = $lRHour + 1; + } else { + # Last run today + $todayStartHour = $hour - $totalHourDiff; + $yesterdayStartHour = 24; + } + + # Less than a day so we need to worry about which scheduled hours were missed. + my $overdue = 0; + my @schedHours = split ( '\s', $ivpRun{'schedule'} ); + foreach my $sHour ( @schedHours ) { + if ( $sHour == 0 and $sHour ne '0' ) { + # not numeric, ignore + logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table ". + "contains as schedule hour that is non-numeric: $sHour. ". + "The value will be ignored." ); + next; + } + if (( $sHour >= $yesterdayStartHour ) or + ( $sHour > $todayStartHour and $sHour <= $hour ) ) { + logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table ". + "is due to be run. Scheduled hour: $sHour, last run: $lRHour." ); + $overdue = 1; + last; + } + } + if ( $overdue == 0 ) { + # did not find a scheduled hour that is due + logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table is not ". + "due to be run this hour." ); + next; + } + } else { + logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table ". + "is due to be run. Last run over 24 hours ago." ); + } + } + + if ( defined $field[4] and $field[4] ne '' ) { + $ivpRun{'type_of_run'} = lc( $field[4] ); + } else { + $ivpRun{'type_of_run'} = 'not specified'; + } + if ( $ivpRun{'type_of_run'} ne 'basicivp' and $ivpRun{'type_of_run'} ne 'fullivp' ) { + my $badValue = $ivpRun{'type_of_run'}; + if ( exists $mnInfo{'ip'} and ( $ivpRun{'ip'} eq $mnInfo{'ip'} )) { + if (( $mnInfo{'role'} eq 'controller' ) or + ( $mnInfo{'role'} eq 'compute' ) or + ( $mnInfo{'role'} eq 'compute_mn' )) { + $ivpRun{'type_of_run'} = 'fullivp'; + } else { + $ivpRun{'type_of_run'} = 'basicivp'; + } + } else { + $ivpRun{'type_of_run'} = 'basicivp'; + } + logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table contains ". + "an unknown run type value of \'$badValue\'. Instead ". + "a run type of \'$ivpRun{'type_of_run'}\' will be performed." ); + } + + if ( defined $field[5] and $field[5] ne '' ) { + $ivpRun{'access_user'} = hexDecode( $field[5] ); + } else { + $ivpRun{'access_user'} = ''; + } + + if ( defined $field[6] and $field[6] ne '' ) { + $ivpRun{'orch_parms'} = hexDecode( $field[6] ); + } else { + $ivpRun{'orch_parms'} = ''; + } + + if ( defined $field[7] and $field[7] ne '' ) { + $ivpRun{'prep_parms'} = hexDecode( $field[7] ); + } else { + $ivpRun{'prep_parms'} = ''; + } + + if ( defined $field[8] and $field[8] ne '' ) { + # Ensure that it is reencoded to pass along to do the actual work. + $ivpRun{'main_ivp_parms'} = hexEncode( $field[8] ); + } else { + $ivpRun{'main_ivp_parms'} = ''; + } + + if ( defined $field[9] and $field[9] ne '' ) { + $ivpRun{'comments'} = hexDecode( $field[9] ); + } else { + $ivpRun{'comments'} = ''; + } + + push @ivps, \%ivpRun; + } + } else { + # Table is empty. Create a single run for the z/VM related to the + # xCAT MN. + logResponse( 'DS', 'GENERIC_RESPONSE', "The ivp table is empty. Default IVPs will be enabled." ); + if ( exists $mnInfo{'node'} ) { + # First IVP is a full IVP for an OpenStack related xCAT at 1 am. + # Otherwise it is a basic IVP. + my %ivpRun; + $ivpRun{'id'} = 1; + if ( exists $mnInfo{'ip'} ) { + $ivpRun{'ip'} = $mnInfo{'ip'}; + } else { + $ivpRun{'ip'} = 'xcat'; + } + $ivpRun{'schedule'} = '1'; + if ( $mnInfo{'role'} eq 'controller' or $mnInfo{'role'} eq 'compute' or $mnInfo{'role'} eq 'compute_mn' ) { + $ivpRun{'type_of_run'} = 'fullivp'; + $ivpRun{'access_user'} = 'root'; + } else { + $ivpRun{'type_of_run'} = 'basicivp'; + $ivpRun{'access_user'} = ''; + } + $ivpRun{'orch_parms'} = ''; + $ivpRun{'prep_parms'} = ''; + $ivpRun{'main_ivp_parms'} = ''; + $ivpRun{'comments'} = 'Default Full IVP run'; + $ivpRun{'defaultRun'} = 'run'; + push @ivps, \%ivpRun; + $totalRunsInTable++; + + # Second IVP is a basic IVP run each hour except for 1 am when a full IVP is run. + my %ivpRun2; + $ivpRun2{'id'} = 2; + if ( exists $mnInfo{'ip'} ) { + $ivpRun2{'ip'} = $mnInfo{'ip'}; + } else { + $ivpRun2{'ip'} = 'xcat'; + } + $ivpRun2{'schedule'} = '0 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23'; + $ivpRun2{'type_of_run'} = 'basicivp'; + $ivpRun2{'access_user'} = ''; + $ivpRun2{'orch_parms'} = ''; + $ivpRun2{'prep_parms'} = ''; + $ivpRun2{'main_ivp_parms'} = ''; + $ivpRun2{'comments'} = 'Default Basic IVP run'; + $ivpRun2{'defaultRun'} = 'runLater'; + push @ivps, \%ivpRun2; + $totalRunsInTable++; + } else { + # xCAT MN does not exist as a node so we will only do a basic IVP the system. + # This is a very abnormal case. We deal in the abnormal so let's run some type + # of IVP but not define it in the table. + logResponse( 'DFS', 'MN03' ); + my %ivpRun; + $ivpRun{'id'} = 1; + if ( exists $mnInfo{'ip'} ) { + $ivpRun{'ip'} = $mnInfo{'ip'}; + } else { + $ivpRun{'ip'} = 'xcat'; + } + $ivpRun{'schedule'} = '0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23'; + $ivpRun{'type_of_run'} = 'basicivp'; + $ivpRun{'access_user'} = ''; + $ivpRun{'orch_parms'} = ''; + $ivpRun{'prep_parms'} = ''; + $ivpRun{'main_ivp_parms'} = ''; + $ivpRun{'comments'} = 'Default Basic IVP run'; + $ivpRun{'defaultRun'} = 'noTableUpdate'; + push @ivps, \%ivpRun; + $totalRunsInTable++; + } + } + + # Handle pruning, if necessary. + if ( $hour == 0 ) { + pruneLogs( $year, $mon + 1, $mday ); + } + + # Go thru the list of IVPs and drive a run for each IVP + # that is due to be run. + foreach my $ivp ( @ivps ) { + my %ivpRun = %$ivp; + + # Build the verify node command. + my $cmd = '/opt/xcat/bin/verifynode -n xcat --notify'; + + if ( $ivpRun{'type_of_run'} eq 'fullivp' ) { + $cmd = "$cmd --fullivp --openstackip \'$ivpRun{'ip'}\' --openstackuser \'" . hexEncode( $ivpRun{'access_user'} ) . "\'"; + } else { + $cmd = "$cmd --basicivp"; + } + + if ( $ivpRun{'orch_parms'} ne '' ) { + $cmd = "$cmd $ivpRun{'orch_parms'}"; # Don't hex encode orchestrator parms + } + + if ( $ivpRun{'prep_parms'} ne '' ) { + $cmd = "$cmd --prepparms \'" . hexEncode( $ivpRun{'prep_parms'} ) . "\'"; + } + + if ( $ivpRun{'main_ivp_parms'} ne '' ) { + $cmd = "$cmd --zxcatparms \'" . hexEncode( $ivpRun{'main_ivp_parms'} ) . "\'"; + } + + # Update the table to indicate the time we start the IVP run. + if ( ! exists $ivpRun{'defaultRun'} ) { + my $chtabCmd = "/opt/xcat/sbin/chtab id=\'$ivpRun{'id'}\' zvmivp.last_run=\'$newLastRun\'"; + $out = `$chtabCmd`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DS', '*NONFORMATTED*', "\'$chtabCmd\' failed for IVP ID($ivpRun{'id'}), ip: $ivpRun{'ip'}, rc: $rc, out: $out\n" ); + } + } elsif ( $ivpRun{'defaultRun'} ne 'noTableUpdate' ) { + logResponse( 'DS', '*NONFORMATTED*', "Adding IVP ID($ivpRun{'id'}) to the z/VM IVP table: $ivpRun{'comments'}\n" ); + my $chtabCmd = "/opt/xcat/sbin/chtab id=\'$ivpRun{'id'}\' ". + "zvmivp.ip=\'$ivpRun{'ip'}\' ". + "zvmivp.schedule=\'$ivpRun{'schedule'}\' ". + "zvmivp.last_run=\'$newLastRun\' ". + "zvmivp.type_of_run=\'$ivpRun{'type_of_run'}\' ". + "zvmivp.access_user=\'" . hexEncode( $ivpRun{'access_user'} ) . "\' ". + "zvmivp.comments=\'" . hexEncode( $ivpRun{'comments'} ) . "\' "; + $out = `$chtabCmd`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DS', '*NONFORMATTED*', "\'$chtabCmd\' failed for ID($ivpRun{'id'}), ip: $ivpRun{'ip'}, rc: $rc, out: $out\n" ); + } + + # Skip running this one if it is marked 'runLater'. + # A basic IVP is not needed if a full IVP is going to be run. + if ( $ivpRun{'defaultRun'} eq 'runLater' ) { + logResponse( 'DS', '*NONFORMATTED*', "Ignoring IVP ID($ivpRun{'id'}) for this hour. It will be run next hour. IVP comment: $ivpRun{'comments'}\n" ); + next; + } + } + + # Drive the run. + $attemptedRuns++; + my $logComments = ''; + if ( $ivpRun{'comments'} eq '' ) { + $logComments = "Running IVP ID($ivpRun{'id'})"; + } else { + $logComments = "Running IVP ID($ivpRun{'id'}) - $ivpRun{'comments'}"; + } + logResponse( 'DS', '*NONFORMATTED*', "$logComments" ); + $out = `$cmd`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DS', '*NONFORMATTED*', "The IVP run for ID($ivpRun{'id'}) returned a ". + "non-zero return code, rc: $rc\n" ); + } + } + + logResponse( 'DFS', '*NONFORMATTED*', "IVP CRON results: $totalRunsInTable runs considered, $disabledRuns runs disabled, $attemptedRuns runs attempted" ); + $rc = 0; + return $rc; +} + + +#------------------------------------------------------- + +=head3 enableDisableRun + + Description : Enable or Disable command line function. + Arguments : ID of the IVP to be disabled + Global input set by command operands are used + by this routine: + $disable - Disable a run. + $enable - Enable a run. + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = enableDisableRun(); + +=cut + +#------------------------------------------------------- +sub enableDisableRun { + my ( $id ) = @_; + my %ids; + my $rc = 0; + + if ( $id eq '' ) { + logResponse( 'DF', 'OPER01', '--id' ); + goto FINISH_enableDisableRun; + } + + # Get the list of IVP ids in the zvmivp table. + my $cmd = '/opt/xcat/sbin/tabdump zvmivp | grep -v "^#"'; + my $out = `$cmd`; + $rc = $?; + if ( $rc ne 0 ) { + logResponse( 'DF', 'GNRL04', $cmd, $rc, $out ); + goto FINISH_enableDisableRun; + } + + my @lines = split( '\n', $out ); + foreach my $line ( @lines ) { + chomp( $line ); + my ($ivpId, $junk) = split( ',', $line, 2 ); + $ivpId =~ s/^\"|\"$//g; # trim quotes from both ends of the string + $ivpId =~ s/^\s+|\s+$//g; # trim spaces from both ends of the string + if ( $ivpId ne '' ) { + $ids{$ivpId} = 1; + } + } + + # Validate the specified id. + if ( ! exists $ids{$id} ) { + logResponse( 'DF', 'ID03', $id ); + } + + my $action; + my $disableFlag = ''; + if ( $disable ) { + $disableFlag = 'YES'; + $action = 'disable'; + } else { + $action = 'enable'; + } + + # Update the table. + logResponse( 'DS', '*NONFORMATTED*', "Updating the z/VM IVP table (zvmivp) to $action $id" ); + my $chtabCmd = "/opt/xcat/sbin/chtab id='$id' zvmivp.disable=\'$disableFlag\'"; + $out = `$chtabCmd`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DS', '*NONFORMATTED*', "\'$chtabCmd\' failed for ID($id), rc: $rc, out: $out\n" ); + $rc = 1; + } + +FINISH_enableDisableRun: + return $rc; +} + + +#------------------------------------------------------- + +=head3 encodeDecodeString + + Description : Encode and decode command line function. + Arguments : Global input set by command operands are used + by this routine: + $decode - String to be decoded if not ''. + $encode - String to be encoded if not ''. + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = encodeDecodeString(); + +=cut + +#------------------------------------------------------- +sub encodeDecodeString { + my $newVal = ''; + if ( $decode ne '' ) { + binmode(STDOUT, ":utf8"); + print( "Value is: '" . hexDecode( $decode ) . "'\n" ); + } + + if ( $encode ne '' ) { + print( "Value is: '" . hexEncode( $encode ) . "'\n" ); + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 finishLogFile + + Description : Complete the log file for the run and + send it to the notify user if necessary. + Arguments : None + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = finishLogFile(); + +=cut + +#------------------------------------------------------- +sub finishLogFile { + my $rc = 0; + $needToFinishLogFile = 0; + + # Add the summary information to the log file. + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); + $endTime = sprintf("%02d:%02d:%02d on %04d-%02d-%02d", + $hour, $min, $sec, $year + 1900, $mon + 1, $mday ); + + logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' ); + logResponse( 'DF', 'GENERIC_RESPONSE', 'Results of the IVP run:\n' ); + logResponse( 'DF', 'GENERIC_RESPONSE', "Run started at $startTime and ended at $endTime." ); + foreach my $line ( @ivpSummary ) { + logResponse( 'DF', 'GENERIC_RESPONSE', $line ); + } + if ( $ignoreCnt != 0 ){ + logResponse( 'DFS', 'GENERIC_RESPONSE', "The orchestrator script (verifynode) ignored messages $ignoreCnt times." ); + my @ignoreArray = sort keys %ignored; + my $ignoreList = join ( ', ', @ignoreArray ); + logResponse( 'DFS', 'GENERIC_RESPONSE', "Message Ids of ignored messages by verifynode: $ignoreList" ); + } + logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' ); + + # Notify the z/VM userid, if necessary. + if ( $notify and $notifyOnErrorOrWarning ) { + notifyUser(); + } + +FINISH_finishLogFile: + return $rc; +} + + +#------------------------------------------------------- + +=head3 getDistro + + Description : Create the dummy image file. + Arguments : Node name or IP address + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = getDistro(); + +=cut + +#------------------------------------------------------- +sub getDistro { + my ( $nodeOrIP ) = @_; + my $rc = 0; + + $tgtOS = xCAT::zvmUtils->getOsVersion( $::SUDOER, $nodeOrIP ); + +FINISH_getDistro: + return $rc; +} + + +#------------------------------------------------------- + +=head3 getLocalIPs + + Description : Get the IP addresses from ifconfig. + Arguments : Node name or IP address + Returns : return code (Currently always 0) + 0 - No error + non-zero - Terminating error detected. + Hash of local IP addresses + Example : $rc = getLocalIPs(); + +=cut + +#------------------------------------------------------- +sub getLocalIPs { + my $ip; + my $junk; + my $rc = 0; + + my $out = `/sbin/ip addr | grep -e '^\\s*inet' -e '^\\s*inet6'`; + my @lines = split( '\n', $out ); + foreach my $line ( @lines ) { + my @parts = split( ' ', $line ); + ($ip) = split( '/', $parts[1], 2 ); + $localIPs{$ip} = 1; + } + +FINISH_getLocalIPs: + return $rc; +} + + +#------------------------------------------------------- + +=head3 getMNInfo + + Description : Get information related to the xCAT MN + and the z/VM system where it is running. + Arguments : None + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = getMNInfo(); + +=cut + +#------------------------------------------------------- +sub getMNInfo { + my $cmd; + my $hostNode; + my @lines; + my $masterIP = ''; + my $out = ''; + my @parts; + my $rc = 0; + my $xcatMN; + + # Get the list of Local IP addresses + getLocalIPs(); + + # Wait up to 10 minutes for xcatd to come up. + my $sleepTime = 60; + my $maxWaits = 10; + for ( my $i=1; $i<=$maxWaits; $i++ ) { + # lsdef uses the xCAT daemon. We use that to see if it is started. + `/opt/xcat/bin/lsdef`; + if ( $? == 0 ) { + last; + } else { + logResponse( 'DFS', 'WAIT01', $sleepTime, $i, $maxWaits ); + sleep( $sleepTime ); + } + } + + # Get information related to all of the host nodes + $cmd = '/opt/xcat/bin/lsdef -w mgt=zvm -w hosttype=zvm -i hcp'; + $out = `$cmd`; + $rc = $?; + if ( $rc == 0 ) { + @lines = split( '\n', $out ); + my $host = ''; + foreach my $line ( @lines ) { + $line =~ s/^\s+|\s+$//g; # trim blanks from both ends of the string + if ( $line =~ /Object name: / ) { + ($host) = $line =~ m/Object name: (.*)/; + next; + } elsif ( $line =~ /hcp\=/ ) { + ($hosts{$host}{'hcp'}) = $line =~ m/hcp\=(.*)/; + next; + } + } + } else { + $rc = logResponse( 'DFS', 'GNRL01', "$cmd", $rc, $out ); + $notify = 1; + } + + # Get key info related to the xCAT MN and the notify targets from the site table. + $mnInfo{'PruneIVP'} = 7; + $cmd = "/opt/xcat/sbin/tabdump site"; + $out = `$cmd`; + $rc = $?; + if ( $rc == 0 ) { + @lines = split( '\n', $out ); + @lines = grep( /^\"master\"|^\"zvmnotify\"|^\"zvmpruneivp\"/, @lines ); + foreach my $line ( @lines ) { + $line =~ s/^\s+|\s+$//g; # trim blanks from both ends of the string + @parts = split( ',', $line ); + $parts[1] =~ s/\"//g; + if ( $parts[0] =~ /^\"master\"/ ) { + $masterIP = $parts[1]; + } elsif ( $parts[0] =~ /^\"zvmnotify\"/ ) { + my @notifyInfo = split( ';', $parts[1] ); + my $notifyHost = ''; + my $notifyUser = ''; + foreach my $hostUser ( @notifyInfo ) { + ($notifyHost) = $hostUser =~ m/(.*)\(/; + ($notifyUser) = $hostUser =~ m/\((.*)\)/; + if ( defined $notifyHost and $notifyHost ne '' and defined $notifyUser and $notifyUser ne '' ) { + $hosts{$notifyHost}{'notifyUser'} = uc( $notifyUser ); + } else { + $rc = logResponse( 'DFS', 'SITE01', 'zvmnotify', $parts[1], $hostUser ); + $notify = 1; + } + } + } elsif ( $parts[0] =~ /^\"zvmpruneivp\"/ ) { + $mnInfo{'PruneIVP'} = $parts[1]; + } + } + } else { + # Unable to read the site table + $rc = logResponse( 'DFS', 'GNRL01', "$cmd", $rc, $out ); + $notify = 1; + } + + # Find a node that has the same address as the master IP and then find + # the host node that relates to that node. + if ( $masterIP eq '' ) { + # Unable to get the master value + $rc = logResponse( 'DFS', 'SITE02', 'master' ); + } else { + $cmd = "/opt/xcat/bin/lsdef -w ip=$masterIP -i hcp"; + $out = `$cmd`; + $rc = $?; + if ( $rc == 0 ) { + @lines = split( '\n', $out ); + foreach my $line ( @lines ) { + $line =~ s/^\s+|\s+$//g; # trim blanks from both ends of the string + if ( $line =~ /Object name: / ) { + ($xcatMN) = $line =~ m/Object name: (.*)/; + $mnInfo{'node'} = $xcatMN; + $mnInfo{'ip'} = $masterIP; + next; + } elsif ( $line =~ /hcp\=/ ) { + ($mnInfo{'hcp'}) = $line =~ m/hcp\=(.*)/; + next; + } + } + } else { + $rc = logResponse( 'DFS', 'MN01', $masterIP, $cmd, $rc, $out ); + } + + # Find the host node which uses the hcp. + foreach $hostNode ( keys %hosts ) { + if ( exists $hosts{$hostNode}{'hcp'} and $hosts{$hostNode}{'hcp'} eq $mnInfo{'hcp'} ) { + if ( exists $hosts{$hostNode}{'notify'} ) { + $hosts{$hostNode}{'notify'} = $hosts{$hostNode}{'notify'} . 'm'; + } else { + $hosts{$hostNode}{'notify'} = 'm'; + } + $mnInfo{'host'} = $hostNode; + } + } + } + + # The following is useful in a z/VM CMA system only. + # As a safety measure, in case the site table is lost or does not have zvmnotify property, + # read the OPNCLOUD application system role file to find the value of the 'notify' property + # and remember it with the xCAT MN information. + # Also, determine the system role. + if ( -e $locApplSystemRole ) { + $out = `cat /var/lib/sspmod/appliance_system_role | grep -e '^notify\=' -e '^role\='`; + @lines = split( '\n', $out ); + foreach my $line ( @lines ) { + $line =~ s/^\s+|\s+$//g; # trim blanks from both ends of the string + my ($key, $value) = split( '=', $line, 2 ); + #($mnInfo{'notifyUser'}) = $line =~ m/^notify\=(.*)/; + if ( $key eq 'role' ) { + $mnInfo{'role'} = lc( $value ); + } + if ( $key eq 'notify' ) { + $mnInfo{'notifyUser'} = uc( $value ); + } + } + } else { + # Not CMA. Indicate role is not set. + $mnInfo{'role'} = ''; + } +} + + +#------------------------------------------------------- + +=head3 getOpenStackLevel + + Description : Get the OpenStack version level as a + name. + Arguments : IP address of OpenStack compute node. + Returns : string - OpenStack version name + (e.g. NEWTON), or + null string - error + Example : $level = getOpenStackLevel(); + +=cut + +#------------------------------------------------------- +sub getOpenStackLevel { + my ( $nodeOrIP, $openstackUser ) = @_; + my $cmd; + my $level = ''; + my $numWords = 0; + my $out = ''; + my @parts; + my $rc; + my %openStackVersion; + + # Get the list of known versions + $cmd = 'cat /opt/xcat/openstack.versions'; + $out = `$cmd`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DFS', 'GNRL01', $cmd, $rc, $out ); + $level = ''; + goto FINISH_getOpenStackLevel; + } + + my @versionLines = split ( /\n/, $out ); + foreach my $versionLine ( @versionLines ) { + if ( $versionLine =~ /^#/ ) { next; } + @parts = split( ' ', $versionLine ); + $openStackVersion{$parts[0]} = $parts[1]; + } + + # Get the version information from the OpenStack node + $cmd = "nova-manage --version 2>&1"; + ($rc, $out) = sshToNode( $openstackIP, $openstackUser, $cmd ); + if ( $rc != 0 ) { + # SSH failed, message already sent. + goto FINISH_getOpenStackLevel; + } + $out =~ s/^\s+|\s+$//g; # trim blanks from both ends of the string + ++$numWords while $out =~ /\S+/g; + if ( $numWords != 1 ) { + logResponse( 'DFS', 'GOSL01', $cmd, $openstackIP, $rc, $out ); + goto FINISH_getOpenStackLevel; + } + + @parts = split( '\.', $out ); + if ( !exists $parts[0] or !exists $parts[1] ) { + logResponse( 'DFS', 'GOSL01', $cmd, $openstackIP, $rc, $out ); + goto FINISH_getOpenStackLevel; + } elsif ( exists $openStackVersion{"$parts[0]."} ) { + $level = $openStackVersion{"$parts[0]."} + } elsif ( exists $openStackVersion{"$parts[0].$parts[1]."} ) { + $level = $openStackVersion{"$parts[0].$parts[1]."} + } else { + logResponse( 'DFS', 'GOSL02', $cmd, $openstackIP, $rc, $out ); + goto FINISH_getOpenStackLevel; + } + +FINISH_getOpenStackLevel: + return $level; +} + + +#------------------------------------------------------- + +=head3 hexDecode + + Description : Convert a string of printable hex + characters (4 hex characters per actual + character) into the actual string that + it represents. The string should + begin with 'HexEncoded:' which indicates + that it is encoded. The routine tolerates + getting called with a string that is not + not encoded and will return the string that + was passed to it instead of trying to decode + it. + Arguments : printable hex value + Returns : Perl string + Example : $rc = hexDecode(); + +=cut + +#------------------------------------------------------- +sub hexDecode { + my ( $hexVal ) = @_; + my $result = ''; + + if ( $hexVal =~ /^HexEncoded:/ ) { + ($hexVal) = $hexVal =~ m/HexEncoded:(.*)/; + my @hexes = unpack( "(a4)*", $hexVal); + for ( my $i = 0; $i < scalar(@hexes); $i++ ) { + $result .= chr( hex( $hexes[$i] ) ); + } + } else { + $result = $hexVal; + } + + return $result; +} + + +#------------------------------------------------------- + +=head3 hexEncode + + Description : Convert a string into a string of + printable hex characters in which each + character in the original string is + represented by the 2 byte (4 char) hex + code value. The string is preceded by + 'HexEncoded:' to indicate that it has + been encoded. The routine will tolerate + getting called with a string that has + already been encoded and not reencode it. + Arguments : ASCII or Unicode string + Returns : Hex string + Example : $rc = hexEncode(); + +=cut + +#------------------------------------------------------- +sub hexEncode { + my ( $str ) = @_; + my $hex; + my $result = $str; # All work done within the result variable. + + if ( $result ne '' ) { + # Encode the string if is not already encoded. Otherwise, leave it alone. + if ( $result !~ /^HexEncoded:/ ) { + $result =~ s/(.)/sprintf("%04x",ord($1))/eg; + $result = "HexEncoded:$result"; + } + } + + return $result; +} + + +#------------------------------------------------------- + +=head3 logResponse + + Description : Build and log the response. + Arguments : Target destination for the response. This is + string which can contain a charater for each + possible destination, e.g 'DSF'. The values are: + D - send to STDOUT + S - send to syslog + F - send to the log file + The default is 'DF' so that we send the output + to STDOUT and put it in the log file. + message ID or special flag: + *NONFORMATTED* indicates that the message build should not + be invoked but instead the message substitutions are + lines for the message to be produced. + *RESET* indicates that the message counter should be reset. + Array of message substitutions + Returns : 0 - No error, general response or info message detected. + 1 - Non-terminating message detected. + 2 - Terminating message detected. + Example : $rc = logResponse( 'D', 'VX01' ); + $rc = logResponse( '', 'VX03', $nodeName, $sub2); + $rc = logResponse( 'DFS', 'VX03', $nodeName, 'sub2a'); + +=cut + +#------------------------------------------------------- +sub logResponse { + my ( $dest, $msgId, @msgSubs ) = @_; + my $rc = 0; + my $extraInfo = ''; + my $msg = ''; + my @msgLines; + my $sev; + my $line; + + if ( $msgId eq '*RESET*' ) { + $warnErrCnt = 0; + goto FINISH_logResponse; + } elsif ( $msgId eq '*NONFORMATTED*' ) { + $rc = 0; + if ( @msgSubs ) { + foreach my $line ( @msgSubs ) { + $msg = "$msg$line\n"; + } + } else { + $msg = '\n'; + } + $sev = 0; + } else { + ( $rc, $sev, $msg, $extraInfo ) = xCAT::zvmMsgs->buildMsg('VERIFYNODE', $msgId, \@msgSubs); + if ( defined $msgsToIgnore{$msgId} ) { + # Ignore this message id + $ignored{$msgId} = 1; + $ignoreCnt += 1; + print( "Message $msgId is being ignored but would have occurred here.\n" ); + goto FINISH_logResponse; + } elsif ( defined $msgsToIgnore{$sev} ) { + # Ignoring all messages of this severity. + $ignored{$msgId} = 1; + $ignoreCnt += 1; + print( "Message $msgId is being ignored but would have occurred here.\n" ); + goto FINISH_logResponse; + } + } + + if ( $sev >= 4 ) { + $warnErrCnt += 1; + } + + # Send the message to the requested destination. + if ( $dest =~ 'D' ) { + print "$msg"; # Send message to STDOUT + } + if ( $dest =~ 'F' and defined $logFileHandle ) { + print $logFileHandle $msg; + } + if ( $dest =~ 'S' ) { + my $logMsg = $msg; + $logMsg =~ s/\t//g; + $logMsg =~ s/\n/ /g; + syslog( 'err', $logMsg ); + } + + # Send the extra info to the requested destination (never send it to syslog). + if ( $extraInfo ne '' ) { + if ( $dest =~ 'D' ) { + print "$extraInfo"; + } + if ( $dest =~ 'F' and defined $logFileHandle ) { + print $logFileHandle $msg; + } + } + +FINISH_logResponse: + return $rc; +} + + +#------------------------------------------------------- + +=head3 notifyUser + + Description : Notify a z/VM user. Send a message + and the log as a SPOOL file. + Arguments : Node name or IP address + Returns : 0 - Always ok. + Example : $rc = notifyUser(); + +=cut + +#------------------------------------------------------- +sub notifyUser { + my $cmd; + my $host; + my @hostOrder; + my $msg = ''; + my $out = ''; + my $rc = 0; + my $tempFile; + my $th; + + # Determine who we should notify based on the host related to the verification. + # The driver script would have set the host related to an full IVP (if we can trust it). + # If we cannot get to the host related to the run then we fall back to sending + # the notification to the user on the host in which the xCAT MN is running. + # If that fails then "tough luck, Chuck". + my $mnAdded = 0; + foreach $host ( keys %hosts ) { + if ( exists $hosts{$host}{'notify'} and exists $hosts{$host}{'hcp'} and exists $hosts{$host}{'notifyUser'} ) { + if ( $hosts{$host}{'notify'} =~ /d/ ) { + # Driver script specified hosts go on the top of the stack. + push @hostOrder, $host; + if ( $hosts{$host}{'notify'} =~ /m/ ) { + # The host related to the MN is already in the list + $mnAdded = 1; + } + } elsif ( $hosts{$host}{'notify'} =~ /m/ ) { + # Management node systems go on the bottom as a fall back plan. + unshift @hostOrder, $host; + $mnAdded = 1; + } + } + } + if ( $mnAdded == 0 and exists $mnInfo{'hcp'} and exists $mnInfo{'notifyUser'} ) { + # Did not find a host related to this management node but we have the + # necessary information to send the notification so add a dummy host + # to the hosts hash and add the dummy host to the end of the hostOrder + # stack to be used when all other notification attemps fail. + $host = '*DEFAULT_MN_HOST*'; + $hosts{$host}{'notify'} = 'm'; + $hosts{$host}{'notifyUser'} = $mnInfo{'notifyUser'}; + $hosts{$host}{'hcp'} = $mnInfo{'hcp'}; + unshift @hostOrder, $host; + } + + # Prepare the message. + $msg = "The xCAT IVP detected some possible issues. A log file is being sent to your reader."; + + # Prepare the log file by removing tabs and splitting the log file at 80 character lines. + $tempFile = mktemp( "$logDir/$logFile.XXXXXX" ); + `expand $logDir/$logFile | fold -w 80 1>$tempFile`; + + # Send the message and log file to the first entity in the host order list that lets us + # successfully do so. + my $done = 0; + my $failed = 0; + foreach $host ( @hostOrder ) { + # Check if zHCP's punch is online and online it if it is not. + ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', 'cat /sys/bus/ccw/drivers/vmur/0.0.000d/online' ); + chomp( $out ); + if ($rc != 0 or $out != 1) { + $cmd = '/sbin/cio_ignore -r 000d;/sbin/chccwdev -e 000d'; + ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', $cmd ); + chomp( $out ); + if ( $rc != 0 or !( $out =~ m/Done$/i ) ) { + $rc = logResponse( 'DFS', 'GNRL03', $hosts{$host}{'hcp'}, $cmd, $rc, $out ); + next; + } + ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', 'which udevadm &> /dev/null && udevadm settle || udevsettle' ); + # Don't worry about the udevadm settle. If it remains a problem then we will see it on the next command to ZHCP. + } + + # Send log file. It will exist temporarily on the ZHCP agent in the /tmp directory + # under its original log file name. + $rc = xCAT::zvmUtils->sendFile( 'root', $hosts{$host}{'hcp'}, "$tempFile", "/tmp/$logFile" ); + if ( $rc != 0 ) { + # An error is not a problem because the zhcp node could be logged off. + next; + } + + # Punch the file from the ZHCP agent to the target user. + $out = xCAT::zvmCPUtils->punch2Reader( 'root', $hosts{$host}{'hcp'}, $hosts{$host}{'notifyUser'}, "/tmp/$logFile", 'XCAT_IVP.RESULTS', '-t', 'A' ); + if ( $out ne 'Done' ) { + $rc = logResponse( 'DFS', 'GNRL02', "/tmp/$logFile", $hosts{$host}{'hcp'}, $hosts{$host}{'notifyUser'}, $host, "$logDir/$logFile", $out ); + $failed = 1; + } + + # Clean up the ZHCP node. + ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', "rm -f /tmp/$logFile" ); + if ( $rc != 0 ) { + $rc = logResponse( 'DFS', 'GNRL03', $hosts{$host}{'hcp'}, "rm -f /tmp/$logFile", $rc, $out ); + next; + } + + # Try another host if we failed to send the file. + if ( $failed ) { + $failed = 0; + next; + } + + # Send a message if the user is logged on the system. + ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', "vmcp query user $hosts{$host}{'notifyUser'}" ); + if ( $rc != 0 ) { + # User is either not logged on or we had a problem issuing the command. Not important, leave. + last; + } + $out = uc( $out ); + if ( $out =~ /^$hosts{$host}{'notifyUser'}/ ) { + my ($userStatus, $junk) = split '\s', $out, 2; + chomp( $userStatus ); + $userStatus =~ s/^\s+|\s+$//g; # trim both ends of the string + if ( $userStatus eq 'SSI' or $userStatus eq 'DSC' ) { + logResponse( 'DFS', 'MSG01', $hosts{$host}{'notifyUser'}, $host, $userStatus ); + last; + } + } + + # Don't worry if message still does not work. It is only a message. + ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', "vmcp message $hosts{$host}{'notifyUser'} $msg" ); + last; + } + + # Remove the temporary log file from the xCAT MN system. + $out = `rm -f $tempFile`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DFS', 'GNRL01', "rm -f $tempFile", $rc, $out ); + } + + $rc = 0; + return $rc; +} + + +#------------------------------------------------------- + + +=head3 pruneLogs + + Description : Compress and prune log files. The number of days to wait + before pruning is specified in the site table with the + zvmpruneivp property. If the property does not exist + or Management node information does not exist because of + some reason then the default is to prune logs that are + 7 days or older. + Arguments : Current year + Current month (numeric) + Current day (Julian day, numeric) + Returns : None. + Example : pruneLogs( $year, $mon + 1, $mday ); + +=cut + +#------------------------------------------------------- +sub pruneLogs{ + my ( $year, $month, $day ) = @_; + + my @lines; + my $pruneOffset = 0; + my $out; + my $pruneDate = ''; + my $rc; + my $removed = 0; + my $zipOut; + my $zipped = 0; + logResponse( 'DFS', '*NONFORMATTED*', "CRON job is pruning log files." ); + + # Determine the prune date value. + if ( ! exists $mnInfo{'PruneIVP'} or $mnInfo{'PruneIVP'} eq '' ) { + $pruneOffset = 7; + } else { + if ( looks_like_number( $mnInfo{'PruneIVP'} ) ) { + $pruneOffset = $mnInfo{'PruneIVP'}; + } else { + $pruneOffset = 7; + logResponse( 'DFS', 'TP01', 'zvmpruneivp', 'site', 'not numeric', $mnInfo{'PruneIVP'}, $pruneOffset ); + } + } + $pruneDate = strftime "%Y-%m-%d", 0, 0, 0, $day - $pruneOffset, $month-1, $year-1900; + logResponse( 'DFS', '*NONFORMATTED*', "Prune date: $pruneDate." ); + + # Zip any log files that are not for today. Current log files are similar to + # /var/log/xcat/ivp/IVP_XCAT_2016-09-19_01:01:03.log and will have .gz appended to the name + # after they have been zipped. + $out = `ls -1 /var/log/xcat/ivp/*.log`; + $rc = $?; + if ( $rc == 0 ) { + @lines = split( '\n', $out ); + foreach my $fqFile ( @lines ) { + chomp( $fqFile ); + my ($file) = $fqFile =~ /\/var\/log\/xcat\/ivp\/(.*)/; + my @parts = split( '_', $file ); + if ( ! defined $parts[0] or $parts[0] ne 'IVP' or + ! defined $parts[1] or ! defined $parts[2] or + $parts[2] eq $todayDate ) { + next; + } + #logResponse( 'DFS', 'GENERIC_RESPONSE', "ZIPPING: $file\n" ); + $zipOut = `gzip $fqFile 2>&1`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DF', 'GENERIC_RESPONSE', "Unable to gzip $fqFile, rc: $rc, out: $out" ); + } else { + $zipped++; + } + } + } + + # Prune any gzipped files that are too old. + $out = `ls -1 /var/log/xcat/ivp/*.log.gz`; + $rc = $?; + if ( $rc == 0 ) { + @lines = split( '\n', $out ); + foreach my $fqFile ( @lines ) { + chomp( $fqFile ); + my ($file) = $fqFile =~ /\/var\/log\/xcat\/ivp\/(.*)/; + my @parts = split( '_', $file ); + if ( ! defined $parts[0] or $parts[0] ne 'IVP' or + ! defined $parts[1] or ! defined $parts[2] or + $parts[2] ge $todayDate ) { + next; + } + if ( $parts[2] ge $pruneDate ) { + next; + } + + #logResponse( 'DFS', 'GENERIC_RESPONSE', "REMOVING: $file\n" ); + $zipOut = `rm $fqFile 2>&1`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DF', 'GENERIC_RESPONSE', "Unable to remove \'rm $fqFile\', rc: $rc, out: $out" ); + } else { + $removed++; + } + } + } + + logResponse( 'DFS', '*NONFORMATTED*', "IVP log pruning completed, zipped: $zipped, pruned: $removed." ); + return; +} + + +#------------------------------------------------------- + +=head3 removeIVP + + Description : Remove an automated IVP. + Arguments : ID of the IVP to be removed + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = removeIVP(); + +=cut + +#------------------------------------------------------- +sub removeIVP { + my ( $id ) = @_; + my $cmd; + my $out; + my $rc; + my $ivpId; + my %ids; + my $junk; + + # Get the list of IVP ids in the zvmivp table. + $cmd = '/opt/xcat/sbin/tabdump zvmivp | grep -v "^#"'; + $out = `$cmd`; + $rc = $?; + if ( $rc ne 0 ) { + logResponse( 'DF', 'GNRL04', $cmd, $rc, $out ); + goto FINISH_removeIVP; + } + my @lines = split( '\n', $out ); + foreach my $line ( @lines ) { + chomp( $line ); + my ($ivpId, $junk) = split( ',', $line, 2 ); + $ivpId =~ s/^\"|\"$//g; # trim quotes from both ends of the string + $ivpId =~ s/^\s+|\s+$//g; # trim spaces from both ends of the string + if ( $ivpId ne '' ) { + $ids{$ivpId} = 1; + } + } + + # Validate the specified id. + if ( $id eq '' or ! exists $ids{$id} ) { + logResponse( 'DF', 'ID03', $id ); + } + + # Update the table. + logResponse( 'DS', '*NONFORMATTED*', "Updating the z/VM IVP table (zvmivp) to remove $id" ); + my $chtabCmd = "/opt/xcat/sbin/chtab -d id=\'$id\' zvmivp"; + $out = `$chtabCmd`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DS', '*NONFORMATTED*', "\'$chtabCmd\' failed for ID($id), rc: $rc, out: $out\n" ); + $rc = 1; + } + +FINISH_removeIVP: + return $rc; +} + + +#------------------------------------------------------- + +=head3 runDriverScript + + Description : Run a downloaded driver script. + Arguments : This routine is driven from the action + table, verifySets. It takes global + input that can be set as command + input or by precursor routines. + The input variables include: + $driver - Driver script name + $driverLoc - Location of the driver script + $hosts - Infor for defined host nodes + $infoCnt - Count of warnings that were generated + $warningCnt - Count of warnings that were generated + $zxcatParms - Command line parms to + pass to zxcatIVP + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = runDriverScript(); + +=cut + +#------------------------------------------------------- +sub runDriverScript{ + my $infoCnt = 0; + my @lines; + my $out; + my $rc = 0; + my $warningCnt = 0; + + # Analyze the driver script to determine the z/VM host that it intends to support. + my $hostNodeZhcp = ''; + my $hostNode = `cat $driverLoc/$driver | grep "^export zxcatIVP_hostNode\=" | sed '/^export zxcatIVP_hostNode\=*/!d; s///; s/\"//g;q'`; + chomp( $hostNode ); + + if ( $hostNode ne '' ) { + if ( exists $hosts{$hostNode}{'hcp'} ) { + if ( exists $hosts{$hostNode}{'notify'} ) { + $hosts{$hostNode}{'notify'} = $hosts{$hostNode}{'notify'} . 'd'; + } else { + $hosts{$hostNode}{'notify'} = 'd'; + } + $zhcpTarget = $hosts{$hostNode}{'hcp'}; + $zvmHost = $hostNode; + push @ivpSummary, "The ZHCP related to the host, \'$hostNode\', identified in the driver script has been identified ". + "as \'$zhcpTarget\'."; + } else { + $rc = logResponse( 'DFS', 'DRIV03', $zvmHost ); + $notify = 1; + } + } else { + # Driver script did not specify the host node. + $rc = logResponse( 'DFS', 'DRIV02', "$driverLoc/$driver", 'zxcatIVP_hostNode' ); + $notify = 1; + } + + # Analyze the driver script to determine the ZHCP node that it intends to support. + my $zhcpNode = `cat $driverLoc/$driver | grep "^export zxcatIVP_zhcpNode\=" | sed '/^export zxcatIVP_zhcpNode\=*/!d; s///; s/\"//g;q'`; + chomp( $zhcpNode ); + my $zhcpHcp = `/opt/xcat/bin/lsdef $zhcpNode | grep "hcp\=" | sed '/hcp\=*/!d; s///; s/\"//g;q'`; + if ( $zhcpHcp ne '' ) { + $zhcpHcp =~ s/^\s+|\s+$//g; # trim both ends of the string + $zhcpTarget = $zhcpHcp; + foreach $hostNode ( keys %hosts ) { + if ( exists $hosts{$hostNode}{'hcp'} and $hosts{$hostNode}{'hcp'} eq $zhcpHcp ) { + if ( exists $hosts{$hostNode}{'notify'} ) { + $hosts{$hostNode}{'notify'} = $hosts{$hostNode}{'notify'} . 'd'; + } else { + $hosts{$hostNode}{'notify'} = 'd'; + } + } + } + } + + my $exportCmd = ''; + if ( $zxcatParms ne '' ) { + $ENV{zxcatIVP_moreCmdOps}=$zxcatParms; + } else { + delete $ENV{zxcatIVP_moreCmdOps}; + } + + logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' ); + logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "Using the driver script to drive the IVP. The output from the run follows." ); + logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' ); + $out = `chmod +x $driverLoc/$driver`; + $out = `$driverLoc/$driver`; + $rc = $?; + if ( $rc != 0 ) { + $rc = logResponse( 'DFS', 'DRIV01', "$driverLoc/$driver", $rc, $out ); + $notify = 1; + goto FINISH_runDriverScript; + } + + # Determine how many warnings and information messages were generated so that we can + # produce a summary message upon completion of the IVP. + @lines = split( '\n', $out ); + foreach my $line ( @lines ) { + if ( $line =~ /^Warning \(/ ) { $warningCnt++; } + if ( $line =~ /^Info \(/ ) { $infoCnt++; } + } + push @ivpSummary, "The driver script generated $warningCnt warnings and $infoCnt information messages."; + logResponse( 'DF', '*NONFORMATTED*', $out ); + +FINISH_runDriverScript: + if ( $warningCnt != 0 ) { + $notify = 1; + } + return $rc; +} + + +#------------------------------------------------------- + +=head3 runPrepScript + + Description : Push the appropriate level of preparation + script to a compute node and run it to + validate the system and build the driver + script. + Arguments : Global defaults set as command line parameters provide input + to this routine: + $driver - Name of driver script + $driverLoc - Location of the driver script + $infoCnt - Count of warnings that were generated + $openstackIP - IP for OpenStack compute node + $openstackUser - User for OpenStack compute node + $prepParms - Parms for preparation script + $warnErrCnt - Count of warnings and errors that were generated + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = runPrepScript(); + +=cut + +#------------------------------------------------------- +sub runPrepScript { + my $cmd = ''; + my $infoCnt = 0; + my $line; + my @lines; + my $out = ''; + my $rc = 0; + my $retRC = 0; + my $tmpDir = ''; + my $warningCnt = 0; + + # Determine the name of the driver script based on the IP address for the compute node. + $driver = "zxcatIVPDriver_$openstackIP.sh"; + + # Create the local IVP directory. + if ( !-d $driverLoc ) { + $out = `mkdir -m a=rwx,g=rx,o= -p $driverLoc`; + $rc = $?; + if ( $rc != 0 ) { + $rc = logResponse( 'DFS', 'PREP01', $driverLoc, $rc, $out ); + $notify = 1; + goto FINISH_runPrepScript; + } + } + + # Determine the OpenStack level. + my $level = getOpenStackLevel( $openstackIP, $openstackUser ); + if ( $level eq '' ) { + $notify = 1; + $rc = logResponse( 'DFS', 'PREP06', $openstackIP ); + goto FINISH_runPrepScript; + } + my $levelLetter = substr( $level, 0, 1); + push @ivpSummary, "OpenStack system at $openstackIP is running the Nova $level release."; + + # Determine the appropriate preparation script to send to the compute node. + my $prepDir = '/opt/xcat/share/xcat/tools/zvm'; + my $prepScript = "prep_zxcatIVP_$level.pl"; + logResponse( 'DF', 'GENERIC_RESPONSE', "Attempting to push $prepScript to the OpenStack system ". + "at $openstackIP. It will be used to validate the OpenStack environment and create ". + "a driver script to be used for the validation on the xCAT management node." ); + my $runPrepScript = 1; + + # Create a directory on the compute node to hold the preparation script and driver script. + $cmd = 'mktemp -d /tmp/xCAT.XXXXXXXXXX'; + ($rc, $tmpDir) = sshToNode( $openstackIP, $openstackUser, $cmd ); + if ( $rc != 0 ) { + # Unable to create the directory. Let's see if we have an old driver script that we can use. + $rc = logResponse( 'DFS', 'PREP02', $openstackIP, "$driverLoc/$driver", $cmd, $rc, $out ); + $notify = 1; + goto FINISH_runPrepScript; + } else { + # Push the preparation script to the compute node and run it. + chomp($tmpDir); + $cmd = "/usr/bin/scp $prepDir/$prepScript $openstackUser\@$openstackIP:$tmpDir"; + $out = `/usr/bin/scp "$prepDir/$prepScript" "$openstackUser\@$openstackIP:$tmpDir"`; + $rc = $?; + if ( $rc != 0 ) { + # Unable to push the preparation script. Let's see if we have an old driver script that we can use. + $rc = logResponse( 'DFS', 'PREP02', $openstackIP, "$driverLoc/$driver", $cmd, $rc, $out ); + $notify = 1; + goto FINISH_runPrepScript; + } + } + + if ( $runPrepScript ) { + # Run the preparation script. + ($rc, $out) = sshToNode( $openstackIP, $openstackUser, "chmod +x $tmpDir/$prepScript"); + ($rc, $out) = sshToNode( $openstackIP, $openstackUser, "$tmpDir/$prepScript '--driver' $tmpDir/$driver $prepParms" ); + logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' ); + logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "The output from the preparation script that is run on the compute node follows. ". + "The preparation script validates the z/VM related OpenStack configuration file properties." ); + logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' ); + logResponse( 'DF', '*NONFORMATTED*', $out ); + + # Determine how many warnings were generated so that we can produce a summary message upon completion of the IVP. + if ( $levelLetter gt 'L' ) { + @lines = split( '\n', $out ); + foreach $line ( @lines ) { + if ( $line =~ /^Warning \(/ ) { $warningCnt++; } + if ( $line =~ /^Info \(/ ) { $infoCnt++; } + } + } else { + @lines = split( '\n', $out ); + foreach $line ( @lines ) { + if ( $line =~ /^Warning:/ ) { $warningCnt++; } + if ( $line =~ /^Info:/ ) { $infoCnt++; } + } + } + push @ivpSummary, "The preparation script generated $warningCnt warnings and $infoCnt information messages."; + + # Pull back the driver script. + if ( -e "$driverLoc/$driver" ) { + $out = `mv -f $driverLoc/$driver $driverLoc/$driver.old`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'S', 'GENERIC_RESPONSE', "Unable to move $driverLoc/$driver to $driverLoc/$driver.old, rc: $rc" ); + $notify = 1; + } + } + + $cmd = "/usr/bin/scp $openstackUser\@$openstackIP:$tmpDir/$driver $driverLoc/$driver"; + $out = `/usr/bin/scp "$openstackUser\@$openstackIP:$tmpDir/$driver" "$driverLoc/$driver"`; + $rc = $?; + if ( $rc != 0 ) { + $rc = logResponse( 'DFS', 'PREP04', "$driverLoc/$driver", $openstackIP, $cmd, $rc, $out ); + $notify = 1; + goto FINISH_runPrepScript; + } + + $cmd = "chmod 660 $driverLoc/$driver 2>&1"; + $out = `$cmd`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'FS', 'PREP07', "$driverLoc/$driver", $cmd, $rc, $out ); + $notify = 1; + } + } + +FINISH_runPrepScript: + if ( !-s "$driverLoc/$driver" && -s "$driverLoc/$driver.old" ) { + # New driver does not exist but old driver exists, use the old one. + $out = `mv -f $driverLoc/$driver.old $driverLoc/$driver`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'S', 'GENERIC_RESPONSE', "Unable to move $driverLoc/$driver.old to $driverLoc/$driver, rc: $rc" ); + } + } + + if ( -s "$driverLoc/$driver" ) { + $retRC = 0; + # Add the driver script to the log file. + $out = `cat $driverLoc/$driver`; + logResponse( 'F', '*NONFORMATTED*', '*******************************************************************************' ); + logResponse( 'F', 'GENERIC_RESPONSE_NOINDENT', "The contents of the driver script used for the rest of this IVP follows. ". + "The driver script is used to run the rest of the IVP on the xCAT Management Node." ); + logResponse( 'F', 'GENERIC_RESPONSE_NOINDENT', 'Note: Any line which set a password related property has been removed.' ); + logResponse( 'F', '*NONFORMATTED*', '*******************************************************************************' ); + $out = `echo "$out" | grep -v "^export zxcatIVP_xcatUserPw"`; + logResponse( 'F', '*NONFORMATTED*', $out ); + } + + if ( $warningCnt != 0 ) { + $notify = 1; + } + + if ( $tmpDir ne '' ) { + $cmd = "rm -Rf $tmpDir 2>&1"; + ($rc, $out) = sshToNode( $openstackIP, $openstackUser, "$cmd"); + $rc = $?; + if ( $rc != 0 ) { + $rc = logResponse( 'DFS', 'CLNUP01', $openstackIP, $tmpDir, $cmd, $rc, $out ); + $notify = 1; + } + } + return $retRC; +} + + +#------------------------------------------------------- + +=head3 scheduleIVP + + Description : Schedule an automated IVP. + Arguments : Global defaults set as command line parameters provide input + to this routine: + $comments - Comments for IVP + $disable - Disable option + $id - ID to update or 'NEW' + $openstackIP - IP for OpenStack compute node + $openstackUser - User for OpenStack compute node + $orchParms - Parms for this script when IVP run + $prepParms - Parms for preparation script + $schedule - Hours to schedule + $scheduledType - Type of IVP + $zxcatParms - Parms for zxcatIVP script + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = scheduleIVP(); + +=cut + +#------------------------------------------------------- +sub scheduleIVP { + my $cmd; + my $out; + my $rc; + my $ivpId; + my %ids; + my $junk; + + # Get the list of IVP ids in the zvmivp table. + $cmd = '/opt/xcat/sbin/tabdump zvmivp | grep -v "^#"'; + $out = `$cmd`; + $rc = $?; + if ( $rc ne 0 ) { + logResponse( 'DF', 'GNRL04', $cmd, $rc, $out ); + goto FINISH_scheduleIVP; + } + my @lines = split( '\n', $out ); + foreach my $line ( @lines ) { + chomp( $line ); + my ($ivpId, $junk) = split( ',', $line, 2 ); + $ivpId =~ s/^\"|\"$//g; # trim quotes from both ends of the string + $ivpId =~ s/^\s+|\s+$//g; # trim spaces from both ends of the string + if ( $ivpId ne '' ) { + $ids{$ivpId} = 1; + } + } + + # Validate the specified id. Either generate a new ID if this is a new + # request (specified as 'new' or omitted or use the id that was passed. + if ( $id eq '' or $id eq 'NEW' ) { + # Generate the new Id + my $i; + for ( $i = 10; $i < 10010; $i++ ) { + if ( ! exists $ids{$i} ) { + last; + } + } + if ( $i <= 10010 ) { + $id = $i; + } else { + # Could not find an available number in the first 10000 IDs. + logResponse( 'DF', 'ID01' ); + goto FINISH_scheduleIVP; + } + } else { + # Validate the Id + if ( ! exists $ids{$id} ) { + logResponse( 'DF', 'ID02', $id ); + } + } + + if ( $scheduledType eq '' ) { + logResponse( 'DF', 'OPER01', '--type' ); + goto FINISH_scheduleIVP; + } + $scheduledType = lc( $scheduledType ); + if ( $scheduledType ne 'basicivp' and $scheduledType ne 'fullivp' ) { + logResponse( 'DF', 'OPER02', '--type', $scheduledType, '\'basicivp\' or \'fullivp\'' ); + goto FINISH_scheduleIVP; + } + if ( $scheduledType eq 'basicivp' ) { + # Ignore any FULLIVP parms + $openstackIP = ''; + $openstackUser = ''; + $prepParms = ''; + } + + # Normalize the schedule. + my %hours; + my @parts = split( ' ', $schedule ); + foreach my $hour ( @parts ) { + $hour =~ s/^\s+|\s+$//g; # trim spaces from both ends of the string + $hours{$hour} = 1; + } + $schedule = ''; + for ( my $hour = 0; $hour <= 23; $hour++ ) { + if ( exists $hours{$hour} ) { + $schedule = "$schedule $hour"; + delete $hours{$hour}; + } + } + $schedule =~ s/^\s+|\s+$//g; # trim spaces from both ends of the string + my (@leftOver) = keys %hours; + if ( scalar @leftOver != 0 ) { + my $badValues = join( '\' and \'', @leftOver ); + logResponse( 'DF', 'OPER02', '--schedule', $badValues, '0-23' ); + goto FINISH_scheduleIVP; + } + + if ( $comments =~ /,/ ) { + $comments =~ s/,//g; # trim commas from the string + } + + my $disableFlag = ''; + if ( $disable == 1 ) { + $disableFlag = 'YES'; + } + + # Update the table. + logResponse( 'DS', '*NONFORMATTED*', "Updating the z/VM IVP table (zvmivp) for $id" ); + my $chtabCmd = "/opt/xcat/sbin/chtab id=\'$id\' ". + "zvmivp.ip=\'$openstackIP\' ". + "zvmivp.schedule=\'$schedule\' ". + "zvmivp.last_run=\'\' ". + "zvmivp.type_of_run=\'$scheduledType\' ". + "zvmivp.access_user=\'" . hexEncode( $openstackUser ) . "\' ". + "zvmivp.orch_parms=\'" . hexEncode( $orchParms ) . "\' ". + "zvmivp.prep_parms=\'" . hexEncode( $prepParms ) . "\' ". + "zvmivp.main_ivp_parms=\'" . hexEncode( $zxcatParms ) . "\' ". + "zvmivp.comments=\'" . hexEncode( $comments ) . "\' ". + "zvmivp.disable=\'$disableFlag\'"; + $out = `$chtabCmd`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DS', '*NONFORMATTED*', "\'$chtabCmd\' failed for ID($id), rc: $rc, out: $out\n" ); + $rc = 1; + } + +FINISH_scheduleIVP: + return $rc; +} + +#------------------------------------------------------- + +=head3 setupLogFile + + Description : Set up the log file for this run. + Arguments : None + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = setupLogFile(); + +=cut + +#------------------------------------------------------- +sub setupLogFile { + my $out; + my $rc = 0; + my $ipString = ''; + + # Indicate that the log file will need to be finished. + # This is a safety in case something goes wrong during + # the IVP run and causes the program to break. + $needToFinishLogFile = 1; + + # Determine the IP address to associate with the log file. + if ( $openstackIP eq '' ) { + # Must be doing either a generic zxcatIVP or a full + # IVP for the compute node sharing the system with this + # xCAT MN. Use the string "XCAT". + $ipString = 'XCAT'; + } else { + if ( exists $localIPs{$openstackIP} ) { + $ipString = 'XCAT'; + } else { + $ipString = $openstackIP; + } + } + + # Determine the timestamp to use for the log. + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); + $startTime = sprintf("%02d:%02d:%02d on %04d-%02d-%02d", + $hour, $min, $sec, $year + 1900, $mon + 1, $mday ); + my $currTime = sprintf("%04d-%02d-%02d_%02d:%02d:%02d", + $year + 1900, $mon + 1, $mday, $hour, $min, $sec); + + # If the log directory does not exist then create it. + if ( !-d $logDir ) { + # Directory did not exist. Create it. + $out = `mkdir -p $logDir`; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DFS', 'GENERIC_RESPONSE', 'Failed to set up the log directory. IVP will run without a log file.' ); + $rc = 0; # Continue processing. + goto FINISH_setupLogFile; + } + } + + # Create the log file. + $logFile = "IVP\_$ipString\_$currTime\.log"; + open $logFileHandle, ">", "$logDir/$logFile"; + $rc = $?; + if ( $rc != 0 ) { + logResponse( 'DFS', 'GENERIC_RESPONSE', "Failed to open the log file: $logFile. IVP will run without a log file. $!" ); + $rc = 0; # Continue processing. + goto FINISH_setupLogFile; + } + $out = `chmod 644 "$logDir/$logFile"`; + + push @ivpSummary, "The following logfile was created for this run: $logFile"; + +FINISH_setupLogFile: + return $rc; +} + + +#------------------------------------------------------- + +=head3 showCILevel + + Description : Show the cloud-init version installed + in the node. + Arguments : None + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = showCILevel(); + +=cut + +#------------------------------------------------------- +sub showCILevel { + my $ciLevel = ''; + my $out = ''; + my $rc = 0; + + # Attempted to obtain the version using the routine + # accessible through the $PATH variable. + ($rc, $out) = sshToNode( $nodeName, '', 'cloud-init --version 2>&1'); + if ( $rc == 255 ) { + logResponse( 'DF', 'GENERIC_RESPONSE', $out ); + goto FINISH_showCILevel; + } elsif ( $rc == 0 ) { + if ( $out =~ /^cloud-init / ) { + ($ciLevel) = $out =~ /^cloud-init (.*)/; + my $msgText = "Version of cloud-init: $ciLevel"; + logResponse( 'DF', 'GENERIC_RESPONSE', $msgText ); + # Add code to compare the version to what is available in xcat. + goto FINISH_showCILevel; + } + } + + # Attempt to locate the version in the various cloud-init scripts + # in the target node. + # Add support to look for versions on the node if the invocation + # using the path did not show the version. + +FINISH_showCILevel: + return $rc; +} + + +#------------------------------------------------------- + +=head3 showHelp + + Description : Show the help inforamtion. + Arguments : None. + Returns : None. + Example : showHelp(); + +=cut + +#------------------------------------------------------- +sub showHelp{ + print "$0 verify the capabilities of a node.\n\n"; + print $usage_string; + return; +} + + +#------------------------------------------------------- + +=head3 sshToNode + + Description : SSH to a node and issue a command. + Check for SSH errors. + Arguments : Node name or IP address/DNS name + user if we need to specify SUDO + Command to issue + Options (char string): + q - Quiet, Don't generate an error message on failure + Returns : Return code: + 0 - Normal Linux success + 255 - Unable to SSH to system + non-zero - command error + Output from the command or a error string on an SSH failure. + Example : ($rc, $out) = sshToNode( $nodeName, $user, $command ); + +=cut + +#------------------------------------------------------- +sub sshToNode{ + my ( $nodeName, $user, $cmd, $options ) = @_; + my $rc = 0; + my $out = ''; + + if ( ! defined $options ) { + $options = ''; + } + + if ( $user eq '' ) { + $out = `ssh $nodeName -qoBatchMode=yes '$cmd'`; + $rc = $? >> 8; + } else { + $out = `ssh $user\@$nodeName -qoBatchMode=yes '$cmd'`; + $rc = $? >> 8; + } + + if ( $rc == 255 and $options !~ /q/ ) { + logResponse( 'DFS', 'VSTN01', $nodeName ); # Keep $rc = 255. + $out = "Unable to SSH to $nodeName"; + } + + return ($rc, $out); +} + + +#------------------------------------------------------- + +=head3 verifyAccess + + Description : Verify the xCAT MN can access a system. + Arguments : Node name or IP address + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = verifyAccess(); + +=cut + +#------------------------------------------------------- +sub verifyAccess{ + my ( $nodeOrIP ) = @_; + + my $rc = 0; + my $out = ''; + + ($rc, $out) = sshToNode( $nodeOrIP, '', 'pwd 2>/dev/null' ); + goto FINISH_verifyAccess if ( $rc == 255 ); # Already generated a message + if ( $rc != 0 ) { + $rc = logResponse( 'DFS', 'VA01' ); + } + +FINISH_verifyAccess: + return $rc; +} + + +#------------------------------------------------------- + +=head3 verifyBasicXCAT + + Description : Verify the basic setup of xCAT. + Arguments : None + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = verifyBasicXCAT(); + +=cut + +#------------------------------------------------------- +sub verifyBasicXCAT{ + my $infoCnt = 0; + my @lines; + my $rc = 0; + my $warningCnt = 0; + + $rc = logResponse( 'DF', 'GENERIC_RESPONSE', 'The IVP will be invoked with BYPASS messages suppressed. '. + 'This is because a basic IVP run will produce a number of BYPASS messages due to the fact that '. + 'it is not driven with a full set of configuration operands causing it to avoid some tests. '. + 'Instead you will see an information line indicating that the message was ignored.' ); + $ENV{'zxcatIVP_bypassMsg'} = 0; # No bypass messages + $ENV{'zxcatIVP_moreCmdOps'} = $zxcatParms; + my $out = `/opt/xcat/bin/zxcatIVP.pl`; + + $rc = logResponse( 'DF', '*NONFORMATTED*', $out ); + # Determine how many warnings were generated so that we can produce a summary message upon completion of the IVP. + @lines = split( '\n', $out ); + foreach my $line ( @lines ) { + if ( $line =~ /^Warning/ ) { $warningCnt++; } + if ( $line =~ /^Info/ ) { $infoCnt++; } + } + push @ivpSummary, "The zxcatIVP.pl script generated $warningCnt warnings and $infoCnt information messages."; + +FINISH_verifyBasicXCAT: + if ( $warningCnt != 0 ) { + $notify = 1; + } + return $rc; +} + + +#------------------------------------------------------- + +=head3 verifyDistro + + Description : Verify that the distro is supported. + Arguments : None + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = verifyDistro(); + +=cut + +#------------------------------------------------------- +sub verifyDistro{ + my $rc = 0; + + my $supported = xCAT::zvmUtils->isOSVerSupported( $tgtOS ); + if ( !$supported ) { + $rc = logResponse( 'DF', 'VD01', ($tgtOS) ); + } + + return $rc; +} + + +#------------------------------------------------------- + +=head3 verifyLogResponse + + Description : Script test function to test functioning + of the logResponse() routine. + Arguments : None + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = verifyLogResponse(); + +=cut + +#------------------------------------------------------- +sub verifyLogResponse{ + my $rc = 0; + my $sub2 = 'sub2'; + + $rc = logResponse( 'DF', 'VX01' ); + print "rc: $rc\n"; + logResponse( 'DF', 'VPF01', ($nodeName, 0, 'result message') ); + $rc = logResponse( 'DF', 'VX03', $nodeName, $sub2); + print "rc: $rc\n"; + $rc = logResponse( 'DF', 'VX03', $nodeName, 'sub2a'); + print "rc: $rc\n"; + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyPower + + Description : Verify the node is powered on. + Arguments : None + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = verifyPower(); + +=cut + +#------------------------------------------------------- +sub verifyPower { + my ( $nodeName ) = @_; + my $rc = 0; + my $powerState; + + my $out = `/opt/xcat/bin/rpower $nodeName stat 2>&1`; + $rc = $?; + if ( $rc != 0 ) { + $rc = logResponse( 'DF', 'VPF01', ($nodeName, $rc, $out) ); + goto FINISH_verifyPower if ( $rc > 0 ); + } + + $out = lc( $out ); + if ( $out =~ /$nodeName: / ) { + chomp $out; + ($powerState) = $out =~ /$nodeName: (.*)/; + } + + if ( $powerState ne 'on' ) { + $rc = logResponse( 'DFS', 'VP02', ($nodeName) ); + } + +FINISH_verifyPower: + return $rc; +} + + +#------------------------------------------------------- + +=head3 verifyService + + Description : Verify that specified services are running. + Arguments : Node name or IP address + Blank delimitted list of service names + service name begins with the name and + has a comma separated list of run levels + which are to be verified as 'on' + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = verifyService(); + +=cut + +#------------------------------------------------------- +sub verifyService { + my ( $nodeOrIP, $namesAndLevels ) = @_; + my @serviceList = split ( / /, $namesAndLevels ); + + my $rc = 0; + my $serviceOut = ''; + + # Get the list of service names and run levels into an array. + + # Get the list of configured services. The output looks similar to: + # service_name 0:off 1:off 2:off 3:off 4:off 5:off 6:off + ($rc, $serviceOut) = sshToNode( $nodeOrIP, '', "chkconfig --list 2>&1" ); + goto FINISH_verifyService if ( $rc == 255 ); + + # Look for missing services + my @missingService; + my @foundService; + my @nonrunningService; + foreach my $serviceInfo ( @serviceList ) { + my @offLevels; + my $levels; + my @serviceRunLevels = split( /,/, $serviceInfo ); + my $service = shift @serviceRunLevels; + ($levels) = $serviceOut =~ /^$service(.*)\s(.*)\n/m; + $levels =~ s/^\s+|\s+$//g if ( defined $levels ); + if (( defined $levels ) and ( $levels ne '' )) { + # Verify the run levels are enabled. + foreach my $level ( @serviceRunLevels ) { + if ( $levels !~ /$level:on/ ) { + push @offLevels, $level; + } + } + if ( @offLevels ) { + $levels = join(", ", @offLevels); + $rc = logResponse( 'DF', 'VS06', $service, $levels ); + goto FINISH_verifyService if ( $rc > 0 ); + } else { + push @foundService, $service; + } + } else { + push @nonrunningService, $service; + } + } + + if ( @foundService ) { + my $list = join(", ", @foundService); + $rc = logResponse( 'DF', 'GENERIC_RESPONSE', "The following services are configured to start: $list" ); + goto FINISH_verifyService if ( $rc > 0 ); + } + if ( @nonrunningService ) { + my $list = join(", ", @nonrunningService); + $rc = logResponse( 'DF', 'VS05', $list ); + goto FINISH_verifyService if ( $rc > 0 ); + } + +FINISH_verifyService: + return $rc; +} + + +#------------------------------------------------------- + +=head3 verifyXcatconf4z + + Description : Verify xcatconf4z is properly installed + and is the correct version. + Arguments : Node name or IP address + Returns : 0 - No error + non-zero - Terminating error detected. + Example : $rc = verifyXcatconf4z(); + +=cut + +#------------------------------------------------------- +sub verifyXcatconf4z{ + my ( $nodeOrIP ) = @_; + my $rc = 0; + my $out; + my ($mnVersion, $tgtVersion); + + # Verify service is installed + $rc = verifyService( $nodeOrIP, 'xcatconf4z,2,3,5' ); + goto FINISH_verifyXcatconf4z if ( $rc == 255 ); + + # Get the xCAT MN's xcatconf4z version level. + $out = `/opt/xcat/share/xcat/scripts/xcatconf4z version`; + if ( $out =~ /xcatconf4z version: / ) { + chomp $out; + ($mnVersion) = $out =~ /xcatconf4z version: (.*)/; + } else { + $rc = logResponse( 'DFS', 'VX01' ); + goto FINISH_verifyXcatconf4z if ( $rc > 0 ); + } + + # Verify that the node contains xcatconf4z in the correct location and is executable. + #$out = `ssh $nodeOrIP 'ls -al /opt/xcatconf4z 2>&1'`; + ($rc, $out) = sshToNode( $nodeOrIP, '', 'ls -al /opt/xcatconf4z 2>&1'); + goto FINISH_verifyXcatconf4z if ( $rc == 255 ); + if ( $out =~ /No such file or directory/ ) { + $rc = logResponse( 'DF', 'VX06' ); + goto FINISH_verifyXcatconf4z if ( $rc > 0 ); + } else { + # Verify that it is executable + } + + # Get the node's xcatconf4z version level. + #$out = `ssh $nodeOrIP '/opt/xcatconf4z version'`; + ($rc, $out) = sshToNode( $nodeOrIP, '', '/opt/xcatconf4z version'); + goto FINISH_verifyXcatconf4z if ( $rc == 255 ); + if ( $out =~ /xcatconf4z version: / ) { + chomp $out; + ($tgtVersion) = $out =~ /xcatconf4z version: (.*)/; + } else { + $rc = logResponse( 'DF', 'VX02' ); + goto FINISH_verifyXcatconf4z if ( $rc > 0 ); + } + + # Verify the version is up to date. + if ( defined $tgtVersion ) { + if ( $mnVersion > $tgtVersion ) { + $rc = logResponse( 'DF', 'VX03', ($tgtVersion, $mnVersion) ); + goto FINISH_verifyXcatconf4z if ( $rc > 0 ); + } + } + + # Verify that authorized senders is setup. + #$out = `ssh $nodeOrIP '/opt/xcatconf4z status'`; + ($rc, $out) = sshToNode( $nodeOrIP, '', '/opt/xcatconf4z status'); + goto verifyXcatconf4z if ( $rc == 255 ); + if ( $out =~ /xcatconf4z is disabled / ) { + $rc = logResponse( 'DF', 'VX04' ); + goto FINISH_verifyXcatconf4z if ( $rc > 0 ); + } else { + # Get list of authorized users and put out an info message. + } + + # Verify that mkisofs is available + ($rc, $out) = sshToNode( $nodeOrIP, '', 'stat /opt/bin/mkisofs'); + goto verifyXcatconf4z if ( $rc == 255 ); + if ( $rc != 0 ) { + $rc = logResponse( 'DF', 'VX07' ); + goto FINISH_verifyXcatconf4z if ( $rc > 0 ); + } + +FINISH_verifyXcatconf4z: + return $rc; +} + + +#***************************************************************************** +# Main routine +#***************************************************************************** +my $ignoreOpt; +my $rc = 0; +my $thisScript = $0; +my $out; + +# Parse the arguments +$Getopt::Long::ignorecase = 0; +Getopt::Long::Configure( "bundling" ); +if (!GetOptions( + 'a|access' => \$verifyAccess, + 'basicivp' => \$runBasicIVP, + 'capturereqs' => \$verifyCaptureReqs, + 'c|cloudinit' => \$verifyCloudInit, + 'comments=s' => \$comments, + 'cron' => \$runCron, + 'decode=s' => \$decode, + 'disable' => \$disable, + 'enable' => \$enable, + 'encode=s' => \$encode, + 'file=s' => \$dataFile, + 'fullivp' => \$runFullIVP, + 'h|help' => \$displayHelp, + 'i|id=s' => \$id, + 'ignore=s' => \$ignoreOpt, + 'cmdoveriucv=s' => \$issueCmdOverIUCV, + 'cmdtonode=s' => \$issueCmdToNode, + 'n|node=s' => \$nodeName, + 'notify' => \$notifyOnErrorOrWarning, + 'openstackuser=s' => \$openstackUser, + 'openstackip=s' => \$openstackIP, + 'orchparms=s' => \$orchParms, + 'prepparms=s' => \$prepParms, + 'remove' => \$remove, + 'schedule=s' => \$schedule, + 'type=s' => \$scheduledType, + 'v|version' => \$versionOpt, + 'x|xcatconf4z' => \$verifyXcatconf4z, + 'zxcatparms=s' => \$zxcatParms, + )) { + print $usage_string; +} + +if ( $versionOpt ) { + logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "Version: $version\n" ); +} + +if ( $displayHelp ) { + showHelp(); +} + +if ( $displayHelp or $versionOpt ) { + goto FINISH_main; +} + +# Convert any encoded operand values back to their unencoded value. +my @convertibleParms = ( 'comments', 'nodeName', 'openstackUser', 'orchParms', 'prepParms', 'zxcatParms' ); +foreach my $parmName ( @convertibleParms ) { + eval( "\$$parmName = hexDecode( \$$parmName )" ); +} + +if ( $schedule eq '' and $orchParms ne '' ) { + # If not scheduling an IVP run and orchestrator parms are present then use them. + my $unrecognizedOps = ''; + $rc = GetOptionsFromString( + $orchParms, + 'ignore=s' => \$ignoreOpt, + ); + if ( $rc == 0 ) { + print "Unrecognized option in --orchParms. ". + "Only --ignore is allowed as an orchestrator option for an immediate run.\n"; + $rc = 2; + goto FINISH_main; + } +} + +# Handle messages to ignore. +if ( defined( $ignoreOpt ) ) { + # Make hash from the specified ignore operands + $ignoreOpt = uc( $ignoreOpt ); + my @ingoreList; + if ( $ignoreOpt =~ ',' ) { + @ingoreList = split( ',', $ignoreOpt ); + } else { + @ingoreList = split( ' ', $ignoreOpt ); + } + + %msgsToIgnore = map { $_ => 1 } @ingoreList; + + # Convert general severity type operands to their numeric value. + if ( $msgsToIgnore{'BYPASS'} ) { + delete $msgsToIgnore{'BYPASS'}; + $msgsToIgnore{'2'} = 1; + } + if ( $msgsToIgnore{'INFO'} ) { + delete $msgsToIgnore{'INFO'}; + $msgsToIgnore{'3'} = 1; + } + if ( $msgsToIgnore{'WARNING'} ) { + delete $msgsToIgnore{'WARNING'}; + $msgsToIgnore{'4'} = 1; + } + if ( $msgsToIgnore{'ERROR'} ) { + delete $msgsToIgnore{'ERROR'}; + $msgsToIgnore{'5'} = 1; + } +} + +if ( $openstackIP ne '' ) { + $openstackIP = uc( $openstackIP ); +} + +# Handle the combinations of disable and enable options. +if ( $disable eq '' ) { + $disable = 0; +} +if ( $enable eq '' ) { + $enable = 0; +} +if ( $disable == 1 and $enable == 1 ) { + $rc = logResponse( 'DFS', 'OPER03', '--disable and --enable' ); + goto FINISH_main; +} + +if ( $runFullIVP or $runBasicIVP ) { + # Set up a log file for an IVP run. + setupLogFile(); +} + +# Determine the information about the xCAT managed node and the z/VM +# host environment where it is running (if running on z/VM). +getMNInfo(); + +if ( $decode ne '' or + $disable or + $enable or + $encode ne '' or + $runFullIVP or + $runCron or + $runBasicIVP or + $remove or + $schedule ne '' ) { + # IVP runs do not need the node. +} elsif ( $nodeName eq '' ) { + $rc = logResponse( 'DFS', 'OPER01', '-n or --node' ); + goto FINISH_main; +} + +($::SUDOER, $::SUDO) = xCAT::zvmUtils->getSudoer(); + +# Setup for a test run of logResponse. Normally, commented out. +#($verifyAccess, $verifyCaptureReqs, $verifyCloudInit, $verifyXcatconf4z) = 0; +#my $test = 1; + +# Run the selected tests +foreach my $verify (keys %verifySets) { + if ( eval $verify ) { + if ( $verifySets{$verify}[0] ne '' ) { + logResponse( 'D', 'GENERIC_RESPONSE_NOINDENT', "\n********************************************************************\n" ); + logResponse( 'D', 'GENERIC_RESPONSE_NOINDENT', "$verifySets{$verify}[0]\n" ); + logResponse( 'D', 'GENERIC_RESPONSE_NOINDENT', "********************************************************************\n" ); + } + my $size = @{$verifySets{$verify}}; + logResponse( 'D', '*RESET*' ); + for (my $i = 1; $i < $size; $i++) { + ($rc) = eval $verifySets{$verify}[$i]; + if ( ! defined $rc ) { + logResponse( 'DFS', 'PERL01', $thisScript, $verifySets{$verify}[$i], $@ ); + $rc = 666; + last; + } + + if ( $rc > 0 ) { + last; + } + } + + if ( $warnErrCnt == 0 ) { + logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "\nProcessing completed." ); + } else { + logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "\nProcessing completed with warning or error messages. " . + "See previous messages for information.\n" ); + } + } +} + +FINISH_main: +if ( $needToFinishLogFile ) { + # A log file was started. We need to complete it by adding the summary + # section. If necessary, we will send the log file to the notify user. + finishLogFile(); +} + +exit $rc; \ No newline at end of file diff --git a/xCAT-client/bin/xcoll b/xCAT-client/bin/xcoll index 03a14a0ef..ffe8005aa 100755 --- a/xCAT-client/bin/xcoll +++ b/xCAT-client/bin/xcoll @@ -8,6 +8,7 @@ use xCAT::Client; use Getopt::Long; use strict; my %output; +my %outputhdrs; my $option; my $printcount; @@ -45,7 +46,7 @@ sub fillerup { } } if ($individual) { - foreach my $node (keys %output) { + foreach my $node (sort { $a <=> $b or $a cmp $b } keys %output) { print "====================================\n"; print "$node\n"; print "====================================\n"; @@ -63,6 +64,11 @@ foreach my $output (keys %collated) { unless ($option) { xCAT::Client::submit_request($cmdref, \&fillerup); } + $outputhdrs{$nodes} = $output; +} +foreach my $hdr (sort { $a <=> $b or $a cmp $b } keys %outputhdrs) { + $nodes = $hdr; + my $output = $outputhdrs{$hdr}; print "====================================\n"; print "$nodes\n"; print "====================================\n"; diff --git a/xCAT-client/bin/zvmMsg b/xCAT-client/bin/zvmMsg new file mode 100644 index 000000000..d7b451c26 --- /dev/null +++ b/xCAT-client/bin/zvmMsg @@ -0,0 +1,113 @@ +#!/usr/bin/perl +# IBM(c) 2016 EPL license http://www.eclipse.org/legal/epl-v10.html +#------------------------------------------------------- + +=head1 + + Provides more information related to an xCAT message + for z/VM. These are messages which are similar to the + following: + Warning (ZXCATIVP:VN01) Network VSW3 was not found as a network. + These message were originally added for the z/VM IVP and + are in the form: + (group:msgId) + + The information provided consists of: + Explanation of the message, + System Action, and + User Action. + +=cut + +#------------------------------------------------------- +package xCAT::zvmMsgs; +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} + +$XML::Simple::PREFERRED_PARSER='XML::Parser'; + +use Getopt::Long; +use lib "$::XCATROOT/lib/perl"; +use Text::Wrap; +use xCAT::zvmMsgs; +use strict; +use warnings; +1; + +# set the usage message +my $usage_string = "Usage:\n + $0 -h + $0 --help + $0 --group --id \n + Use this script to display extra information for messages related + to z/VM that have the format: + (:) + for example: + Warning (ZXCATIVP:VN01) Network VSW3 was not found.\n + The following options are supported: + --group + specified the identifier of the group to which the message belongs. + The group id is the first part of the identifer, e.g. + 'Warning (ZXCATIVP:VDS01)' belongs to the 'ZXCATIVP' group. + The group id is case sensitive. This operand should be specified + along with the --id operand. + -h | --help + Displays usage information. + --id + specifies the message identifier. The message id is the second part + of the identifier, e.g. 'Warning (ZXCATIVP:VDS01)' where 'VDS01' + is the message id. The message identifier is case sensitive. This + operand should be specified along with the --group operand to fully + identify the message.\n"; + +#***************************************************************************** +# Main routine +#***************************************************************************** +# Parse the arguments +my $displayHelp = 0; +my $group = ''; +my $msgId = ''; +$Getopt::Long::ignorecase = 0; +Getopt::Long::Configure( 'bundling' ); + +if ( !GetOptions( + 'h|help' => \$displayHelp, + 'group=s' => \$group, + 'id=s' => \$msgId, + )) { + print $usage_string; + goto FINISH; +} + +if ( $displayHelp ) { + print $usage_string; + goto FINISH; +} + +if ( $group eq '' ) { + print "--group operand was not specified.\n"; + print $usage_string; +} elsif ( $msgId eq '' ) { + print "--id operand was not specified.\n"; + print $usage_string; +} else { + my $extraInfo; + my $msg; + my $recAction; + my $sev; + ( $recAction, $sev, $msg, $extraInfo ) = xCAT::zvmMsgs->buildMsg( $group, $msgId ); + if ( $msg =~ ': Message was not found!' ) { + # Oops, we could not find the message. + print "$msg\n"; + } else { + if ( $extraInfo ne '' ) { + print "Additional information for message $msgId in group $group:\n"; + print "$extraInfo\n"; + } + } +} + +FINISH: +exit; \ No newline at end of file diff --git a/xCAT-client/bin/zxcatCopyCloneList.pl b/xCAT-client/bin/zxcatCopyCloneList.pl new file mode 100644 index 000000000..defab5cbc --- /dev/null +++ b/xCAT-client/bin/zxcatCopyCloneList.pl @@ -0,0 +1,353 @@ +#!/usr/bin/perl +############################################################################### +# IBM (C) Copyright 2015, 2016 Eclipse Public License +# http://www.eclipse.org/org/documents/epl-v10.html +############################################################################### +# COMPONENT: zxcatCopyCloneList.pl +# +# This is a program to copy the "DOCLONE COPY" file from the 193 disk to +# /opt/xcat/doclone.txt +############################################################################### + +use strict; +#use warnings; +use Capture::Tiny ':all'; +use Getopt::Long; + +my $file_location = '/var/opt/xcat/'; +my $source_file = 'DOCLONE.COPY'; +my $file_name = 'doclone.txt'; +my $tempPattern = 'doclone.XXXXXXXX'; +my $source_vdev = '193'; +my $version = "1.0"; +my $out; +my $err; +my $returnvalue; +my $displayHelp = 0; # Display help information +my $versionOpt = 0; # Show version information flag + +my $usage_string = "This script copies the DOCLONE COPY from the MAINT 193 +to the $file_location$file_name\n\n + Usage:\n + $0 [ -v ] + $0 [ -h | --help ]\n + The following options are supported:\n + -h | --help Display help information\n + -v Display the version of this script.\n"; + +# Copied this routine from sspmodload.pl +# This will get the Linux address of the vdev +sub get_disk($) +{ + my ($id_user) = @_; + my $id = hex $id_user; + my $hex_id = sprintf '%x', $id; + my $completed = 1; + my $dev_path = sprintf '/sys/bus/ccw/drivers/dasd-eckd/0.0.%04x', $id; + if (!-d $dev_path) { + $dev_path = sprintf '/sys/bus/ccw/drivers/dasd-fba/0.0.%04x', $id; + } + if (!-d $dev_path) { + print "(Error) Unable to find a path to the $source_vdev in /sys/bus/ccw/drivers/\n"; + } + -d $dev_path or return undef; + + #offline the disk so that a new online will pick up the current file + my @sleepTimes = ( 1, 2, 3, 5, 8, 15, 22, 34, 60); + system("echo 0 > $dev_path/online"); + + my $dev_block = "$dev_path/block"; + + #wait if the disk directory is still there + if (-d $dev_block) { + $completed = 0; + foreach (@sleepTimes) { + system("echo 0 > $dev_path/online"); + sleep $_; + if (!-d $dev_block) { + $completed = 1; + last; + } + } + } + + if (!$completed) { + print "(Error) The 193 disk failed to complete the offline!\n"; + return undef; + } + + system("echo 1 > $dev_path/online"); + # Bring the device online if offline + if (!-d $dev_block) { + $completed = 0; + foreach (@sleepTimes) { + system("echo 1 > $dev_path/online"); + sleep $_; + if (-d $dev_block) { + $completed = 1; + last; + } + } + if (!$completed) { + print "(Error) The 193 disk failed to come online!\n"; + return undef; + } + } + if (opendir(my $dir, $dev_block)) { + my $dev; + while ($dev = readdir $dir) { + last if (!( $dev eq '.' || $dev eq '..' ) ); + } + closedir $dir; + if (!defined $dev) { + print "(Error) undefined $dev\n"; + } + defined $dev ? "/dev/$dev" : undef; + } else { + print "(Error) Unable to opendir $dev_block\n"; + return undef; + } +} + +# *********************************************************** +# Mainline. Parse any arguments, usually no arguments +$Getopt::Long::ignorecase = 0; +Getopt::Long::Configure( "bundling" ); + +GetOptions( + 'h|help' => \$displayHelp, + 'v' => \$versionOpt ); + +if ( $versionOpt ) { + print "Version: $version\n"; + exit 0; +} + +if ( $displayHelp ) { + print $usage_string; + exit 0; +} + +my $tempFileName = ''; +my $rc = 0; +my $oldFileExists = 0; +my $dev = get_disk($source_vdev); +if (defined($dev)) { + # make sure directory exists + if (!-d $file_location) { + $returnvalue = mkdir "$file_location", 0755; + if (!$returnvalue) { + print "(Error) mkdir $file_location failed with errno:$!"; + $rc = 1; + goto MAIN_EXIT; + + } + } + my $oldFiletime; + # Create a temp file name to use while validating + $tempFileName = `/bin/mktemp -p $file_location $tempPattern`; + chomp($tempFileName); + # if we are overwriting an existing file, save time stamp + if (-e "$file_location$file_name") { + # stat will return results in $returnvalue + ( $out, $err, $returnvalue ) = eval { capture { `stat \'-c%y\' $file_location$file_name` } }; + chomp($out); + chomp($err); + chomp($returnvalue); + if (length($err) > 0) { + print "(Error) Cannot stat the $file_location$file_name\n$err\n"; + $rc = 1; + goto MAIN_EXIT; + } + $oldFileExists = 1; + $oldFiletime = $returnvalue; + } + + ( $out, $err, $returnvalue ) = eval { capture { `/sbin/cmsfscp -d $dev -a $source_file $tempFileName` } }; + chomp($out); + chomp($err); + chomp($returnvalue); + if (length($err) > 0) { + # skip any blksize message for other blksize + if ($err =~ 'does not match device blksize') { + } else { + print "(Error) Cannot copy $source_file\n$err\n"; + $rc = 1; + goto MAIN_EXIT; + } + } + + if ($oldFileExists == 1) { + ( $out, $err, $returnvalue ) = eval { capture { `stat \'-c%y\' $tempFileName` } }; + chomp($out); + chomp($err); + chomp($returnvalue); + if (length($err) > 0) { + print "(Error) Cannot stat the $tempFileName\n$err\n"; + $rc = 1; + goto MAIN_EXIT; + } + if ($oldFiletime eq $returnvalue) { + print "The $source_file copied to temporary file $tempFileName is the same time stamp as original.\n"; + } else { + print "$source_file copied to temporary file $tempFileName successfully\n"; + } + } else { + print "$source_file copied to temporary file $tempFileName successfully\n"; + } + + print "Validating $tempFileName contents for proper syntax...\n"; + if (-f "$tempFileName") { + $out = `cat $tempFileName`; + } else { + print "(Error) Missing temporary file: $tempFileName\n"; + $rc = 1; + goto MAIN_EXIT; + } + my @lines = split('\n',$out); + my %hash = (); + my %imagenames = (); + my $count = @lines; + if ($count < 1) { + print "(Error) $tempFileName does not have any data.\n"; + ( $out, $err, $returnvalue ) = eval { capture { `rm $tempFileName` } }; + chomp($out); + chomp($err); + chomp($returnvalue); + if (length($err) > 0) { + print "(Error) Cannot erase temporary file $tempFileName $err\n"; + } + $rc = 1; + goto MAIN_EXIT; + } + + # loop for any lines found + for (my $i=0; $i < $count; $i++) { + # skip comment lines, * or /* + if ( $lines[$i] =~ '^\s*[\*]') { + next; + } + if ( $lines[$i] =~ '^\s*/[*]') { + next; + } + # is this a blank line? if so skip it + if ($lines[$i] =~/^\s*$/) { + next; + } + my $semicolons = $lines[$i] =~ tr/\;//; + if ($semicolons < 3) { + print "(Error) Semicolons need to end each key=value on line ".($i+1)."\n"; + $rc = 1; + } + + %hash = ('IMAGE_NAME' => 0,'CLONE_FROM' => 0,'ECKD_POOL' => 0, 'FBA_POOL' => 0 ); + # IMAGE_NAME=imgBoth; CLONE_FROM=testFBA; ECKD_POOL=POOLECKD; FBA_POOL=POOLFBA + 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++) { + # if this token is all blanks skip it. Could be reading blanks at the end of the line + if ($parms[$j] =~ /^\s*$/) { + next; + } + my $parmlength = length($parms[$j]); + my @keyvalue = split('=', $parms[$j]); + my $key = $keyvalue[0]; + $key =~ s/^\s+|\s+$//g; # get rid of leading and trailing blanks + + if ( length( $key ) == 0 ) { + print "(Error) Missing keyword on line ".($i+1)."\n"; + $rc = 1; + next; + } + my $value = $keyvalue[1]; + $value =~ s/^\s+|\s+$//g; + if ( length( $value ) == 0 ) { + print "(Error) Missing value for key $key on line ".($i+1)."\n"; + $rc = 1; + next + } + #uppercase both key and value; + my $UCkey = uc $key; + my $UCvalue = uc $value; + $hash{$UCkey} = $hash{$UCkey} + 1; + if ($UCkey eq "IMAGE_NAME") { + if (exists $imagenames{$UCvalue}) { + print "(Error) Duplicate IMAGE_NAME found on line ".($i+1)." with value: $value\n"; + $rc = 1; + } else { + $imagenames{$UCvalue} = 1; + } + } + if ($UCkey ne "IMAGE_NAME" && $UCkey ne "CLONE_FROM" && $UCkey ne "ECKD_POOL" && $UCkey ne "FBA_POOL") { + print "(Error) Unknown keyword $key found on line ".($i+1)."\n"; + $rc = 1; + } + } + # Check to make sure they have at least an image name, from and one pool + if ($hash{IMAGE_NAME} == 1 && $hash{CLONE_FROM} == 1 && ($hash{ECKD_POOL} ==1 || $hash{FBA_POOL} ==1 )) { + next; + } else { + if ($hash{IMAGE_NAME} == 0) { + print "(Error) Missing IMAGE_NAME key=value on line ".($i+1)."\n"; + $rc = 1; + } + if ($hash{IMAGE_NAME} > 1) { + print "(Error) Multiple IMAGE_NAME keys found on line ".($i+1)."\n"; + $rc = 1; + } + if ($hash{CLONE_FROM} == 0) { + print "(Error) Missing CLONE_FROM key=value on line ".($i+1)."\n"; + $rc = 1; + } + if ($hash{CLONE_FROM} > 1) { + print "(Error) Multiple CLONE_FROM keys found on line ".($i+1)."\n"; + $rc = 1; + } + if ($hash{ECKD_POOL} == 0 && $hash{FBA_POOL} == 0) { + print "(Error) Missing ECKD_POOL or FBA_POOL on line ".($i+1)."\n"; + $rc = 1; + } + if ($hash{ECKD_POOL} > 1) { + print "(Error) Multiple ECKD_POOL keys found on line ".($i+1)."\n"; + $rc = 1; + } + if ($hash{FBA_POOL} > 1) { + print "(Error) Multiple FBA_POOL keys found on line ".($i+1)."\n"; + $rc = 1; + } + } + } +} else { + print "(Error) Unable to access the $source_vdev disk.\n"; + $rc = 1; +} +# Main exit for this routine. Handles any necessary clean up. +MAIN_EXIT: +if (length($tempFileName) > 0 ) { + # If a good rc, Copy the temp file to the correct file + if ($rc == 0) { + ( $out, $err, $returnvalue ) = eval { capture { `/bin/cp -f $tempFileName $file_location$file_name` } }; + print $out; + print $err; + print $returnvalue; + chomp($out); + chomp($err); + chomp($returnvalue); + if (length($err) > 0) { + print "(Error) Cannot copy the temporary file $tempFileName to $file_location$file_name \n $err\n"; + $rc = 1; + } else { + print "Validation completed. Temporary file copied to $file_location$file_name.\nIt is ready to use\n"; + } + } + ( $out, $err, $returnvalue ) = eval { capture { `rm $tempFileName` } }; + chomp($out); + chomp($err); + chomp($returnvalue); + if (length($err) > 0) { + print "(Error) Cannot erase temporary file $tempFileName\n$err\n"; + $rc = 1; + } +} +exit $rc; diff --git a/xCAT-client/bin/zxcatIVP.pl b/xCAT-client/bin/zxcatIVP.pl new file mode 100644 index 000000000..5e1a79604 --- /dev/null +++ b/xCAT-client/bin/zxcatIVP.pl @@ -0,0 +1,2607 @@ +#!/usr/bin/perl +############################################################################### +# IBM (C) Copyright 2014, 2016 Eclipse Public License +# http://www.eclipse.org/org/documents/epl-v10.html +############################################################################### +# COMPONENT: zxcatIVP.pl +# +# This is an Installation Verification Program for z/VM's xCAT Management Node +# and zHCP agent. +############################################################################### +package xCAT::verifynode; +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} + +$XML::Simple::PREFERRED_PARSER='XML::Parser'; + +use strict; +#use warnings; +use Getopt::Long; +use Getopt::Long qw(GetOptionsFromString); +use MIME::Base64; +use Sys::Syslog qw( :DEFAULT setlogsock); +use Text::Wrap; +use LWP; +use JSON; +use lib "$::XCATROOT/lib/perl"; +use xCAT::zvmMsgs; +require HTTP::Request; + +# Global variables set based on input from the driver program. +my $glob_bypassMsg = 1; # Display bypass messages +my $glob_CMA = 0; # CMA appliance indicator, Assume not running in CMA +my $glob_CMARole = ''; # CMA role, CONTROLLER, COMPUTE or '' (unknown) +my $glob_cNAddress; # IP address or hostname of the compute node that + # is accessing this xCAT MN. (optional) +my $glob_defaultUserProfile; # Default profile used in creation of server instances. +my $glob_displayHelp = 0; # Display help instead of running the IVP +my @glob_diskpools; # Array of disk pools, e.g. ('POOLSCSI', 'POOL1'), + # that are expected to exist. (optional) +my $glob_expectedReposSpace; # Minimum amount of repository space. +my $glob_expUser; # User name used for importing and exporting images +my @glob_instFCPList; # Array of FCPs used by server instances +my $glob_hostNode; # Node of host being managed. If blank, + # IVP will search for the host node. (optional) +my $glob_macPrefix; # User prefix for MAC Addresses of Linux level 2 interfaces +my %glob_msgsToIgnore; # Hash of messages to be ignored +my $glob_mgtNetmask; +my $glob_mnNode; # Node name for xCAT MN (optional). +my $glob_moreCmdOps; # Additional command operands passed with an environment variable +my @glob_networks; # Array of networks and possible VLAN ranges + # eg. ( 'xcatvsw1', 'xcatvsw2:1:4999'). (optional) +my $obfuscatePw; # Obfuscate the PW in the driver file that is built +my $glob_signalTimeout; # Signal Shutdown mininum acceptable timeout +my $glob_syslogErrors; # Log errors in SYSLOG: 0 - no, 1 - yes +my %glob_vswitchOSAs; # Hash list of vswitches and their OSAs +my @glob_xcatDiskSpace; # Array information of directories in xCAT MN that should be validated for disk space +my $glob_xcatMNIp; # Expected IP address of this xCAT MN +my $glob_xcatMgtIp; # Expected IP address of this xCAT MN on the Mgt Network +my $glob_xcatUser; # User defined to communicate with xCAT MN +my $glob_xcatUserPw; # User's password defined to communicate with xCAT MN +my @glob_zhcpDiskSpace; # Array information of directories in zhcp that should be validated for disk space +my @glob_zhcpFCPList; # Array of FCPs used by zHCP +my $glob_zhcpNode; # Node name for xCAT zHCP server (optional) + +# Global IVP run time variables +my $glob_versionInfo; # Version info for xCAT MN and zHCP +my $glob_successfulTestCnt = 0; # Number of successful tests +my @glob_failedTests; # List of failed tests. +#my @glob_hostNodes; # Array of host node names +my %glob_hostNodes; # Hash of host node information +my %glob_ignored; # List of ignored messages +my $glob_ignoreCnt = 0; # Number of times we ignored a message +my %glob_localIPs; # Hash of local IP addresses for the xCAT MN's system +my $glob_localZHCP = ''; # Local ZHCP node name and hostname when ZHCP is on xCAT MN's system +my $glob_totalFailed = 0; # Number of failed tests +my $glob_testNum = 0; # Number of tests that were run + +my $glob_versionFileCMA = '/opt/ibm/cmo/version'; +my $glob_versionFileXCAT = '/opt/xcat/version'; +my $glob_applSystemRole = '/var/lib/sspmod/appliance_system_role'; + +# Tables for environment variable and command line operand processing. +my ( $cmdOp_bypassMsg, $cmdOp_cNAddress, $cmdOp_defaultUserProfile, $cmdOp_diskpools, + $cmdOp_expectedReposSpace, $cmdOp_expUser, $cmdOp_hostNode, $cmdOp_ignore, + $cmdOp_instFCPList, $cmdOp_instFCPList, $cmdOp_macPrefix, $cmdOp_mgtNetmask, + $cmdOp_mnNode, $cmdOp_moreCmdOps, $cmdOp_bypassMsg, $cmdOp_networks, $cmdOp_pw_obfuscated, + $cmdOp_syslogErrors, $cmdOp_signalTimeout, $cmdOp_vswitchOSAs, + $cmdOp_xcatDiskSpace, $cmdOp_xcatMgtIp, $cmdOp_xcatMNIp, + $cmdOp_xcatUser, $cmdOp_zhcpFCPList, $cmdOp_zhcpNode, $cmdOp_zhcpDiskSpace ); +my @cmdOps = ( + { + 'envVar' => 'zxcatIVP_bypassMsg', + 'opName' => 'bypassMsg', + 'inpVar' => 'cmdOp_bypassMsg', + 'var' => 'glob_bypassMsg', + 'type' => 'scalar', + 'desc' => "Controls whether bypass messages are produced:\n" . + "0: do not show bypass messages, or\n" . + "1: show bypass messages.\n" . + "Bypass messages indicate when a test is not run. " . + "This usually occurs when a required environment variable or command line operand is " . + "missing.", + }, + { + 'envVar' => 'zxcatIVP_cNAddress', + 'opName' => 'cNAddress', + 'inpVar' => 'cmdOp_cNAddress', + 'var' => 'glob_cNAddress', + 'type' => 'scalar', + 'desc' => 'Specifies the IP address or hostname of the OpenStack compute node that is ' . + 'accessing the xCAT MN.', + }, + { + 'envVar' => 'zxcatIVP_defaultUserProfile', + 'opName' => 'defaultUserProfile', + 'inpVar' => 'cmdOp_defaultUserProfile', + 'var' => 'glob_defaultUserProfile', + 'type' => 'scalar', + 'desc' => 'Specifies the default profile that is used in creation of server instances.', + }, + { + 'envVar' => 'zxcatIVP_diskpools', + 'opName' => 'diskpools', + 'inpVar' => 'cmdOp_diskpools', + 'var' => 'glob_diskpools', + 'type' => 'array', + 'case' => 'uc', + 'separator' => ';, ', + 'desc' => 'Specifies an array of disk pools that are expected to exist. ' . + 'The IVP will verify that space exists in those disk pools. ', + }, + { + 'envVar' => 'zxcatIVP_expectedReposSpace', + 'opName' => 'expectedReposSpace', + 'inpVar' => 'cmdOp_expectedReposSpace', + 'var' => 'glob_expectedReposSpace', + 'type' => 'scalar', + 'default' => '1G', + 'desc' => 'Specifies the expected space available in the xCAT MN image repository. ' . + 'The OpenStack compute node attempts to ensure that the space is available ' . + 'in the xCAT image repository by removing old images. This can cause ' . + 'images it be removed and added more often than desired if the value is too high.', + }, + { + 'envVar' => 'zxcatIVP_expUser', + 'opName' => 'expUser', + 'inpVar' => 'cmdOp_expUser', + 'var' => 'glob_expUser', + 'type' => 'scalar', + 'desc' => 'Specifies the name of the user under which the OpenStack Nova component runs ' . + 'on the compute node. The IVP uses this name when it attempts to verify access ' . + 'of the xCAT MN to the compute node.', + }, + { + 'envVar' => 'zxcatIVP_hostNode', + 'opName' => 'hostNode', + 'inpVar' => 'cmdOp_hostNode', + 'var' => 'glob_hostNode', + 'type' => 'scalar', + 'desc' => 'Specifies the node of host being managed by the compute node. ' . + 'The IVP will verify that the node name exists and use this to determine the ' . + 'ZHCP node that supports the host. If this value is missing or empty, the ' . + 'IVP will validate all host nodes that it detects on the xCAT MN.', + }, + { + 'envVar' => 'zxcatIVP_ignore', + 'opName' => 'ignore', + 'inpVar' => 'cmdOp_ignore', + 'var' => 'glob_msgsToIgnore', + 'type' => 'hash', + 'case' => 'uc', + 'separator' => ';, ', + 'desc' => 'Specifies a comma separated list of message Ids that should be ignored. ' . + 'Ignored messages do not generate a full message and are not counted as ' . + 'trigger to notify the monitoring userid (see XCAT_notify property in the ' . + 'DMSSICNF COPY file). Instead a line will be generated in the output indicating ' . + 'that the message was ignored.', + }, + { + 'envVar' => 'zxcatIVP_instFCPList', + 'opName' => 'instFCPList', + 'inpVar' => 'cmdOp_instFCPList', + 'var' => 'glob_instFCPList', + 'type' => 'array', + 'separator' => ';, ', + 'desc' => 'Specifies the list of FCPs used by instances.', + }, + { + 'envVar' => 'zxcatIVP_macPrefix', + 'opName' => 'macPrefix', + 'inpVar' => 'cmdOp_macPrefix', + 'var' => 'glob_macPrefix', + 'type' => 'scalar', + 'desc' => 'Specifies user prefix for MAC Addresses of Linux level 2 interfaces.', + }, + { + 'envVar' => 'zxcatIVP_mgtNetmask', + 'opName' => 'mgtNetmask', + 'inpVar' => 'cmdOp_mgtNetmask', + 'var' => 'glob_mgtNetmask', + 'type' => 'scalar', + 'desc' => 'Specifies xCat management interface netmask.', + }, + { + 'envVar' => 'zxcatIVP_mnNode', + 'opName' => 'mnNode', + 'inpVar' => 'cmdOp_mnNode', + 'var' => 'glob_mnNode', + 'type' => 'scalar', + 'desc' => 'Specifies the node name for xCAT MN.', + }, + { + 'envVar' => 'zxcatIVP_moreCmdOps', + 'opName' => 'moreCmdOps', + 'inpVar' => 'cmdOp_moreCmdOps', + 'var' => 'glob_moreCmdOps', + 'type' => 'scalar', + 'desc' => 'Specifies additional command operands to be passed to the zxcatIVP script. ' . + 'This is used interally by the IVP programs.', + }, + { + 'envVar' => 'zxcatIVP_networks', + 'opName' => 'networks', + 'inpVar' => 'cmdOp_networks', + 'var' => 'glob_networks', + 'type' => 'array', + 'separator' => ';, ', + 'desc' => "Specifies an array of networks and possible VLAN ranges. " . + "The array is a list composed of network names and optional " . + "vlan ranges in the form: vswitch:vlan_min:vlan_max where " . + "each network and vlan range components are separated by a colon.\n" . + "For example, 'vsw1,vsw2:1:4095' specifies two vswitches vsw1 without a " . + "vlan range and vsw2 with a vlan range of 1 to 4095.", + }, + { + 'envVar' => 'zxcatIVP_pw_obfuscated', + 'opName' => 'pw_obfuscated', + 'inpVar' => 'cmdOp_pw_obfuscated', + 'var' => 'obfuscatePw', + 'type' => 'scalar', + 'desc' => "Indicates whether the password zxcatIVP_xcatUserPw is obfuscated:\n" . + "1 - obfuscated,\n0 - in the clear.", + }, + { + 'envVar' => 'zxcatIVP_signalTimeout', + 'opName' => 'signalTimeout', + 'inpVar' => 'cmdOp_signalTimeout', + 'var' => 'glob_signalTimeout', + 'type' => 'scalar', + 'default' => '30', + 'desc' => "Specifies the minimum acceptable time value that should be specified ". + "in the z/VM using the SET SIGNAL SHUTDOWNTIME configuration statement. ". + "A value less than this value will generate a warning in the IVP.", + }, + { + 'envVar' => 'zxcatIVP_syslogErrors', + 'opName' => 'syslogErrors', + 'inpVar' => 'cmdOp_syslogErrors', + 'var' => 'glob_syslogErrors', + 'type' => 'scalar', + 'default' => '1', + 'desc' => "Specifies whether Warnings and Errors detected by the IVP are ". + "logged in the xCAT MN syslog:\n0: do not log,\n1: log to syslog.", + }, + { + 'envVar' => 'zxcatIVP_vswitchOSAs', + 'opName' => 'vswitchOSAs', + 'inpVar' => 'cmdOp_vswitchOSAs', + 'var' => 'glob_vswitchOSAs', + 'type' => 'hash', + 'separator' => ';, ', + 'desc' => 'Specifies vswitches and their related OSAs that are used by ' . + 'systems created by the OpenStack compute node.', + }, + { + 'envVar' => 'zxcatIVP_xcatDiskSpace', + 'opName' => 'xcatDiskSpace', + 'inpVar' => 'cmdOp_xcatDiskSpace', + 'var' => 'glob_xcatDiskSpace', + 'type' => 'array', + 'separator' => ';,', + 'default' => '/ 80 . 10M;/install 90 1g .', + 'desc' => 'Specifies a list of directories in the xCAT server that should be '. + 'verified for storage availability. Each directory consists of '. + 'a blank separated list of values:'. + "\n". + '* directory name,'. + "\n". + '* maximum in use percentage (a period indicates that the value should not be tested),'. + "\n". + '* minumum amount of available storage (period indicates that '. + 'available storage based on size should not be validated),'. + "\n". + '* minimum file size at which to generate a warning when available space tests '. + 'detect a size issue (a period indicates that the value should not be tested).'. + "\n\n". + "For example: '/ 80 5G 3M' will cause the IVP to check the space for the ". + 'root directory (/) to verify that it has at least 80% space available or '. + '5G worth of space available. If the space tests fail, a warning will be '. + 'generated for each file (that is not a jar or so file) which is 3M or larger. '. + 'Additional directories may be specified using a list separator.', + }, + { + 'envVar' => 'zxcatIVP_xcatMgtIp', + 'opName' => 'xcatMgtIp', + 'inpVar' => 'cmdOp_xcatMgtIp', + 'var' => 'glob_xcatMgtIp', + 'type' => 'scalar', + 'desc' => 'Specifies xCat MN\'s IP address on the xCAT management network.', + }, + { + 'envVar' => 'zxcatIVP_xcatMNIp', + 'opName' => 'xcatMNIp', + 'inpVar' => 'cmdOp_xcatMNIp', + 'var' => 'glob_xcatMNIp', + 'type' => 'scalar', + 'desc' => 'Specifies the expected IP address of the xcat management node.', + }, + { + 'envVar' => 'zxcatIVP_xcatUser', + 'opName' => 'xcatUser', + 'inpVar' => 'cmdOp_xcatUser', + 'var' => 'glob_xcatUser', + 'type' => 'scalar', + 'desc' => 'Specifies the user defined to communicate with xCAT management node.', + }, + { + 'envVar' => 'zxcatIVP_xcatUserPw', + 'opName' => 'xcatUserPw', + 'inpVar' => 'cmdOp_xcatUserPw', + 'var' => 'glob_xcatUserPw', + 'type' => 'scalar', + 'desc' => 'Specifies the user password defined to communicate with xCAT MN over the REST API.', + }, + { + 'envVar' => 'zxcatIVP_zhcpFCPList', + 'opName' => 'zhcpFCPList', + 'inpVar' => 'cmdOp_zhcpFCPList', + 'var' => 'glob_zhcpFCPList', + 'type' => 'array', + 'separator' => ';, ', + 'desc' => 'Specifies the list of FCPs used by zHCP.', + }, + { + 'envVar' => 'zxcatIVP_zhcpNode', + 'opName' => 'zhcpNode', + 'inpVar' => 'cmdOp_zhcpNode', + 'var' => 'glob_zhcpNode', + 'type' => 'scalar', + 'desc' => 'Specifies the expected ZHCP node name that the compute node ' . + 'expects to be used to manage the z/VM host.', + }, + { + 'envVar' => 'zxcatIVP_zhcpDiskSpace', + 'opName' => 'zhcpDiskSpace', + 'inpVar' => 'cmdOp_zhcpDiskSpace', + 'var' => 'glob_zhcpDiskSpace', + 'type' => 'array', + 'separator' => ';,', + 'default' => '/ 90 . 10M', + 'desc' => "Specifies a list of directories in the ZHCP server that should be ". + 'verified for storage availability. Each directory consists of '. + 'a blank separated list of values:'. + "\n". + '* directory name,'. + "\n". + '* maximum in use percentage (a period indicates that the value should not be tested),'. + "\n". + '* minumum amount of available storage (period indicates that '. + 'available storage based on size should not be validated),'. + "\n". + '* minimum file size at which to generate a warning when available space tests '. + 'detect a size issue (a period indicates that the value should not be tested).'. + "\n\n". + "For example: '/ 80 5G 3M' will cause the IVP to check the space for the ". + 'root directory (/) to verify that it has at least 80% space available or '. + '5G worth of space available. If the space tests fail, a warning will be '. + 'generated for each file (that is not a jar or so file) which is 3M or larger. '. + 'Additional directories may be specified using a list separator.', + }, + ); + +my $usage_string = "Usage:\n + zxcatIVP +or + zxcatIVP +or + zxcatIVP --help +or + zxcatIVP -h\n\n"; + + +#------------------------------------------------------- + +=head3 applyOverrides + + Description : Apply the overrides from either + the environment variables or command + line to the target global variables. + Arguments : None + Returns : None. + Example : applyOverrides(); + +=cut + +#------------------------------------------------------- +sub applyOverrides{ + # Handle the normal case variables and values. + foreach my $opHash ( @cmdOps ) { + my $opVarRef = eval('\$' . $opHash->{'inpVar'}); + if ( ! defined $$opVarRef) { + #print "Did not find \$$opHash->{'inpVar'}\n"; + next; + } else { + #print "key: $opHash->{'inpVar'}, value: $$opVarRef\n" + } + + # Modify the case of the value, if necessary. + if ( ! exists $opHash->{'case'} ) { + # Ignore case handling + } elsif ( $opHash->{'case'} eq 'uc' ) { + $$opVarRef = uc( $$opVarRef ); + } elsif ( $opHash->{'case'} eq 'lc' ) { + $$opVarRef = lc( $$opVarRef ); + } + + # Process the value to set the variable in this script. + if ( $opHash->{'type'} eq "scalar" ) { + my $globRef = eval('\$' . $opHash->{'var'}); + $$globRef = $$opVarRef; + } elsif ( $opHash->{'type'} eq "array" ) { + my $globRef = eval('\@' . $opHash->{'var'}); + my @array; + if ( $opHash->{'separator'} =~ /,/ and $$opVarRef =~ /,/ ) { + @array = split( ',', $$opVarRef ); + } elsif ( $opHash->{'separator'} =~ /;/ and $$opVarRef =~ /;/ ) { + @array = split( ';', $$opVarRef ); + } elsif ( $opHash->{'separator'} =~ /\s/ and $$opVarRef =~ /\s/ ) { + @array = split( '\s', $$opVarRef ); + } else { + push @array, $$opVarRef; + } + @$globRef = @array; + } elsif ( $opHash->{'type'} eq "hash" ) { + my $globRef = eval('\%' . $opHash->{'var'}); + my @array; + my %hash; + if ( $opHash->{'separator'} =~ /,/ and $$opVarRef =~ /,/ ) { + @array = split( ',', $$opVarRef ); + %hash = map { $_ => 1 } @array; + } elsif ( $opHash->{'separator'} =~ /;/ and $$opVarRef =~ /;/ ) { + @array = split( ';', $$opVarRef ); + %hash = map { $_ => 1 } @array; + } elsif ( $opHash->{'separator'} =~ /\s/ and $$opVarRef =~ /\s/ ) { + @array = split( '\s', $$opVarRef ); + %hash = map { $_ => 1 } @array; + } else { + $hash{$$opVarRef} = 1; + } + %$globRef = %hash; + } else { + print "Internal error: Unsupported \%cmdOpRef type '$opHash->{'type'}' for $opHash->{'inpVar'}\n"; + } + } +} + + +#------------------------------------------------------- + +=head3 calculateRoutingPrefix + + Description : Calculate the routing prefix for a given subnet mask. + Arguments : Subnet Mask + Returns : -1 - Unable to calculate routing prefix + zero or non-zero - Routing prefix number + Example : $rc = calculateRoutingPrefix( $subnetMask ); + +=cut + +#------------------------------------------------------- +sub calculateRoutingPrefix{ + my ( $subnetMask ) = @_; + my $routingPrefix = 0; + my @parts; + + # Determine the inet version based on the mask separator and + # calculate the routing prefix. + if ( $subnetMask =~ m/\./ ) { + # inet 4 mask + @parts = split( /\./, $subnetMask ); + foreach my $part ( @parts ) { + if (( $part =~ /\D/ ) || ( length($part) > 3 )) { + return -1; # subnet mask is not valid + } + foreach my $i ( 1, 2, 4, 8, + 16, 32, 64, 128 ) { + if ( $part & $i ) { + $routingPrefix++; + } + } + } + } elsif ( $subnetMask =~ m/\:/ ) { + # inet 6 mask + @parts = split( /:/, $subnetMask ); + foreach my $part ( @parts ) { + if (( $part =~ /[^0-9^a-f^A-F]/ ) || ( length($part) > 4 )) { + print "part failed: $part\n"; + return -1; # subnet mask is not valid + } + $part = hex $part; + foreach my $i ( 1, 2, 4, 8, + 16, 32, 64, 128, + 256, 512, 1024, 2048, + 4096, 8192, 16384, 32768 ) { + if ( $part & $i ) { + $routingPrefix++; + } + } + } + } + + return $routingPrefix +} + + +#------------------------------------------------------- + +=head3 convertDiskSize + + Description : Reduce a size with a magnitude (eg. 25G or 25M) + to a common scalar value. + Arguments : Size to convert. + Returns : non-negative - No error + -1 - Error detected. + Example : my $size = convertDiskSize( $diskType, $diskSize ); + +=cut + +#------------------------------------------------------- +sub convertDiskSize{ + my ( $diskType, $diskSize ) = @_; + my $size; + + my $bytesPer3390Cylinder = 849960; + my $bytesPer3380Cylinder = 712140; + my $bytesPer9345Cylinder = 696840; + my $bytesPerFbaBlock = 512; + my $cylindersPer3390_03 = 3339; + my $kilobyte = 1024; + my $megabyte = 1024 ** 2; + my $gigabyte = 1024 ** 3; + + $diskType = uc( $diskType ); + if ( $diskType =~ '3390-' ) { + $size = $diskSize * $bytesPer3390Cylinder / $gigabyte; + $size = sprintf("%.2f", $size); + $size = "$diskSize(cyl) -> $size" . "Gig"; + } elsif ( $diskType =~ '3380-') { + $size = $diskSize * $bytesPer3380Cylinder / $gigabyte; + $size = sprintf("%.2f", $size); + $size = "$diskSize(cyl) -> $size" . "Gig"; + } elsif ( $diskType =~ '9345-') { + $size = $diskSize * $bytesPer9345Cylinder / $gigabyte; + $size = sprintf("%.2f", $size); + $size = "$diskSize(cyl) -> $size" . "Gig"; + } elsif ( $diskType =~ '9336-') { + $size = $diskSize * $bytesPerFbaBlock / $gigabyte; + $size = sprintf("%.2f", $size); + $size = "$diskSize(block) -> $size" . "Gig"; + } elsif ( $diskType =~ '9332') { + $size = $diskSize * $bytesPerFbaBlock / $gigabyte; + $size = "$diskSize(block)"; + } else { + $size = "$diskSize"; + } + + return $size; +} + + +#------------------------------------------------------- + +=head3 convertSize + + Description : Reduce a size with a magnitude (eg. 25G or 25M) + to a common scalar value. + Arguments : Size to convert. + Returns : non-negative - No error + -1 - Error detected. + Example : my $size = convertSize( "25G" ); + +=cut + +#------------------------------------------------------- +sub convertSize{ + my ( $magSize ) = @_; + my $size; + my $numeric; + my $kilobyte = 1024; + my $megabyte = 1024 ** 2; + my $gigabyte = 1024 ** 3; + my $terabyte = 1024 ** 4; + my $petabyte = 1024 ** 5; + my $exabyte = 1024 ** 6; + + $magSize = uc( $magSize ); + $numeric = substr( $magSize, 0, -1 ); + if ( length $magSize == 0 ) { + logTest( 'misc', "size is less than expected, value: $magSize." ); + } elsif ( $magSize =~ m/K$/ ) { + $size = $numeric * $kilobyte; + } elsif ( $magSize =~ m/M$/ ) { + $size = $numeric * $megabyte; + } elsif ( $magSize =~ m/G$/ ) { + $size = $numeric * $gigabyte; + } elsif ( $magSize =~ m/T$/ ) { + $size = $numeric * $terabyte; + } elsif ( $magSize =~ m/P$/ ) { + $size = $numeric * $petabyte; + } elsif ( $magSize =~ m/E$/ ) { + $size = $numeric * $exabyte; + } else { + logTest( 'misc', "magnitude of $magSize is unknown." ); + return -1; + } + + return $size; +} + + +#------------------------------------------------------- + +=head3 driveREST + + Description : Verify the REST interface is running. + Arguments : IP address + User + Password + Rest Object ( e.g. nodes/xcat ) + Method ( GET | PUT | POST | DELETE ) + Format + Returns : Response structure + Example : my $response = driveREST( $glob_xcatMNIp, $glob_xcatUser, + $glob_xcatUserPw, "nodes/$glob_mnNode", "GET", "json", \@restOps ); + +=cut + +#------------------------------------------------------- +sub driveREST{ + my ( $addr, $user, $pw, $obj, $method, $format, $restOps) = @_; + my $url = "https://$addr/xcatws/$obj" . "?userName=$user&password=$pw" . + "&format=$format"; + + my @updatearray; + my $fieldname; + my $fieldvalue; + my @args = (); + if ( scalar( @args ) > 0 ){ + foreach my $tempstr (@args) { + push @updatearray, $tempstr; + } + } + + my $request; + + my $ua = LWP::UserAgent->new(); + my $response; + if (( $method eq 'PUT' ) or ( $method eq 'POST' )) { + my $tempstr = encode_json \@updatearray; + $request = HTTP::Request->new( $method => $url ); + $request->header('content-type' => 'text/plain'); + $request->header( 'content-length' => length( $tempstr ) ); + $request->content( $tempstr ); + } elsif (( $method eq 'GET' ) or ( $method eq 'DELETE' )) { + $request = HTTP::Request->new( $method=> $url ); + } + + $response = $ua->request( $request ); + + #print $response->content . "\n"; + #print "code: " . $response->code . "\n"; + #print "message: " .$response->message . "\n"; + return $response; +} + + +#------------------------------------------------------- +=head3 findZhcpNode + + Description : Find the object name of the zHCP node. + Arguments : Target node whose ZHCP we want to find + Returns : zHCP node name, if found + undefined, if not found + Example : my $zhcpNode = findZhcpNode(); + +=cut + +#------------------------------------------------------- +sub findZhcpNode{ + my ( $targetNode) = @_; + my $rc = 0; + my $zhcpNode; + + # Get the HCP hostname from the node + my %targetInfo = getLsdefNodeInfo( $targetNode ); + my $hcpHostname = $targetInfo{'hcp'}; + + # Find the node that owns the zHCP hostname + my @nodes = getNodeNames(); + foreach my $node (@nodes){ + my %nodeInfo = getLsdefNodeInfo( $node ); + if ( $nodeInfo{'hostnames'} =~ $hcpHostname ) { + $zhcpNode = $node; + last; + } + } + + return $zhcpNode; +} + + +#------------------------------------------------------- + +=head3 getDiskPoolNames + + Description : Obtain the list of disk pools for a + z/VM host. + Arguments : Host Node + Returns : Array of disk pool names - No error + empty array - Error detected. + Example : my @pools = getDiskPoolNames($node); + +=cut + +#------------------------------------------------------- +sub getDiskPoolNames{ + my ( $hostNode) = @_; + my @pools; + + # Find the related zHCP node + my $zhcpNode = findZhcpNode( $hostNode ); + if ( !defined $zhcpNode ) { + return @pools; + } + + my $out = `/opt/xcat/bin/lsvm $zhcpNode --diskpoolnames | awk '{print \$NF}'`; + @pools = split /\n/, $out; + return @pools; +} + + +#------------------------------------------------------- + +=head3 getHostNodeNames + + Description : Get a list of the host nodes defined to this + xCAT MN. + Arguments : none + Returns : List of host nodes + undefined - Error detected. + Example : my @hostNodes = getHostNodeNames(); + +=cut + +#------------------------------------------------------- +sub getHostNodeNames{ + my @nodes = getNodeNames(); + my @hostNodes; + + foreach my $node (@nodes){ + my %nodeInfo = getLsdefNodeInfo( $node ); + if ( ! %nodeInfo ) { + next; + } + if (( exists $nodeInfo{'hosttype'} ) and ( $nodeInfo{'hosttype'} =~ 'zvm' )) { + push( @hostNodes, $node); + } + } + + return @hostNodes; +} + + +#------------------------------------------------------- + +=head3 getLocalIPs + + Description : Get the IP addresses from ifconfig. + Arguments : Node name or IP address + Returns : Hash of local IP addresses + Example : %localIPs = getLocalIPs(); + +=cut + +#------------------------------------------------------- +sub getLocalIPs { + my $ip; + my $junk; + my %localIPs; + my $rc = 0; + + my $out = `/sbin/ip addr | grep -e '^\\s*inet' -e '^\\s*inet6'`; + my @lines = split( '\n', $out ); + foreach my $line ( @lines ) { + my @parts = split( ' ', $line ); + ($ip) = split( '/', $parts[1], 2 ); + $localIPs{$ip} = 1; + } + +FINISH_getLocalIPs: + return %localIPs; +} + + +#------------------------------------------------------- + +=head3 getLsdefNodeInfo + + Description : Obtain node info from LSDEF. + Arguments : Name of node to retrieve + Returns : Hash of node properties. + Example : my %hash = getLsdefNodeInfo($node); + +=cut + +#------------------------------------------------------- +sub getLsdefNodeInfo{ + my ( $node) = @_; + my %hash; + + my $out = `/opt/xcat/bin/lsdef $node`; + + my @list1 = split /\n/, $out; + foreach my $item (@list1) { + if ( $item !~ "Object name:" ) { + my ($i,$j) = split(/=/, $item); + $i =~ s/^\s+|\s+$//g; # trim both ends of the string + $hash{$i} = $j; + } + } + + return %hash; +} + + +#------------------------------------------------------- + +=head3 getNodeNames + + Description : Get a list of the nodes defined to this + xCAT MN. + Arguments : none + Returns : Array of nodes + undefined - Error detected. + Example : my @nodes = getNodeNames(); + +=cut + +#------------------------------------------------------- +sub getNodeNames{ + my $out = `/opt/xcat/bin/lsdef | sed "s/ (node)//g"`; + my @nodes = split( /\n/, $out ); + return @nodes; +} + + +#------------------------------------------------------- + +=head3 getUseridFromLinux + + Description : Obtain the z/VM virtual machine userid from + /proc/sysinfo file. + Arguments : Variable to receive the output + Returns : 0 - No error + non-zero - Can't get the virtual machine id. + Example : my $rc = getUseridFromLinux( \$userid ); + +=cut + +#------------------------------------------------------- +sub getUseridFromLinux{ + my ( $userid) = @_; + my $rc = 0; + + $$userid = `cat /proc/sysinfo | grep 'VM00 Name:' | awk '{print \$NF}'`; + $$userid =~ s/^\s+|\s+$//g; # trim both ends of the string + + if ( $$userid ne '' ) { + $rc = 1; + } + + return $rc; +} + + +#------------------------------------------------------- + +=head3 getVswitchInfo + + Description : Query a vswitch and produce a hash of the data. + Arguments : zHCP node + Name of switch to be queried + Returns : hash of switch data, if found. + hash contains either: + $switchInfo{'Base'}{$property} = $value; + $switchInfo{'Authorized users'}{'User'} = $value; + $switchInfo{'Connections'}{$property} = $value; + $switchInfo{'Real device xxxx'}{$property} = $value; + Example : $rc = getVswitchInfo( $zhcpNode, $switch ); + +=cut + +#------------------------------------------------------- +sub getVswitchInfo{ + my ( $zhcpNode, $switch ) = @_; + my %switchInfo; + my @word; + my $device; + + my $out = `ssh $zhcpNode smcli Virtual_Network_Vswitch_Query -T xxxx -s $switch`; + if ( $out !~ /^Failed/ ) { + # Got some information. Process it. + my @lines = split( "\n", $out ); + pop( @lines ); + my $subsection = 'Base'; + foreach my $line ( @lines ) { + #print "line: $line\n"; + my $indent = $line =~ /\S/ ? $-[0] : length $line; # Get indentation level + $line =~ s/^\s+|\s+$//g; # trim both ends of the line; + if ( $line eq '' ) { + next; + } elsif ( $indent == 0 ) { + if ( $line =~ 'VSWITCH:' ) { + $line = substr( $line, 8 ); + $line =~ s/^\s+|\s+$//g; # trim both ends of the line; + @word = split( /:/, $line ); + $word[1] =~ s/^\s+|\s+$//g; # trim both ends of the line; + $switchInfo{'Base'}{$word[0]} = $word[1]; + } + } elsif ( $indent == 2 ) { + if ( $line =~ /Devices:/ ) { + $subsection = 'Real device'; + } elsif ( $line =~ /Authorized users:/ ) { + $subsection = 'Authorized users'; + } elsif ( $line =~ /Connections:/ ) { + $subsection = 'Connections'; + } else { + $subsection = 'Base'; + @word = split( /:/, $line ); + $switchInfo{$subsection}{$word[0]} = $word[1]; + } + } elsif ( $indent == 4 ) { + if ( $subsection eq 'Real device' ) { + @word = split( ':', $line ); + if ( $line =~ /Real device:/ ) { + $device = $word[1]; + $device =~ s/^\s+|\s+$//g; # trim both ends of the string + } else { + if ( !exists $word[1] ) { + $word[1] = ''; + } + my $key = "$subsection $device"; + $switchInfo{$key}{$word[0]} = $word[1]; + } + } elsif ( $subsection eq 'Authorized users' ) { + @word = split( ':', $line ); + if ( $word[1] eq '' ) { + next; + } + if ( exists $switchInfo{$subsection} ) { + $switchInfo{$subsection} = "$switchInfo{$subsection} $word[1]"; + } else { + $switchInfo{$subsection} = "$word[1]"; + } + } elsif ( $subsection eq 'Connections' ) { + @word = split( ' ', $line ); + if ( !exists $word[2] ) { + next; + } + $switchInfo{$subsection}{$word[2]} = $word[5]; + } + } + } + } + return %switchInfo; +} + + +#------------------------------------------------------- + +=head3 getVswitchInfoExtended + + Description : Query a vswitch and produce a hash of the data + using the extended (keyword) related API. + Arguments : zHCP node + Name of switch to be queried + Returns : hash of switch data, if found. + hash contains sections and hash/value pairs: + $switchInfo{'Base'}{$property} = $value; + $switchInfo{'Real device'}{$device}{$property} = $value; + $switchInfo{'Authorized users'}{$authUser}{$property} = $value; + $switchInfo{'Connections'}{$adapter_owner}{$property} = $value; + Example : $rc = getVswitchInfoExtended( $zhcpNode, $switch ); + +=cut + +#------------------------------------------------------- +sub getVswitchInfoExtended{ + my ( $zhcpNode, $switch ) = @_; + my %switchInfo; + my @word; + my $device; + my $authUser; + + my $out = `ssh $zhcpNode smcli Virtual_Network_Vswitch_Query_Extended -T xxxx -k switch_name=$switch`; + if ( $out !~ /^Failed/ ) { + # Got some information. Process it. + my @lines = split( "\n", $out ); + pop( @lines ); + my $subsection = 'Base'; + my $authPort; + my $adapter_owner; + + foreach my $line ( @lines ) { + #print "line: $line\n"; + my $indent = $line =~ /\S/ ? $-[0] : length $line; # Get indentation level + $line =~ s/^\s+|\s+$//g; # trim both ends of the line; + if ( $line eq '' ) { + next; + } + + $line =~ s/^\s+|\s+$//g; # trim both ends of the line; + @word = split( /:/, $line ); + $word[1] =~ s/^\s+|\s+$//g; # trim both ends of the line; + if ( !exists $word[1] ) { + $word[1] = ''; + } + + if ( $word[0] eq 'switch_name' ) { + $switchInfo{'Base'}{$word[0]} = $word[1]; + $subsection = 'Base'; + next; + } elsif ( $word[0] eq 'real_device_address' ) { + $subsection = 'Real device'; + $device = $word[1]; + if ( !exists $switchInfo{$subsection}{'RDEVs'} ) { + $switchInfo{$subsection}{'RDEVs'} = $device; + } else { + $switchInfo{$subsection}{'RDEVs'} = $switchInfo{$subsection}{'RDEVs'} . ' ' . $device; + } + next; + } elsif ( $word[0] eq 'port_num' ) { + $subsection = 'Authorized users'; + $authPort = $word[1]; + next; + } elsif ( $word[0] eq 'adapter_owner' ) { + $subsection = 'Connections'; + $adapter_owner = $word[1]; + if ( !exists $switchInfo{$subsection}{'ConnectedUsers'} ) { + $switchInfo{$subsection}{'ConnectedUsers'} = $adapter_owner; + } else { + $switchInfo{$subsection}{'ConnectedUsers'} = $switchInfo{$subsection}{'ConnectedUsers'} . ' ' . $adapter_owner; + } + next; + } + + # Fill in hash based upon the subsection we are handling. + my $key; + if ( $subsection eq 'Base' ) { + $switchInfo{$subsection}{$word[0]} = $word[1]; + } elsif ( $subsection eq 'Real device' ) { + $switchInfo{$subsection}{$device}{$word[0]} = $word[1]; + } elsif ( $subsection eq 'Authorized users' ) { + if ( $word[0] eq 'grant_userid' ) { + $authUser = $word[1]; + $switchInfo{$subsection}{$authUser}{'port_num'} = $authPort; + if ( !exists $switchInfo{$subsection}{'AuthorizedUsers'} ) { + $switchInfo{$subsection}{'AuthorizedUsers'} = $authUser; + } else { + $switchInfo{$subsection}{'AuthorizedUsers'} = $switchInfo{$subsection}{'AuthorizedUsers'} . ' ' . $authUser; + } + } else { + $switchInfo{$subsection}{$authUser}{$word[0]} = $word[1]; + } + } elsif ( $subsection eq 'Connections' ) { + $switchInfo{$subsection}{$adapter_owner}{$word[0]} = $word[1]; + } + } + } + return %switchInfo; +} + + +#------------------------------------------------------- + +=head3 hexDecode + + Description : Convert a string of printable hex + characters (4 hex characters per actual + character) into the actual string that + it represents. + Arguments : printable hex value + Returns : Perl string + Example : $rc = hexDecode(); + +=cut + +#------------------------------------------------------- +sub hexDecode { + my ( $hexVal ) = @_; + my $result = ''; + + if ( $hexVal =~ /^HexEncoded:/ ) { + ($hexVal) = $hexVal =~ m/HexEncoded:(.*)/; + my @hexes = unpack( "(a4)*", $hexVal); + for ( my $i = 0; $i < scalar(@hexes); $i++ ) { + $result .= chr( hex( $hexes[$i] ) ); + } + } else { + $result = $hexVal; + } + + return $result; +} + + +#------------------------------------------------------- + +=head3 logTest + + Description : Log the start and result of a test. + Failures are added to syslog and printed as script output. + Arguments : Status of the test: + bypassed: Bypassed a test (STDOUT, optionally SYSLOGged) + failed: Failed test (STDOUT, optionally SYSLOGged) + passed: Successful test (STDOUT only) + started: Start test (STDOUT only, increments test number) + misc: Miscellaneous output (STDOUT only) + miscNF: Miscellaneous non-formatted output (STDOUT only) + info: Information output similar to miscellaneous output + but has a message number (STDOUT only) + Message ID (used for "bypassed", "failed", or "warning" messages) or + message TEXT (used for "misc", "passed", or "started" messages). + Message id should begin with the initials of the subroutine + generating the message and begin at 1. For example, the + first error message from verifyNode subroutine would be 'VN01'. + Message substitution values (used for "bypassed", "failed", or + "warning" messages) + Returns : None + Example : logTest( 'failed', "VMNI01", $name, $tgtIp ); + logTest( 'started', "xCAT MN has a virtual storage size of at least $vstorMin." ); + +=cut + +#------------------------------------------------------- +sub logTest{ + my ( $testStatus, $msgInfo, @msgSubs ) = @_; + my $extraInfo; + my $rc; + my $sev; + my $msg; + + if ( $testStatus eq 'misc' ) { + # Miscellaneous output + $msgSubs[0] = "$msgInfo\n"; + ( $rc, $sev, $msg, $extraInfo ) = xCAT::zvmMsgs->buildMsg('ZXCATIVP', 'GENERIC_RESPONSE', \@msgSubs ); + print( "$msg\n" ); + } elsif ( $testStatus eq 'miscNF' ) { + # Miscellaneous output + print("$msgInfo\n"); + } elsif ( $testStatus eq 'passed' ) { + # Test was successful. Log it as ok. + if ( $msgInfo ne '' ) { + $msgSubs[0] = "$msgInfo\n"; + ( $rc, $sev, $msg, $extraInfo ) = xCAT::zvmMsgs->buildMsg('ZXCATIVP', 'GENERIC_RESPONSE', \@msgSubs ); + print( "$msg\n" ); + } + } elsif ( $testStatus eq 'started' ) { + # Start test + $glob_testNum++; + print( "\n" ); + $msgSubs[0] = "Test $glob_testNum: Verifying $msgInfo"; + ( $rc, $sev, $msg, $extraInfo ) = xCAT::zvmMsgs->buildMsg('ZXCATIVP', 'GENERIC_RESPONSE', \@msgSubs ); + print( "$msg\n" ); + } else { + ( $rc, $sev, $msg, $extraInfo ) = xCAT::zvmMsgs->buildMsg('ZXCATIVP', $msgInfo, \@msgSubs ); + + # Determine whether we need to ignore the message or produce it and count it. + if ( defined $glob_msgsToIgnore{$msgInfo} ) { + # Ignore this message id + $glob_ignored{$msgInfo} = 1; + $glob_ignoreCnt += 1; + print( "Message $msgInfo is being ignored but would have occurred here.\n" ); + } elsif ( defined $glob_msgsToIgnore{$sev} ) { + # Ignoring all messages of this severity. + $glob_ignored{$msgInfo} = 1; + $glob_ignoreCnt += 1; + print( "Message $msgInfo is being ignored but would have occurred here.\n" ); + } else { + # Handle the failed, warning and bypassed messages + if ( $testStatus eq 'failed' ) { + # Test failed. Log it as failure and produce necessary messages + $glob_totalFailed += 1; + if ( $glob_totalFailed == 1 || $glob_failedTests[-1] != $glob_testNum ) { + push( @glob_failedTests, $glob_testNum ); + } + print( "$msg" ); + if ( $extraInfo ne '' ) { + print( "$extraInfo" ); + } + } elsif ( $testStatus eq 'warning' ) { + # Warning unrelated to a test. + print("$msg"); + if ( $extraInfo ne '' ) { + print( "$extraInfo" ); + } + } elsif ( $testStatus eq 'info' ) { + # Information message + print("$msg"); + if ( $extraInfo ne '' ) { + print( "$extraInfo" ); + } + } elsif ( $testStatus eq 'bypassed' ) { + # Bypass message + if ( $glob_bypassMsg != 0 ) { + print("$msg"); + if ( $extraInfo ne '' ) { + print( "$extraInfo" ); + } + } + } + + # Write the message to syslog + if ( $testStatus ne 'info' ) { + my $logMsg = $msg; + $logMsg =~ s/\t//g; + $logMsg =~ s/\n/ /g; + syslog( 'err', $logMsg ); + } + } + } +} + + +#------------------------------------------------------- + +=head3 setOverrides + + Description : Set global variables based on input from + an external driver perl script, the + command line or the zxcatIVP_moreCmdOps + environment variable. This allows + the script to be run standalone or overriden + by a driver perl script. + Arguments : None + Returns : None. + Example : setOverrides(); + +=cut + +#------------------------------------------------------- +sub setOverrides{ + my $rc; + my $unrecognizedOps = ''; + my $val; + + # Read the environment variables. + foreach my $opHash ( @cmdOps ) { + my $inpRef = eval('\$' . $opHash->{'inpVar'}); + + # Update the local input variable with the value from the environment + # variable or set the default. + if ( defined $ENV{ $opHash->{'envVar'} } ) { + $$inpRef = $ENV{ $opHash->{'envVar'} }; + } else { + if ( exists $opHash->{'default'} ) { + $$inpRef = $opHash->{'default'}; + } else { + next; + } + } + } + + # Apply the environent variables as overrides to the global variables in this script. + applyOverrides(); + + # Clear the input variables so that we can use them for command line operands. + foreach my $opHash ( @cmdOps ) { + my $inpRef = eval('\$' . $opHash->{'inpVar'}); + $$inpRef = undef; + } + + # Handle options from the command line. + $Getopt::Long::ignorecase = 0; + Getopt::Long::Configure( "bundling" ); + if ( !GetOptions( + 'bypassMsg=s' => \$cmdOp_bypassMsg, + 'cNAddress=s' => \$cmdOp_cNAddress, + 'defaultUserProfile=s' => \$cmdOp_defaultUserProfile, + 'diskpools=s' => \$cmdOp_diskpools, + 'expectedReposSpace=s' => \$cmdOp_expectedReposSpace, + 'expUser=s' => \$cmdOp_expUser, + 'h|help' => \$glob_displayHelp, + 'hostNode=s' => \$cmdOp_hostNode, + 'ignore=s' => \$cmdOp_ignore, + 'instFCPList=s' => \$cmdOp_instFCPList, + 'macPrefix=s' => \$cmdOp_macPrefix, + 'mgtNetmask=s' => \$cmdOp_mgtNetmask, + 'mnNode=s' => \$cmdOp_mnNode, + 'moreCmdOps=s' => \$glob_moreCmdOps, + 'networks=s' => \$cmdOp_networks, + 'pw_obfuscated' => \$cmdOp_pw_obfuscated, + 'signalTimeout=s' => \$cmdOp_signalTimeout, + 'syslogErrors' => \$cmdOp_syslogErrors, + 'vswitchOSAs=s' => \$cmdOp_vswitchOSAs, + 'xcatDiskSpace=s' => \$cmdOp_xcatDiskSpace, + 'xcatMgtIp=s' => \$cmdOp_xcatMgtIp, + 'xcatMNIp=s' => \$cmdOp_xcatMNIp, + 'xcatUser=s' => \$cmdOp_xcatUser, + 'zhcpDiskSpace=s' => \$cmdOp_zhcpDiskSpace, + 'zhcpFCPList=s' => \$cmdOp_zhcpFCPList, + 'zhcpNode=s' => \$cmdOp_zhcpNode, + )) { + print $usage_string; + } + + # Handle options passed using the environment variable. + # This will override the same value that was passed in the command line. + # Don't specify the same option on both the command line and in the environment variable. + if ( defined $glob_moreCmdOps ) { + $glob_moreCmdOps =~ hexDecode( $glob_moreCmdOps ); + ($rc, $unrecognizedOps) = GetOptionsFromString( + $glob_moreCmdOps, + 'bypassMsg=s' => \$cmdOp_bypassMsg, + 'cNAddress=s' => \$cmdOp_cNAddress, + 'defaultUserProfile=s' => \$cmdOp_defaultUserProfile, + 'diskpools=s' => \$cmdOp_diskpools, + 'expectedReposSpace=s' => \$cmdOp_expectedReposSpace, + 'expUser=s' => \$cmdOp_expUser, + 'h|help' => \$glob_displayHelp, + 'hostNode=s' => \$cmdOp_hostNode, + 'ignore=s' => \$cmdOp_ignore, + 'instFCPList=s' => \$cmdOp_instFCPList, + 'macPrefix=s' => \$cmdOp_macPrefix, + 'mgtNetmask=s' => \$cmdOp_mgtNetmask, + 'mnNode=s' => \$cmdOp_mnNode, + 'networks=s' => \$cmdOp_networks, + 'pw_obfuscated' => \$cmdOp_pw_obfuscated, + 'signalTimeout=s' => \$cmdOp_signalTimeout, + 'syslogErrors' => \$cmdOp_syslogErrors, + 'vswitchOSAs=s' => \$cmdOp_vswitchOSAs, + 'xcatDiskSpace=s' => \$cmdOp_xcatDiskSpace, + 'xcatMgtIp=s' => \$cmdOp_xcatMgtIp, + 'xcatMNIp=s' => \$cmdOp_xcatMNIp, + 'xcatUser=s' => \$cmdOp_xcatUser, + 'zhcpDiskSpace=s' => \$cmdOp_zhcpDiskSpace, + 'zhcpFCPList=s' => \$cmdOp_zhcpFCPList, + 'zhcpNode=s' => \$cmdOp_zhcpNode, + ); + if ( $rc == 0 ) { + print $usage_string; + } + } + + # Apply the command line operands as overrides to the global variables in this script. + applyOverrides(); + + # Special handling for the deobfuscation of the user pw. + if ( defined $glob_xcatUserPw and $glob_xcatUserPw ne '' and $obfuscatePw ) { + # Unobfuscate the password so that we can use it. + $glob_xcatUserPw = decode_base64($val); + } + + # Special processing for ignore messages to convert general severity type + # operands to their numeric value. + if ( $glob_msgsToIgnore{'BYPASS'} ) { + delete $glob_msgsToIgnore{'BYPASS'}; + $glob_msgsToIgnore{'2'} = 1; + } + if ( $glob_msgsToIgnore{'INFO'} ) { + delete $glob_msgsToIgnore{'INFO'}; + $glob_msgsToIgnore{'3'} = 1; + } + if ( $glob_msgsToIgnore{'WARNING'} ) { + delete $glob_msgsToIgnore{'WARNING'}; + $glob_msgsToIgnore{'4'} = 1; + } + if ( $glob_msgsToIgnore{'ERROR'} ) { + delete $glob_msgsToIgnore{'ERROR'}; + $glob_msgsToIgnore{'5'} = 1; + } + +FINISH_setOverrides: + return; +} + + +#------------------------------------------------------- + +=head3 showHelp + + Description : Show the help inforamtion. + Arguments : None. + Returns : None. + Example : showHelp(); + +=cut + +#------------------------------------------------------- +sub showHelp{ + my ($rc, $sev, $extraInfo, @array); + my $msg; + + print "$0 run tests to verify the xCAT installation.\n\n"; + print $usage_string; + print "The following environment variables (indicated by env:) ". + "and command line\noperands (indicated by cmd:) are supported.\n\n"; + foreach my $opHash ( @cmdOps ) { + if ( exists $opHash->{'desc'} ) { + if ( exists $opHash->{'envVar'} ) { + print "env: $opHash->{'envVar'}\n"; + } + if ( exists $opHash->{'opName'} ) { + print "cmd: --$opHash->{'opName'} \n"; + } + if ( exists $opHash->{'separator'} ) { + print "List separator: '$opHash->{'separator'}'\n" + } + if ( exists $opHash->{'default'} ) { + print "Default: $opHash->{'default'}\n"; + } + print wrap( '', '', "Value: $opHash->{'desc'}" ). "\n"; + print "\n"; + } + } + print ( + "Usage notes:\n" . + "1. An input value can be specified in one of three ways, either as: \n" . + " * an environment variable, \n" . + " * an operand on the command line using the -- \n" . + " operand, or \n" . + " * a --moreCmdOps operand. \n" . + " The input value in the -- operand overrides the value \n" . + " specifed by the environment variable. The --moreCmdOps operand \n" . + " overrides both the -- operand and the environment \n" . + " variable. \n" . + "2. The value for an operand that has a list value may have the \n" . + " members of the list separated by one of the indicated \n" . + " 'List separator' operands. The same separator should be used to \n" . + " separator all members of the list. For example, do NOT separate \n" . + " the first and second element by a comma and separate the second . \n" . + " and third element by a semi-colon. \n" . + "3. If blank is an allowed list separator for the operand and is used \n" . + " then the list should be enclosed in quotes or double quotes so that\n" . + " the list is interpretted as a value associated with the operand. \n" . + " You may need to escape the quotes depending on how you are invoking\n" . + " the command. For this reason, it is often better to choose a \n" . + " separator other than blank. \n" + ); + + return; +} + + +#------------------------------------------------------- + +=head3 showPoolInfo + + Description : Show available space for each disk in the pool + Arguments : Disk pool name + Array of disk information for the pool + Returns : None. + Example : showPoolInfo($node, $args); + +=cut + +#------------------------------------------------------- +sub showPoolInfo{ + my ( $diskPool, $diskLines ) = @_; + my $lines; + + $lines = "$diskPool contains the following disks that have space available:"; + foreach my $disk ( @$diskLines ) { + my @diskInfo = split( / /, $disk ); + my $size = convertDiskSize( $diskInfo[2], $diskInfo[4] ); + $lines = $lines . "\nvolid: $diskInfo[1], type: $diskInfo[2], available: $size"; + } + logTest( 'misc', $lines ); +} + + +#------------------------------------------------------- + +=head3 verifyCMAProperties + + Description : Verify key CMA properties are specified + and set the global ROLE property for + user by other functions. + Arguments : None + Returns : 0 - No error + non-zero - Error detected. + Example : $rc = verifyCMAProperties(); + +=cut + +#------------------------------------------------------- +sub verifyCMAProperties{ + logTest( "started", "some key CMA properties"); + + my $out = `cat $glob_versionFileCMA`; + chomp( $out ); + if ( $out ne '' ) { + $glob_versionInfo = "$out"; + # Determine CMA role: Controller or Compute + my $delim = "="; + open( FILE, $glob_applSystemRole ); + while ( ) { + my $line = $_; + if ( $line =~ "^role$delim" or $line =~ "^role $delim" ) { + my @array = split( /$delim/, $line, 2 ); + $array[1] =~ s/^\s+|\s+$//g; # trim both ends of the string + $glob_CMARole = uc( $array[1] ); + } + } + close(FILE); + if ( ' CONTROLLER COMPUTE COMPUTE_MN MN ' !~ / $glob_CMARole / ) { + logTest( "failed", "VCMAP01", $glob_applSystemRole ); + $glob_CMARole = ''; + } + } else { + $glob_versionInfo = "CMO Appliance version unknown"; + logTest( "failed", "VCMAP02", $glob_versionFileCMA ); + } +} + + +#------------------------------------------------------- + +=head3 verifyComputeNodeConnectivity + + Description : Verify the xCAT MN can SSH to the + Compute Node. + Arguments : Node address (IP or hostname) of the + Compute Node. + User underwhich remote exports will be performed. + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : my $rc = verifyComputeNodeConnectivity( $nodeAddress ); + +=cut + +#------------------------------------------------------- +sub verifyComputeNodeConnectivity{ + my ( $nodeAddress, $user ) = @_; + + logTest( 'started', "xCAT MN can ssh to $nodeAddress with user $user." ); + my $out = `ssh -o "NumberOfPasswordPrompts 0" $user\@$nodeAddress pwd`; + my $rc = $? >> 8; + if ( $rc != 0 ) { + logTest( 'failed', "VCNC01", $nodeAddress, $user ); + return 0; # Non-critical error detected + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyDirectorySpace + + Description : Verify disk directory space is sufficient. + Arguments : Array of directories containing: + directory name, + maximum percentage in use, + maximum file size (or empty if we should not check) + Printable node name or ZHCP host name (if remote = 1) + Remote processing flag (1 - use SSH to contact the node) + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : $rc = verifyDirectorySpace( \@dirInfo, $zhcpIP ); + +=cut + +#------------------------------------------------------- +sub verifyDirectorySpace{ + my ( $dirInfoRef, $system, $remote ) = @_; + my @dirInfo = @$dirInfoRef; + my $minAvailableSpace = '100M'; + my $largeFileSize = '30000k'; + my $out; + my $rc; + my @sizes; + + # If system is the ZHCP running on this xCAT MN's system then bypass the test + # because we would have already tested the directories when we ran the tests + # for the xCAT MN. + if ( $system eq $glob_localZHCP ) { + logTest( 'bypassed', "BPVDS01" ); + goto FINISH_verifyDirectorySpace; + } + + foreach my $line ( @dirInfo ) { + chomp( $line ); + $line =~ s/^\s+|\s+$//g; # trim both ends of the string + + my @info = split( ' ', $line ); + if ( ! defined $info[0] or $info[0] eq '' or ! defined $info[1] or $info[1] eq '' ) { + # Empty array item and/or maximum percentage is missing. + next; + } + if ( defined $info[2] and $info[2] ne '' and $info[2] ne '.' ) { + $minAvailableSpace = $info[2]; + } + if ( defined $info[3] and $info[3] ne '' and $info[3] ne '.' ) { + $largeFileSize = $info[3]; + } + + # Special case for old ZHCP servers with a memory backed / directory. + if ( $remote and $info[0] eq '/' ) { + $out = `ssh $system ls /persistent 1>/dev/null 2>/dev/null`; + $rc = $? >> 8; + if ( $rc == 255 ) { + logTest( 'failed', "STN01", $system ); + next; + } elsif ( $rc == 0 ) { + # Validate /persistent directory instead of / + $info[0] = '/persistent'; + } + } + + logTest( 'started', "the file system related to $info[0] on the $system system has sufficient space available." ); + my $sizeTestFailed = 0; + if( $remote ) { + $out = `ssh $system df -h $info[0] | sed '1d' | sed 'N;s/\\n/ /' | awk '{print \$4,\$5}'`; + $rc = $? >> 8; + if ( $rc == 255 ) { + logTest( 'failed', "STN01", $system ); + next; + } + } else { + $out = `df -h $info[0] | sed '1d' | sed 'N;s/\\n/ /' | awk '{print \$4,\$5}'`; + } + chomp( $out ); + if ( $out ) { + @sizes = split( ' ', $out, 2 ); + # Percentage In Use test + $sizes[1] =~ s/\%+$//g; # trim percent from end of the string + if ( $info[1] ne '.' and $sizes[1] > $info[1] ) { + logTest( 'failed', "VDS01", $info[0], $system, $sizes[1], $info[1] ); + $sizeTestFailed = 1; + } + # Minimum Available Size test + if ( $info[2] ne '.' and convertSize( $sizes[0] ) < convertSize( $minAvailableSpace ) ) { + logTest( 'failed', "VDS02", $info[0], $system, $sizes[0], $minAvailableSpace ); + $sizeTestFailed = 1; + } + + if ( $sizeTestFailed == 0 ) { + logTest( 'misc', "The file system related to $info[0] on the $system system is $sizes[1] percent in use with $sizes[0] available." ); + } + } else { + logTest( 'failed', "VDS03", $system, $info[0] ); + $sizeTestFailed = 1; + return 0; + } + + if ( $info[3] ne '.' and $sizeTestFailed == 1 ) { + # Show any large files in the directory space. + logTest( 'started', "the file system related to $info[0] directory on $system system has reasonable size files." ); + if( $remote ) { + $out = `ssh $system find $info[0] -mount -type f -size +$largeFileSize 2>/dev/null -exec ls -lh {} \\; | grep -v -e .so. -e .so -e .jar | awk \'{ print \$9 \": \" \$5 }\'`; + $rc = $? >> 8; + if ( $rc == 255 ) { + logTest( 'failed', "STN01", $system ); + next; + } + } else { + $out = `find $info[0] -mount -type f -size +$largeFileSize 2>/dev/null -exec ls -lh {} \\; | grep -v -e .so. -e .so -e .jar | awk \'{ print \$9 \": \" \$5 }\'`; + } + if ( $out ne '' ) { + $out =~ s/\n+$//g; # remove last newline + logTest( 'failed', "VDS04", $largeFileSize, $out ); + } else { + logTest( 'passed', "" ); + } + } + } + + if ( $system eq 'xCAT MN' and $glob_expectedReposSpace ne '' ) { + if ( convertSize( $sizes[0] ) < convertSize( $glob_expectedReposSpace ) ) { + logTest( 'failed', "VDS05", $sizes[0], $glob_expectedReposSpace ); + } else { + logTest( 'passed', "" ); + } + } + +FINISH_verifyDirectorySpace: + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyDiskPools + + Description : Verify disk pools are defined and have + at least a minimum amount of space. + Arguments : Array of expected disk pools. + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : $rc = verifyDiskPools( $hostNode, $diskpools ); + + lsvm zhcp --diskpoolnames + lsvm zhcp --diskpool pool1 free + lsvm zhcp --diskpool pool1 used + +=cut + +#------------------------------------------------------- +sub verifyDiskPools{ + my ( $hostNode, $diskPools ) = @_; + my $out; + my $zhcpNode; + + if ( exists $glob_hostNodes{$hostNode}{'zhcp'} ) { + $zhcpNode = $glob_hostNodes{$hostNode}{'zhcp'}; + } else { + return 0; + } + + logTest( 'started', "disk pools for host: $hostNode." ); + + $out = `/opt/xcat/bin/lsvm $zhcpNode --diskpoolnames | awk '{print \$NF}'`; + my @definedPools = split /\n/, $out; + + # Warn if no disk pools are defined. + if ( @definedPools == 0 ) { + logTest( 'failed', "VDP03", $hostNode ); + return 0; + } + + logTest( 'misc', "$hostNode has the following disk pools defined: " . join(', ', @$diskPools) . "." ); + + foreach my $diskPool ( @$diskPools ) { + $diskPool = uc( $diskPool ); + + # Verify pool is in the list of pools + if ( grep { $_ eq $diskPool } @definedPools ) { + } else { + logTest( 'failed', "VDP01", $diskPool ); + next; + } + + # Warn if we have very little disk space available + $out = `/opt/xcat/bin/lsvm $zhcpNode --diskpool $diskPool free | grep $zhcpNode | sed '1d'`; + my @disks = split /\n/, $out; + my $numberOfDisks = @disks; + if ( $numberOfDisks == 0 ) { + if (( $diskPool ne 'XCAT' ) and ( $diskPool ne 'XCAT1' )) { + logTest( 'failed', "VDP02", $diskPool ); + } + } else { + showPoolInfo( $diskPool, \@disks ); + } + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyHost + + Description : Verify the Host node is defined properly. + Arguments : Host node + ZHCP node + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : my $rc = verifyHost( $node ); + +=cut + +#------------------------------------------------------- +sub verifyHost{ + my ( $node) = @_; + my %hostInfo = getLsdefNodeInfo( $node ); + + # Verify node is defined + logTest( 'started', "that the host node ($node) is defined in xCAT." ); + my $count = keys %hostInfo; + if ( $count == 0 ) { + logTest( 'failed', "VHN01", $node ); + return 1; # Critical error detected. IVP should exit. + } + + # Verify the 'hcp' is defined for the node + logTest( 'started', "a zHCP is associated with the host node ($node)." ); + if ( $hostInfo{'hcp'} eq '' ) { + logTest( 'failed', "VHN02" ); + return 1; # Critical error detected. IVP should exit. + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyHostNode + + Description : Verify the Host node is defined properly. + Arguments : Host node + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : my $rc = verifyHostNode( $node ); + +=cut + +#------------------------------------------------------- +sub verifyHostNode{ + my ( $node ) = @_; + my %hostInfo = getLsdefNodeInfo( $node ); + + # Verify node is defined + logTest( 'started', "that the host node ($node) is defined in xCAT." ); + my $count = keys %hostInfo; + if ( $count == 0 ) { + logTest( 'failed', "VHN01", $node ); + return 1; # Critical error detected. IVP should exit. + } + + # Verify the 'hcp' is defined for the node + logTest( 'started', "a zHCP is associated with the host node ($node)." ); + if ( $hostInfo{'hcp'} eq '' ) { + logTest( 'failed', "VHN02" ); + return 1; # Critical error detected. IVP should exit. + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyMACUserPrefix + + Description : Verify that the specified MACADDR + user prefix matches the one on the host. + Arguments : Host node + MACADDR user prefix + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : verifyMACUserPrefix( $hostNode, $userPrefix ); + +=cut + +#------------------------------------------------------- +sub verifyMACUserPrefix{ + my ( $hostNode, $userPrefix ) = @_; + $userPrefix = uc( $userPrefix ); + logTest( 'started', "the z/VM system's MACID user prefix matches the one specified in the OpenStack configuration file." ); + + my %nodeInfo = getLsdefNodeInfo($hostNode); + + my $hostUserPrefix = `ssh $nodeInfo{'hcp'} vmcp QUERY VMLAN | sed '1,/VMLAN MAC address assignment:/d' | grep ' MACADDR Prefix:' | awk '{print \$6}'`; + chomp( $hostUserPrefix ); + + if ( $userPrefix ne $hostUserPrefix ) { + logTest( 'failed', "VMUP01", $hostNode, $hostUserPrefix, $userPrefix ); + } else { + logTest( 'passed', "" ); + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyMemorySize + + Description : Verify the virtual machine has + sufficient memory. + Arguments : None + Returns : 0 - No error + non-zero - Error detected. + Example : $rc = verifyMemorySize($node, $args); + +=cut + +#------------------------------------------------------- +sub verifyMemorySize{ + my $vstorMin = '8G'; + my ( $out, $tag, $storSize ); + + # Verify the virtual machine has the recommended virtual storage size. + logTest( 'started', "xCAT MN has a virtual storage size of at least $vstorMin." ); + + $out = `vmcp query virtual storage | grep STORAGE`; + if ( $out eq '' ) { + logTest( 'failed', "VMS01" ); + return 0; + } + + ($tag, $storSize) = split(/=/, $out, 2); + $storSize =~ s/^\s+|\s+$//g; # trim both ends of the string + my $convStorSize = convertSize( $storSize ); + my $convVStorMin = convertSize( $vstorMin ); + + if ( $convStorSize < $convVStorMin ) { + logTest( 'failed', "VMS02", $storSize, $vstorMin ); + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyMiscHostStuff + + Description : Verify miscellaneous items related to + the host. + Arguments : Host node + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : my $rc = verifyMiscHostStuff( $node ); + +=cut + +#------------------------------------------------------- +sub verifyMiscHostStuff{ + my ( $hostNode) = @_; + my $out; + my $rc; + my $zhcpNode; + + if ( exists $glob_hostNodes{$hostNode}{'zhcp'} ) { + $zhcpNode = $glob_hostNodes{$hostNode}{'zhcp'}; + } else { + return 0; + } + + # Verify the signal shutdown time is not too small + logTest( 'started', "the signal shutdown timeout on $hostNode is more than $glob_signalTimeout." ); + my $timeVal; + $out = `ssh $zhcpNode vmcp query signal shutdowntime`; + $rc = $? >> 8; + if ( $rc == 255 ) { + logTest( 'failed', 'STN01', $zhcpNode ); + } elsif ( $out !~ "System default shutdown signal timeout:" ) { + logTest( 'failed', 'VMHS01', $hostNode, $rc, $out ); + } else { + ($timeVal) = $out =~ m/System default shutdown signal timeout: (.*) seconds/; + if ( $timeVal < $glob_signalTimeout ) { + logTest( 'failed', 'VMHS02', $hostNode, $timeVal, $glob_signalTimeout ); + } + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyMnIp + + Description : Verify the xCAT MN Ip is the same one used + by this xCAT MN. + Arguments : xCAT MN IP address or host name + hostName flag, 1 - can be a hostname, 0 - must be an IP address + descriptive name string + subnet mask (optional) + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : my $rc = verifyMnIp( $ip, $possibleHostname, $name, $subnetMask ); + +=cut + +#------------------------------------------------------- +sub verifyMnIp{ + my ( $ip, $possibleHostname, $name, $subnetMask ) = @_; + my ( $out, $rest ); + my $tgtIp = $ip; + my $localRP; + my $addrType = 4; + + # Verify the IP address or hostname is defined for this machine + logTest( 'started', "xCAT MN has an interface for the $name defined as $ip." ); + + if ( $possibleHostname ) { + # Assume the input is a hostname, obtain the IP address associated with that name. + # Look for the name in /etc/hosts + $out = `grep " $ip " < /etc/hosts`; + if ( $out ne '' ) { + ($tgtIp, $rest) = split(/\s/, $out, 2); + } + } + + if ( $tgtIp =~ /:/ ) { + $addrType = 6; + } + + # Verify the IP address is defined + $out=`ip addr show to $tgtIp`; + if ( $out eq '' ) { + logTest( 'failed', "VMNI01", $name, $tgtIp ); + return 0; # Non-critical error detected + } else { + my $inetString; + if ( $addrType == 4 ) { + $inetString = " inet"; + } else { + $inetString = " inet$addrType"; + } + + my @lines= split( /\n/, $out ); + @lines= grep( /$inetString/, @lines ); + if ( @lines == 0 ) { + logTest( 'failed', "VMNI02", $name, $tgtIp ); + return 0; # Non-critical error detected + } + my @ipInfo = split( ' ', $lines[0] ); # split, ignoring leading spaces + my @parts = split( '/', $ipInfo[1] ); + $localRP = $parts[1]; + } + + # Verify the subnet mask matches what is set on the system + if ( defined $subnetMask ) { + logTest( 'started', "xCAT MN's subnet mask is $subnetMask." ); + my $rp = calculateRoutingPrefix( $subnetMask ); + if ( $rp == -1 ) { + logTest( 'failed', "VMNI03", $subnetMask ); + } + elsif ( $rp != $localRP ) { + logTest( 'failed', "VMNI04", $tgtIp, $localRP, $rp, $subnetMask, $name ); + } + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyMnNode + + Description : Verify the xCAT MN node is defined properly. + Arguments : xCAT MN node + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : my $rc = verifyMnNode( $node ); + +=cut + +#------------------------------------------------------- +sub verifyMnNode{ + my ( $node) = @_; + my %mnInfo = getLsdefNodeInfo( $node ); + + # Verify node is defined + logTest( 'started', "xCAT MN node ($node) is defined in xCAT." ); + my $count = keys %mnInfo; + if ( $count == 0 ) { + logTest( 'failed', "VMN01", $node ); + return 0; # Non-critical error detected + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyNodeExists + + Description : Verify that a named node exists in xCAT. + Arguments : Node name + Function of the node (e.g. "zHCP node") + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : verifyNodeExists($node, $function); + +=cut + +#------------------------------------------------------- +sub verifyNodeExists{ + my ( $node, $function ) = @_; + + logTest( 'started', "$function is defined and named $node." ); + my %hash = getLsdefNodeInfo($node); + if ( %hash ) { + logTest( 'passed', "" ); + } else { + logTest( 'failed', "VNE01", $node ); + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyNetworks + + Description : Verify the specified networks are defined + and have the expected VLAN settings. + Arguments : Host node name + Reference to array of networks to be verified + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : my $rc = verifyNetworks($hostNode, $network); + + lsvm zhcp --getnetworknames + lsvm zhcp --getnetwork xcatvsw2 + +=cut + +#------------------------------------------------------- +sub verifyNetworks{ + my ( $hostNode, $networks ) = @_; + my $out; + + my $zhcpNode = $glob_hostNodes{$hostNode}{'zhcp'}; + + foreach my $network ( @$networks ) { + $network = uc( $network ); + + # Split off any VLAN information from the input + my $match; + my @vlans = split( /:/, $network ); + if ( exists $vlans[1] ) { + $network = $vlans[0]; # Remove vlan info from the $network variable + $match = "VLAN Aware"; + } else { + $match = "VLAN Unaware"; + } + logTest( 'started', "$network is defined as a network to $hostNode." ); + + # Obtain the network info + my %switchInfo = getVswitchInfo( $zhcpNode, $network ); + if ( !%switchInfo ) { + logTest( 'failed', "VN01", $network ); + next; # Non-critical error detected, iterate to the next switch + } + + # Verify that the defined network matches the expectations. + logTest( 'started', "$network is $match" ); + if (( $match eq "VLAN Aware" && $switchInfo{'Base'}{'VLAN ID'} != 0 ) || + ( $match eq "VLAN Unaware" && $switchInfo{'Base'}{'VLAN ID'} == 0 )) { + logTest( 'passed', "" ); + } else { + logTest( 'failed', "VN02", $network, $match ); + } + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyProfile + + Description : Verify profile is defined in the z/VM directory. + Arguments : Host node name + Profile to be verified + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : $rc = verifyProfile($hostNode, $profile); + +=cut + +#------------------------------------------------------- +sub verifyProfile{ + my ( $hostNode, $profile ) = @_; + $profile = uc( $profile ); + + logTest( 'started', "$hostNode has the profile ($profile) in the z/VM directory." ); + my $zhcpNode = $glob_hostNodes{$hostNode}{'zhcp'}; + + my $out = `/opt/xcat/bin/chhypervisor $hostNode --smcli 'Image_Query_DM -T $profile'`; + if ( $out !~ "PROFILE $profile" ) { + logTest( 'failed', "VP01", $profile ); + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyREST + + Description : Verify the REST interface is running. + Arguments : None + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : my $rc = verifyREST(); + +=cut + +#------------------------------------------------------- +sub verifyREST{ + logTest( 'started', "REST API is accepting requests from user $glob_xcatUser." ); + my @restOps = (); + my $response = driveREST( $glob_xcatMNIp, $glob_xcatUser, $glob_xcatUserPw, "nodes/$glob_mnNode", "GET", "json", \@restOps ); + #print "Content: " . $response->content . "\n"; + #print "Code: " . $response->code . "\n"; + #print "Message: " .$response->message . "\n"; + + if ( $response->message ne "OK" or $response->code != 200 ) { + logTest( 'failed', "VR01", $response->code, $response->message, $response->content ); + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyUser + + Description : Verify a user is authorized for xCAT MN. + Arguments : User + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : $rc = verifyUser( $user ); + +=cut + +#------------------------------------------------------- +sub verifyUser{ + my ( $user ) = @_; + my $out; + + logTest( 'started', "user ($user) is in the xCAT policy table." ); + $out = `/opt/xcat/bin/gettab name=\'$user\' policy.rule`; + $out =~ s/^\s+|\s+$//g; # trim both ends of the string + if ( $out eq '' ) { + logTest( 'failed', "VU01", $user ); + } elsif ( $out ne 'allow' and $out ne 'accept' ) { + logTest( 'failed', "VU02", $user, $out ); + } else { + logTest( 'passed', "The test is successful. The user ($user) is in the policy table with the rule: \'$out\'." ); + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyVswitchOSAs + + Description : Verify the specified vswitches OSA exist. + Arguments : Hash of Vswitches and their OSAs + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : my $rc = verifyVswitchOSAs( \%vswitchOSAs ); + +=cut + +#------------------------------------------------------- +sub verifyVswitchOSAs{ + my ( $hostNode, $vswitchOSAs ) = @_; + my $out; + + logTest( 'started', "vswitches with related OSAs are valid." ); + + my $zhcpNode = $glob_hostNodes{$hostNode}{'zhcp'}; + + # For each vswitch, verify that it has the specified OSA associated + # with it and it is active or a backup. + foreach my $switch ( keys %$vswitchOSAs ) { + my %switchInfo = getVswitchInfoExtended( $zhcpNode, uc( $switch ) ); + if ( !%switchInfo ) { + logTest( 'failed', "VVO01", $switch ); + next; # Non-critical error detected, iterate to the next switch + } + + my @devices = split( ',', $$vswitchOSAs{$switch} ); + foreach my $device ( @devices ) { + $device = uc( $device ); + + my @osa = split( /\./, $device ); + + # Verify the RDEV + $device = substr( "000$osa[0]", -4 ); # pad with zeroes + if ( $switchInfo{'Real device'}{'RDEVs'} !~ $device ) { + logTest( 'failed', "VVO02", $switch, $device ); + } + } + } + + return 0; +} + + +#------------------------------------------------------- + +=head3 verifyZHCPNode + + Description : Verify the xCAT zHCP node is defined properly. + Arguments : Host node + Returns : 0 - OK, or only a non-critical error detected + non-zero - Critical error detected, IVP should exit. + Example : my $rc = verifyZHCPNode( $node ); + +=cut + +#------------------------------------------------------- +sub verifyZHCPNode{ + my ( $hostNode ) = @_; + my $out; + my $rc; + + logTest( 'started', "that a zHCP node is associated with the host: $hostNode." ); + my $zhcpNode = findZhcpNode( $hostNode ); + if ( ! defined $zhcpNode ) { + logTest( "failed", "VZN05", $hostNode ); + return 1; # Critical error detected. IVP should exit. + } + my %zhcpNodeInfo = getLsdefNodeInfo( $zhcpNode ); + + # Check if this ZHCP node is on the same system as the xCAT MN + if ( exists $zhcpNodeInfo{'ip'} and exists $glob_localIPs{$zhcpNodeInfo{'ip'}} ) { + $glob_localZHCP = $zhcpNode; + } + + # Verify that we can ping zHCP + logTest( 'started', "zHCP node ($zhcpNode) is running." ); + $out = `/opt/xcat/bin/pping $zhcpNode`; + if ( $out !~ "$zhcpNode: ping" ) { + logTest( 'failed', "VZN01", $zhcpNode ); + return 1; # Critical error detected. IVP should exit. + } + + # Obtain and zHCP version information. + $out = `ssh $zhcpNode "[ -e \"/opt/zhcp/version\" ] \&\& cat \"/opt/zhcp/version\""`; + $rc = $? >> 8; + if ( $rc == 255) { + logTest( 'failed', "STN01", $zhcpNode ); + return 1; # Critical error detected. IVP should exit. + } + if ( $out ne '' ) { + chomp( $out ); + $glob_versionInfo = "$glob_versionInfo\nOn $zhcpNode node: $out"; + } else { + $glob_versionInfo = "$glob_versionInfo\nOn $zhcpNode node: ZHCP version level is unknown."; + } + + # Drive a simple rpower request to zHCP which talks to CP + logTest( 'started', "zHCP ($zhcpNode) can handle a simple request to talk to CP." ); + $out = `/opt/xcat/bin/rpower $zhcpNode stat | grep '$zhcpNode:'`; + if ( $out !~ "$zhcpNode: on" ) { + logTest( 'failed', "VZN02", $zhcpNode ); + return 1; # Critical error detected. IVP should exit. + } + + # Drive a simple SMAPI request thru zHCP + logTest( 'started', "zHCP ($zhcpNode) can handle a simple request to SMAPI." ); + $out = `ssh $zhcpNode /opt/zhcp/bin/smcli Query_API_Functional_Level -T dummy 2>&1`; + $rc = $? >> 8; + if ( $rc == 255) { + logTest( 'failed', "STN01", $zhcpNode ); + return 1; # Critical error detected. IVP should exit. + } + if ( $out !~ "The API functional level is" ) { + chomp( $out ); + logTest( 'failed', "VZN04", $zhcpNode, $out ); + return 1; # Critical error detected. IVP should exit. + } + + # Yea, We can talk to SMAPI. Remember that we can use this ZHCP for other tests. + $glob_hostNodes{$hostNode}{'zhcp'} = $zhcpNode; + + # Drive a more complex request to zHCP, an LSVM command + logTest( 'started', "zHCP ($zhcpNode) can handle a more complex xCAT LSVM request." ); + $out = `/opt/xcat/bin/lsvm $zhcpNode | grep '$zhcpNode:'`; + $rc = $? >> 8; + if ( $rc == 255) { + logTest( 'failed', "STN01", $zhcpNode ); + return 1; # Critical error detected. IVP should exit. + } + my $zhcpUserid = uc( $zhcpNodeInfo{'userid'} ); + if ( $out !~ "USER $zhcpUserid" and $out !~ "IDENTITY $zhcpUserid" ) { + logTest( 'failed', "VZN03", $zhcpNode, $zhcpUserid ); + return 1; # Critical error detected. IVP should exit. + } + + return 0; +} + + + +#***************************************************************************** +# Main IVP routine +#***************************************************************************** + +my $rc; +my $out; +my $userid; +my $terminatingError = 0; + +# Update global variables based on overrides from an external perl script. +setOverrides(); + +# Handle help function. +if ( $glob_displayHelp == 1 ) { + showHelp(); + goto FINISH; +} + +# Establish SYSLOG logging for errors if function is desired. +if ( $glob_syslogErrors == 1 ) { + my $user = $ENV{ 'USER' }; + setlogsock( 'unix' ); + openlog( 'xcatIVP', '', 'user'); + syslog( 'info', "Began xcatIVP test" ); +} + +# Detect CMA and obtain the CMA's version information +if ( -e $glob_versionFileCMA ) { + $glob_CMA = 1; + verifyCMAProperties(); +} else { + $glob_CMA = 0; +} + +%glob_localIPs = getLocalIPs(); + +# Obtain the xCAT MN's version information +my $xcatVersion; +if ( -e $glob_versionFileXCAT ) { + $out = `cat $glob_versionFileXCAT`; + chomp( $out ); + $xcatVersion = "$out"; +} else { + $xcatVersion = "xCAT version: unknown"; +} +if ( $glob_versionInfo eq '' ) { + $glob_versionInfo = $xcatVersion; +} else { + $glob_versionInfo = "$glob_versionInfo\n$xcatVersion"; +} + +# Verify the memory size. +if ( $glob_CMA == 1 ) { + verifyMemorySize(); +} + +# Verify xCAT MN's IP address +if ( defined $glob_xcatMNIp) { + verifyMnIp( $glob_xcatMNIp, 1, "xCAT server address" ); +} + +# Verify xCAT MN mgt network IP address +if ( defined $glob_xcatMgtIp) { + verifyMnIp( $glob_xcatMgtIp, 0, "Mgt network IP address", $glob_mgtNetmask ); +} + +# Verify the management node is properly defined in xCAT +if ( defined $glob_mnNode ) { + verifyMnNode( $glob_mnNode ); +} else { + logTest( 'bypassed', "BPVMN01" ); +} + +# Create the list of host node information. +if ( defined $glob_hostNode ) { + $glob_hostNodes{$glob_hostNode}{'input'} = 1; +} else { + my @hostNodes = getHostNodeNames(); + foreach my $hostNode (@hostNodes) { + $glob_hostNodes{$hostNode}{'input'} = 0; + } + if ( keys %glob_hostNodes ) { + $glob_hostNode = split( ' ', keys( %glob_hostNodes ), 1 ); + } +} + +# Verify the host node is properly defined in xCAT and has a ZHCP agent. +foreach my $hostNode ( keys %glob_hostNodes ) {; + $terminatingError = verifyHostNode( $hostNode ); + if ( $terminatingError and scalar keys( %glob_hostNodes ) == 1 ) { + goto FINISH; + } + $terminatingError = 0; + + # Verify the zHCP node is properly defined in xCAT + $terminatingError = verifyZHCPNode( $hostNode ); + if ( $terminatingError and keys( %glob_hostNodes ) == 1 ) { + goto FINISH; + } + $terminatingError = 0; +} + +# Verify the zHCP node specified as input is accessible. +if ( defined $glob_zhcpNode ) { + # Verify the zHCP node is properly defined in xCAT + verifyNodeExists( $glob_zhcpNode, "zHCP node" ); +} + +# Verify the disk pools used to create virtual machines exist +# in the Directory Manager. +if ( @glob_diskpools ) { + verifyDiskPools( $glob_hostNode, \@glob_diskpools ); +} else { + logTest( 'bypassed', "BPVDP01" ); + foreach my $hostNode ( keys %glob_hostNodes ) { + my @pools = getDiskPoolNames( $hostNode ); + verifyDiskPools( $hostNode, \@pools ); + } +} + +# Verify the networks used by deployed virtual machines exist. +if ( @glob_networks ) { + verifyNetworks( $glob_hostNode, \@glob_networks ); +} else { + logTest( 'bypassed', "BPVN01" ); +} + +# Verify the MACADDR user prefix matches the one on the host. +if ( defined $glob_macPrefix ) { + verifyMACUserPrefix( $glob_hostNode, $glob_macPrefix ); +} + +# Verify vswitches with related OSAs are valid. +if ( %glob_vswitchOSAs ) { + verifyVswitchOSAs( $glob_hostNode, \%glob_vswitchOSAs ); +} + +# Verify file system space on the xCAT MN. +verifyDirectorySpace( \@glob_xcatDiskSpace, 'xCAT MN', 0 ); + +# Verify file system space on the zhcp server for each host. +foreach my $hostNode ( keys %glob_hostNodes ) { + verifyDirectorySpace( \@glob_zhcpDiskSpace, $glob_hostNodes{$hostNode}{'zhcp'}, 1 ); +} + +# Verify Host related items for each host in the hostNodes hash. +foreach my $hostNode ( keys %glob_hostNodes ) { + # Verify default user profile is defined to the Directory Manager. + if ( defined $glob_defaultUserProfile ) { + verifyProfile( $hostNode, $glob_defaultUserProfile ); + } + # Verify the signal shutdown interval is appropriate. + if ( $glob_signalTimeout != 0 ) { + verifyMiscHostStuff( $hostNode ); + } +} + +# Verify the xCAT user is defined in the xCAT policy table. +if ( defined $glob_xcatUser ) { + verifyUser( $glob_xcatUser ); +} + +# Verify the REST Interface is responsive. +if ( defined $glob_xcatUser and defined $glob_xcatUserPw and defined $glob_xcatMNIp and defined $glob_mnNode ) { + verifyREST(); +} + +# Verify that xCAT MN can access the compute node. +if ( defined $glob_cNAddress and defined $glob_expUser ) { + verifyComputeNodeConnectivity( $glob_cNAddress, $glob_expUser ); +} else { + logTest( "bypassed", "BPVCNC01" ); +} + +FINISH: +if ( $terminatingError ) { + logTest( "warning", "MAIN01" ); +} + +logTest( "misc", "" ); + +if ( $glob_versionInfo ) { + logTest( "miscNF", "The following versions of code were detected:\n" . $glob_versionInfo ); + logTest( "misc", "" ); +} + +if ( scalar(@glob_failedTests) != 0 ) { + logTest( "misc", "The following tests generated warning(s): " . join(", ", @glob_failedTests) . '.' ); +} +if ( $glob_displayHelp != 1 ) { + logTest( "misc", "$glob_testNum IVP tests ran, " . $glob_totalFailed . " tests generated warnings." ); +} + +if ( $glob_ignoreCnt != 0 ){ + logTest( "misc", "Ignored messages $glob_ignoreCnt times." ); + my @ignoreArray = sort keys %glob_ignored; + my $ignoreList = join ( ', ', @ignoreArray ); + logTest( "misc", "Message Ids of ignored messages: $ignoreList" ); +} + +# Close out our use of syslog +if ( $glob_syslogErrors == 1 ) { + syslog( 'info', "Ended zxcatIVP test" ); + closelog(); +} + +exit 0; diff --git a/xCAT-client/bin/zxcatexport.pl b/xCAT-client/bin/zxcatexport.pl new file mode 100644 index 000000000..1907aa313 --- /dev/null +++ b/xCAT-client/bin/zxcatexport.pl @@ -0,0 +1,333 @@ +#!/usr/bin/perl +############################################################################### +# IBM (C) Copyright 2015, 2016 Eclipse Public License +# http://www.eclipse.org/org/documents/epl-v10.html +############################################################################### +# COMPONENT: zxcatExport +# +# This is a program to save the xCAT tables to the /install/xcatmigrate directory; +# then close and export the /install LVM +# +# The reverse process on the other system can be done if the LVM disks are +# writeable and online. The zxcatmigrate script can be used for that. +# It will issue pvscan, vgimport, vgchange -ay, mkdir, then mount commands. +# +############################################################################### + +use strict; +use warnings; +use Capture::Tiny ':all'; +use Getopt::Long; +use lib '/opt/xcat/lib/perl/'; +use xCAT::TableUtils; +use xCAT::zvmUtils; +$| = 1; # turn off STDOUT buffering + +my $lvmPath = "/dev/xcat/repo"; +my $mountPoint = "/install"; +my $exportDir = "/install/xcatmigrate"; +my $exportTablesDir = "/install/xcatmigrate/xcattables"; +my $exportFcpConfigsDir = "/install/xcatmigrate/fcpconfigs"; +my $exportFcpOtherFilesDir = "/install/xcatmigrate/fcpotherfiles"; +my $exportDocloneFilesDir = "/install/xcatmigrate/doclone"; +my $lvmInfoFile = "lvminformation"; +my $lsdasdInfoFile = "lsdasdinformation"; +my $zvmVirtualDasdInfoFile = "zvmvirtualdasdinformation"; +my $vgName = "xcat"; + +# xCAT table information to be filled in +my $masterIP; +my $xcatNode; +my $hcp; +my $zhcpNode; + +my $version = "1.1"; +my $targetIP = ""; # IP address to get data from +my $skipInstallFiles = 0; # Skip copying any install files +my $skipTables = 0; # Skip copying and installing xcat tables +my $displayHelp = 0; # Display help information +my $versionOpt = 0; # Show version information flag + +my @entries; +my @propNames; +my $propVals; + +my $usage_string = "This script saves the xcat tables in /install/xcatmigrate and\n +then exports the LVM mounted at /install. This should only be used to migrate\n +the /install LVM to a new userid.\n\n + Usage:\n + $0 [ -v ]\n + $0 [ -h | --help ]\n + The following options are supported:\n + -h | --help Display help information\n + -v Display the version of this script.\n"; + + +#------------------------------------------------------- + +=head3 chompall + + Description : Issue chomp on all three input parms (pass by reference) + Arguments : arg1, arg2, arg3 + Returns : nothing + Example : chompall(\$out, \$err, \$returnvalue); + +=cut + +#------------------------------------------------------- +sub chompall{ + my ( $arg1, $arg2, $arg3 ) = @_; + chomp($$arg1); + chomp($$arg2); + chomp($$arg3); +} + +# *********************************************************** +# Mainline. Parse any arguments, usually no arguments +$Getopt::Long::ignorecase = 0; +Getopt::Long::Configure( "bundling" ); + +GetOptions( + 'h|help' => \$displayHelp, + 'v' => \$versionOpt ); + +if ( $versionOpt ) { + print "Version: $version\n"; + exit; +} + +if ( $displayHelp ) { + print $usage_string; + exit; +} + +my $out = ''; +my $err = ''; +my $returnvalue = 0; + +# This looks in the passwd table for a key = sudoer +($::SUDOER, $::SUDO) = xCAT::zvmUtils->getSudoer(); + +# Scan the xCAT tables to get the zhcp node name +# Print out a message and stop if any errors found +@entries = xCAT::TableUtils->get_site_attribute("master"); +$masterIP = $entries[0]; +if ( !$masterIP ) { + print "xCAT site table is missing a master with ip address\n"; + exit; +} + +# Get xcat node name from 'hosts' table using IP as key +@propNames = ( 'node'); +$propVals = xCAT::zvmUtils->getTabPropsByKey('hosts', 'ip', $masterIP, @propNames); +$xcatNode = $propVals->{'node'}; +if ( !$xcatNode ) { + print "xCAT hosts table is missing a node with ip address of $masterIP\n"; + exit; +} + +# Get hcp for xcat from the zvm table using xcat node name +@propNames = ( 'hcp'); +$propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $xcatNode, @propNames ); +$hcp = $propVals->{'hcp'}; +if ( !$hcp ) { + print "xCAT zvm table is missing hcp value for $xcatNode\n"; + exit; +} + +# Get zhcp node name from 'hosts' table using hostname as key +@propNames = ( 'node'); +$propVals = xCAT::zvmUtils->getTabPropsByKey('hosts', 'hostnames', $hcp, @propNames); +$zhcpNode = $propVals->{'node'}; +if ( !$zhcpNode ) { + print "xCAT hosts table is missing a zhcp node with hostname of $hcp\n"; + exit; +} + +#Create the migrate directory and the xcat tables directory. This should not get error even if it exists +print "Creating directory $exportDir\n"; +( $out, $err, $returnvalue ) = eval { capture { system( "mkdir -p -m 0755 $exportDir"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to create $exportDir:\n"; + print "$err\n"; + exit; +} + +print "Creating directory $exportTablesDir\n"; +( $out, $err, $returnvalue ) = eval { capture { system( "mkdir -p -m 0755 $exportTablesDir"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to create $exportTablesDir:\n"; + print "$err\n"; + exit; +} + +print "Creating directory $exportFcpConfigsDir\n"; +( $out, $err, $returnvalue ) = eval { capture { system( "mkdir -p -m 0755 $exportFcpConfigsDir"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to create $exportFcpConfigsDir:\n"; + print "$err\n"; + exit; +} + +print "Creating directory $exportFcpOtherFilesDir\n"; +( $out, $err, $returnvalue ) = eval { capture { system( "mkdir -p -m 0755 $exportFcpOtherFilesDir"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to create $exportFcpOtherFilesDir:\n"; + print "$err\n"; + exit; +} + +print "Creating directory $exportDocloneFilesDir\n"; +( $out, $err, $returnvalue ) = eval { capture { system( "mkdir -p -m 0755 $exportDocloneFilesDir"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to create $exportDocloneFilesDir:\n"; + print "$err\n"; + exit; +} + +#Save the current LVM information +print "Saving current LVM information at $exportDir/$lvmInfoFile \n"; +( $out, $err, $returnvalue ) = eval { capture { system( "vgdisplay '-v' 2>&1 > $exportDir/$lvmInfoFile"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to display LVM information:\n"; + print "$err\n"; + exit; +} + +#Save the current Linux DASD list information +print "Saving current Linux DASD list information at $exportDir/$lsdasdInfoFile \n"; +( $out, $err, $returnvalue ) = eval { capture { system( "lsdasd 2>&1 > $exportDir/$lsdasdInfoFile"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to display Linux DASD list information:\n"; + print "$err\n"; + exit; +} + +#Save the current zVM virtual DASD list information +print "Saving current zVM virtual DASD list information at $exportDir/$zvmVirtualDasdInfoFile \n"; +( $out, $err, $returnvalue ) = eval { capture { system( "vmcp q v dasd 2>&1 > $exportDir/$zvmVirtualDasdInfoFile"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to display zVM virtual DASD list information:\n"; + print "$err\n"; + exit; +} + +#save the xcat tables +print "Dumping xCAT tables to $exportTablesDir\n"; +( $out, $err, $returnvalue ) = eval { capture { system( ". /etc/profile.d/xcat.sh; /opt/xcat/sbin/dumpxCATdb -p $exportTablesDir"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to dump the xcat tables to $exportTablesDir:\n"; + print "$err\n"; + exit; +} + +#Check for and save any zhcp FCP configuration files +print "Checking zhcp for any FCP configuration files\n"; +( $out, $err, $returnvalue ) = eval { capture { system( "ssh $zhcpNode ls /var/opt/zhcp/zfcp/*.conf"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue == 0) { + # Save any *.conf files + print "Copying /var/opt/zhcp/zfcp/*.conf files to $exportFcpConfigsDir\n"; + ( $out, $err, $returnvalue ) = eval { capture { system( "scp $::SUDOER\@$zhcpNode:/var/opt/zhcp/zfcp/*.conf $exportFcpConfigsDir"); } }; + chompall(\$out, \$err, \$returnvalue); + if ($returnvalue) { + print "Error rv:$returnvalue trying to use scp to copy files from $zhcpNode\n"; + print "$err\n"; + exit; + } +} else { + # If file not found, that is an OK error, if others then display error and exit + if (index($err, "No such file or directory")== -1) { + print "Error rv:$returnvalue trying to use ssh to list files on $zhcpNode\n"; + print "$err\n"; + exit; + } +} +# Check for any other zhcp FCP files +( $out, $err, $returnvalue ) = eval { capture { system( "ssh $zhcpNode ls /opt/zhcp/conf/*"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue == 0) { + # Save any files found + print "Copying /opt/zhcp/conf/*.conf files to $exportFcpOtherFilesDir\n"; + ( $out, $err, $returnvalue ) = eval { capture { system( "scp $::SUDOER\@$zhcpNode:/opt/zhcp/conf/* $exportFcpOtherFilesDir"); } }; + chompall(\$out, \$err, \$returnvalue); + if ($returnvalue) { + print "Error rv:$returnvalue trying to use scp to copy /opt/zhcp/conf/* files from $zhcpNode\n"; + print "$err\n"; + exit; + } +} else { + # If file not found, that is an OK error, if others then display error and exit + if (index($err, "No such file or directory")== -1) { + print "Error rv:$returnvalue trying to use ssh to list files on $zhcpNode\n"; + print "$err\n"; + exit; + } +} + +# Check for any doclone.txt file +( $out, $err, $returnvalue ) = eval { capture { system( "ls /var/opt/xcat/doclone.txt"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue == 0) { + # Save any file found + print "Copying /var/opt/xcat/doclone.txt file to $exportDocloneFilesDir\n"; + ( $out, $err, $returnvalue ) = eval { capture { system( "cp /var/opt/xcat/doclone.txt $exportDocloneFilesDir"); } }; + chompall(\$out, \$err, \$returnvalue); + if ($returnvalue) { + print "Error rv:$returnvalue trying to copy /var/opt/xcat/doclone.txt file\n"; + print "$err\n"; + exit; + } +} else { + # If file not found, that is an OK error, if others then display error and exit + if (index($err, "No such file or directory")== -1) { + print "Error rv:$returnvalue trying to copy /var/opt/xcat/doclone.txt file\n"; + print "$err\n"; + exit; + } +} + +#unmount the /install +print "Unmounting $lvmPath\n"; +( $out, $err, $returnvalue ) = eval { capture { system( "umount $lvmPath"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to umount $lvmPath:\n"; + print "$err\n"; + exit; +} + +#mark the lvm inactive +print "Making the LVM $vgName inactive\n"; +( $out, $err, $returnvalue ) = eval { capture { system( "vgchange '-an' $vgName"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to inactivate volume group $vgName:\n"; + print "$err\n"; + exit; +} + +#export the volume group +print "Exporting the volume group $vgName\n"; +( $out, $err, $returnvalue ) = eval { capture { system( "vgexport $vgName"); } }; +chompall(\$out, \$err, \$returnvalue); +if ($returnvalue) { + print "Error rv:$returnvalue trying to export volume group $vgName:\n"; + print "$err\n"; + exit; +} + +print "\nVolume group $vgName is exported, you can now signal shutdown xcat and\n"; +print "have the xcat lvm disks linked RW in the new appliance."; +exit 0; + + diff --git a/xCAT-client/bin/zxcatimport.pl b/xCAT-client/bin/zxcatimport.pl new file mode 100644 index 000000000..3bfc619fb --- /dev/null +++ b/xCAT-client/bin/zxcatimport.pl @@ -0,0 +1,758 @@ +#!/usr/bin/perl +############################################################################### +# IBM (C) Copyright 2015, 2016 Eclipse Public License +# http://www.eclipse.org/org/documents/epl-v10.html +############################################################################### +# COMPONENT: zxcatimport +# +# This is a program to copy the xCAT /install files and the xCAT tables from +# an old XCAT userid to the new appliance +# See usage string below for parameters. +# return code = 0 successful; else error. +# +############################################################################### + +use strict; +use warnings; +use Capture::Tiny ':all'; +use Getopt::Long; +use lib '/opt/xcat/lib/perl/'; +use xCAT::TableUtils; +use xCAT::Table; +use xCAT::zvmUtils; +use xCAT::MsgUtils; + +my $lvmPath = "/dev/xcat/repo"; +my $lvmMountPoint = "/install2"; +my $lvmImportDir = "/install2/xcatmigrate"; +my $lvmImportTablesDir = "/install2/xcatmigrate/xcattables"; +my $lvmImportFcpConfigsDir = "/install2/xcatmigrate/fcpconfigs"; +my $lvmImportFcpOtherFilesDir = "/install2/xcatmigrate/fcpotherfiles"; +my $lvmImportDocloneFilesDir = "/install2/xcatmigrate/doclone"; +my $lvmInfoFile = "lvminformation"; +my $lsdasdInfoFile = "lsdasdinformation"; +my $zvmVirtualDasdInfoFile = "zvmvirtualdasdinformation"; +my $vgName = "xcat"; +my $persistentMountPoint = "/persistent2"; +my @defaultTables = ("hosts", "hypervisor", "linuximage", "mac", "networks", "nodelist", + "nodetype", "policy", "zvm"); + +my $version = "1.0"; +my $out; +my $err; +my $returnValue; + +my $copyLvmFiles = 0; # Copy files under old /install to new /install +my $replaceAllXcatTables = 0; # Copy one or all xcat tables +my $addTableData = '*none*'; # Add node data to one table or default tables +my $copyFcpConfigs = 0; # copy old zhcp fcp *.conf files +my $copyDoclone = 0; # copy old doclone.txt file +my $replaceSshKeys = 0; # replace SSH keys with old xCAT SSH keys +my $displayHelp = 0; # Display help information +my $versionOpt = 0; # Show version information flag +my $rc = 0; + +my $usage_string = "This script will mount or copy the old xcat lvm and old persistent disk\n +to this appliance. The old xCAT LVM volumes and the persistent disk on XCAT userid must \n +be linked in write mode by this appliance. The LVM will be mounted at '/install2' and \n +the persistent disk will be mounted at '/persistent2'.\n +\n +The default is to just mount the persistent and LVM disks.\n +They will be mounted as /install2 and /persistent2\n\n + + Usage:\n + $0 [--addtabledata [tablename]] [--installfiles ] [--doclonefile]\n + [--fcppoolconfigs] [--replacealltables] [--replaceSSHkeys] \n + $0 [ -v ]\n + $0 [ -h | --help ]\n + The following options are supported:\n + --addtabledata [tablename] | ['tablename1 tablename2 ..']\n + Add old xCAT data to specific table(s) or\n + default to the following xCAT tables:\n + hosts, hypervisor, linuximage, mac, networks, nodelist,\n + nodetype, policy, zvm/n + --installfiles Copy any files from old /install to appliance /install\n + --doclonefile Copy any doclone.txt to appliance\n + --fcppoolconfigs Copy any zhcp FCP pool configuration files\n + --replacealltables Replace all xCAT tables with old xCAT tables\n + --replaceSSHkeys Replaces the current xCAT SSH keys with the old xCAT SSH keys\n + -h | --help Display help information\n + -v Display the version of this script.\n"; + +#------------------------------------------------------- + +=head3 chompall + + Description : Issue chomp on all three input parms (pass by reference) + Arguments : arg1, arg2, arg3 + Returns : nothing + Example : chompall(\$out, \$err, \$returnValue); + +=cut + +#------------------------------------------------------- +sub chompall{ + my ( $arg1, $arg2, $arg3 ) = @_; + chomp($$arg1); + chomp($$arg2); + chomp($$arg3); +} + +# =======unit test/debugging routine ========== +# print the return data from tiny capture return +# data for: out, err, return value +sub printreturndata{ + my ( $arg1, $arg2, $arg3 ) = @_; + print "=============================\n"; + print "Return value ($$arg3)\n"; + print "out ($$arg1)\n"; + print "err ($$arg2)\n\n"; +} + +## ---------------------------------------------- ## +## Subroutine to find device name from address + +sub get_disk($) +{ + my ($id_user) = @_; + my $id = hex $id_user; + my $hex_id = sprintf '%x', $id; + my $dev_path = sprintf '/sys/bus/ccw/drivers/dasd-eckd/0.0.%04x', $id; + unless (-d $dev_path) { + $dev_path = sprintf '/sys/bus/ccw/drivers/dasd-fba/0.0.%04x', $id; + } + -d $dev_path or return undef; + my $dev_block = "$dev_path/block"; + unless (-d $dev_block) { + # Try bringing the device online + for (1..5) { + system("echo 1 > $dev_path/online"); + last if -d $dev_block; + sleep(10); + } + } + opendir(my $dir, $dev_block) or return undef; + my $dev; + while ($dev = readdir $dir) { + last unless $dev eq '.' || $dev eq '..'; + } + closedir $dir; + defined $dev ? "/dev/$dev" : undef; +} + +#------------------------------------------------------- + +=head3 mountOldLVM + + Description : This routine will import the old LVM and mount + it at /install2 + Arguments : none + Returns : 0 - LVM mounted or already mounted + non-zero - Error detected. + Example : $rc = mountOldLVM; + +=cut + +#------------------------------------------------------- +sub mountOldLVM{ + + my $saveMsg; + my $saveErr; + my $saveReturnValue; + + #Check for /install2 If already mounted should get a return value(8192) and $err output + #Check $err for "is already mounted on", if found we are done. + print "Checking for $lvmMountPoint.\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "mount $lvmMountPoint"); } }; + chompall(\$out, \$err, \$returnValue); + if (index($err, "already mounted on $lvmMountPoint") > -1) { + print "Old xCAT LVM is already mounted at $lvmMountPoint\n"; + return 0; + } + + print "Importing $vgName\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "/sbin/vgimport $vgName"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + # There could be a case where the LVM has been imported already + # Save this error information and do the next step (vgchange) + $saveMsg = "Error rv:$returnValue trying to vgimport $vgName"; + $saveErr = "$err"; + $saveReturnValue = $returnValue; + } + + print "Activating LVM $vgName\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "/sbin/vgchange -a y $vgName"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + # If the import failed previously, put out that message instead. + if (!defined $saveMsg) { + print "$saveMsg\n"; + print "$saveErr\n"; + return $saveReturnValue; + } else { + print "Error rv:$returnValue trying to vgchange -a y $vgName\n"; + print "$err\n"; + retun $returnValue; + } + } + + print "Making $lvmMountPoint directory\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "mkdir -p $lvmMountPoint"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to mkdir -p $lvmMountPoint\n"; + print "$err\n"; + return $returnValue; + } + + print "Mounting LVM $lvmPath at $lvmMountPoint\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "mount -t ext3 $lvmPath $lvmMountPoint"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to mkdir -p $lvmMountPoint\n"; + print "$err\n"; + return $returnValue; + } + + print "Old xCAT LVM is now mounted at $lvmMountPoint\n"; + return 0; +} + +#------------------------------------------------------- + +=head3 mountOldPersistent + + Description : This routine will look for the old persistent disk and mount + it at /persistent2 + Arguments : none + Returns : 0 - /persistent2 mounted or already mounted + non-zero - Error detected. + Example : $rc = mountOldPersistent; + +=cut + +#------------------------------------------------------- +sub mountOldPersistent{ + + #Check for /persistent2 If already mounted should get a return value(8192) and $err output + #Check $err for "is already mounted on", if found we are done. + print "Checking for $persistentMountPoint.\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "mount $persistentMountPoint"); } }; + chompall(\$out, \$err, \$returnValue); + if (index($err, "already mounted on $persistentMountPoint") > -1) { + print "The old xCAT /persistent disk already mounted at $persistentMountPoint\n"; + return 0; + } + + # search the exported Linux lsdasd file to get the vdev for vdev 100 (dasda) + # should look like: 0.0.0100 active dasda 94:0 ECKD 4096 2341MB 599400 + my $dasda = `cat "$lvmImportDir/$lsdasdInfoFile" | egrep -i "dasda"`; + if (length($dasda) <= 50) { + print "Unable to find dasda information in $lvmImportDir/$lsdasdInfoFile\n"; + return 1; + } + my @tokens = split(/\s+/, $dasda); + my @vdevparts = split (/\./, $tokens[0]); + my $vdev = $vdevparts[2]; + if (!(length($vdev))) { + print "Unable to find a vdev value for dasda\n"; + return 1; + } + + # search the exported zVM virtual dasd list to get the volume id of the disk + # should look like: DASD 0100 3390 QVCD69 R/W 3330 CYL ON DASD CD69 SUBCHANNEL = 000B + my $voliddata = `cat "$lvmImportDir/$zvmVirtualDasdInfoFile" | egrep -i "DASD $vdev"`; + if (length($voliddata) <= 50) { + print "Unable to find volid information for $vdev in $lvmImportDir/$zvmVirtualDasdInfoFile\n"; + return 1; + } + @tokens = split(/\s+/, $voliddata); + my $volid = $tokens[3]; + if (!(length($volid))) { + print "Unable to find a volume id for vdev $vdev\n"; + return 1; + } + + # Now display the current zVM query v dasd to see if they have the volid listed + # and what vdev it is mounted on + ( $out, $err, $returnValue ) = eval { capture { system( "vmcp q v dasd 2>&1"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to vmcp q v dasd\n"; + print "$err\n"; + return $returnValue; + } + + # get the current VDEV the old volid is now using + # If not they they did not update the directory to link to the old classic disk + ( $out, $err, $returnValue ) = eval { capture { system( "echo \"$out\" | egrep -i $volid"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to echo $out\n"; + print "$err\n"; + return $returnValue; + } + if (!(length($out))) { + print "Unable to find a current vdev value for volume id $volid\n"; + return 1; + } + @tokens = split(/\s+/, $out); + my $currentvdev = $tokens[1]; + if (!(length($currentvdev))) { + print "Unable to find a current vdev value for volume id $volid\n"; + return 1; + } + + # Now get the Linux disk name that is being used for this vdev (/dev/dasdx) + my $devname = get_disk($currentvdev); + #print "Devname found: $devname\n"; + if (!(defined $devname)) { + print "Unable to find a Linux disk for address $currentvdev volume id $volid\n"; + return 1; + } + + # Create the directory for the mount of old persistent disk + ( $out, $err, $returnValue ) = eval { capture { system( "mkdir -p -m 0755 $persistentMountPoint"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to create $persistentMountPoint:\n"; + print "$err\n"; + return $returnValue; + } + + # Mount the old persistent disk, must be partition 1 + my $partition = 1; + ( $out, $err, $returnValue ) = eval { capture { system( "mount -t ext3 $devname$partition $persistentMountPoint"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to mount -t ext3 $devname$partition $persistentMountPoint\n"; + print "$err\n"; + return $returnValue; + } + print "The old xCAT /persistent disk is mounted at $persistentMountPoint\n"; + return 0; +} +# *********************************************************** +# Mainline. Parse any arguments +$Getopt::Long::ignorecase = 0; +Getopt::Long::Configure( "bundling" ); + +GetOptions( + 'installfiles' => \$copyLvmFiles, + 'replacealltables' => \$replaceAllXcatTables, + 'addtabledata:s' => \$addTableData, + 'fcppoolconfigs' => \$copyFcpConfigs, + 'doclonefile' => \$copyDoclone, + 'replaceSSHkeys' => \$replaceSshKeys, + 'h|help' => \$displayHelp, + 'v' => \$versionOpt ); + +if ( $versionOpt ) { + print "Version: $version\n"; + exit 0; +} + +if ( $displayHelp ) { + print $usage_string; + exit 0; +} + +# Use sudo or not +# This looks in the passwd table for a key = sudoer +($::SUDOER, $::SUDO) = xCAT::zvmUtils->getSudoer(); + +$rc = mountOldLVM(); +if ($rc != 0) { + exit 1; +} + +$rc = mountOldPersistent(); +if ($rc != 0) { + exit 1; +} + +# ***************************************************************************** +# **** Copy the LVM files from old xCAT LVM to current LVM +if ( $copyLvmFiles ) { + $rc = chdir("$lvmMountPoint"); + if (!$rc) { + print "Error rv:$rc trying to chdir $lvmMountPoint\n"; + exit 1; + } + + $out = `cp -a * /install 2>&1`; + if ($?) { + print "Error rv:$? trying to copy from $lvmMountPoint to /install. $out\n"; + exit $?; + } + print "Old LVM Files copied from $lvmMountPoint to /install\n" ; +} + +# ***************************************************************************** +# **** Replace all the current xCAT tables with the old xCAT tables +if ( $replaceAllXcatTables ) { + print "Restoring old xCAT tables from $lvmImportTablesDir\n"; + # restorexCATdb - restores the xCAT db tables from the directory -p path + ( $out, $err, $returnValue ) = eval { capture { system( ". /etc/profile.d/xcat.sh; /opt/xcat/sbin/restorexCATdb -p $lvmImportTablesDir"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to restore the xcat tables from $lvmImportTablesDir:\n"; + print "$err\n"; + exit 1; + } + # There is a chance the return value is 0, and the $out says "Restore of Database Complete."; + # Yet some of the tables had failures. That information is in $err + if (length($err)) { + print "Some tables did not restore. Error output:\n$err\n "; + exit 1; + } +} + +# ***************************************************************************** +# **** Copy the zhcp FCP config files +if ($copyFcpConfigs) { + # Check if there are any FCP config files to copy + ( $out, $err, $returnValue ) = eval { capture { system( "ls $lvmImportFcpConfigsDir/*.conf"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue == 0) { + # Save any *.conf files + print "Copying $lvmImportFcpConfigsDir/*.conf files to /var/opt/zhcp/zfcp\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "mkdir -p /var/opt/zhcp/zfcp && cp -R $lvmImportFcpConfigsDir/*.conf /var/opt/zhcp/zfcp/"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to use cp to copy files from $lvmImportFcpConfigsDir\n"; + print "$err\n"; + exit 1; + } + } else { + print "There were not any zhcp FCP *.conf files to copy\n"; + } + # Check if there are any other FCP files to copy + ( $out, $err, $returnValue ) = eval { capture { system( "ls $lvmImportFcpOtherFilesDir/*"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue == 0) { + # Save any files + print "Copying $lvmImportFcpOtherFilesDir/* files to /opt/zhcp/conf\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "mkdir -p /opt/zhcp/conf && cp -R $lvmImportFcpOtherFilesDir/* /opt/zhcp/conf/"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to use cp to copy files from $lvmImportFcpOtherFilesDir\n"; + print "$err\n"; + exit 1; + } + } else { + print "There were not any zhcp files from /opt/zhcp/conf to copy\n"; + } +} + +# ***************************************************************************** +# **** Copy the doclone.txt file if it exists +if ($copyDoclone) { + # Check if there is a doclone.txt to copy + ( $out, $err, $returnValue ) = eval { capture { system( "ls $lvmImportDocloneFilesDir/doclone.txt"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue == 0) { + # Save this file in correct location + print "Copying $lvmImportDocloneFilesDir/doclone.txt file to /var/opt/xcat/doclone.txt\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "cp -R $lvmImportDocloneFilesDir/doclone.txt /var/opt/xcat/"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to use cp to copy doclone.txt file from $lvmImportDocloneFilesDir\n"; + print "$err\n"; + exit 1; + } + } else { + print "There was not any doclone.txt file to copy\n"; + } +} + +# ***************************************************************************** +# **** Add old xCAT table data to a table +my $test = length($addTableData); +# Add old xCAT data to an existing table. Admin may need to delete out duplicates using the GUI +if ((length($addTableData)==0) || $addTableData ne "*none*") { + #defaultTables = ("hosts", "hypervisor", "linuximage", "mac", "networks", "nodelist", + # "nodetype", "policy", "zvm"); + my @tables = @defaultTables; + if (length($addTableData)>1 ) { + # use the table specified + @tables = (); + @tables = split(' ',$addTableData); + } + foreach my $atable (@tables) { + print "Adding data to table $atable\n"; + # the current xCAT code we have does not support the -a option + # use xCAT::Table functions + + my $tabledata = `cat "$lvmImportTablesDir\/$atable\.csv"`; + if (length($tabledata) <= 10) { + print "Unable to find table information for $atable in $lvmImportTablesDir\n"; + return 1; + } + # remove the hash tag from front + $tabledata =~ s/\#//; + my @rows = split('\n', $tabledata); + my @keys; + my @values; + my $tab; + # loop through all the csv rows, first are the header keys, rest is data + foreach my $i (0 .. $#rows) { + my %record; + #print "row $i data($rows[$i])\n"; + if ($i == 0) { + @keys = split(',', $rows[0]); + #print "Keys found:(@keys)\n"; + } else { + # now that we know we have data, lets create table + if (!defined $tab) { + $tab = xCAT::Table->new($atable, -create => 1, -autocommit => 0); + } + # put the data into the new table. + @values = split(',', $rows[$i]); + foreach my $v (0 .. $#values) { + # Strip off any leading and trailing double quotes + $values[$v] =~ s/"(.*?)"\z/$1/s; + $record{$keys[$v]} = $values[$v]; + #print "Row $i matches key $keys[$v] Value found:($values[$v])\n"; + } + } + # write out the row if any keys added to the hash + if (%record) { + my @dbrc = $tab->setAttribs(\%record, \%record); + if (!defined($dbrc[0])) { + print "Error ($dbrc[1]) setting database for table $atable"; + $tab->rollback(); + $tab->close; + exit 1; + } + } + } + # if we made it here and $tab is defined, commit it. + if (defined $tab) { + $tab->commit; + print "Data successfully added and committed to $atable.\n*****! Remember to check the table and remove any rows not needed\n"; + } + }#end for each table +} + +# ***************************************************************************** +# **** Replace the xCAT SSH key with the old xCAT SSH key + +# First copy the current keys and copy the old xCAT keys into unique file names +if ($replaceSshKeys) { + # Make temp file names to hold the current and old ssh public and private key + my $copySshKey= `/bin/mktemp -p /root/.ssh/ id_rsa.pub_XXXXXXXX`; + chomp($copySshKey); + my $copySshPrivateKey= `/bin/mktemp -p /root/.ssh/ id_rsa_XXXXXXXX`; + chomp($copySshPrivateKey); + + # Make temp files for the RSA backup keys in appliance + my $copyHostSshKey= `/bin/mktemp -p /etc/ssh/ ssh_host_rsa_key.pub_XXXXXXXX`; + chomp($copyHostSshKey); + my $copyHostSshPrivateKey= `/bin/mktemp -p /etc/ssh/ ssh_host_rsa_key_XXXXXXXX`; + chomp($copyHostSshPrivateKey); + + # Save old keys in unique names + my $oldSshKey= `/bin/mktemp -p /root/.ssh/ id_rsa.pub_OldMachineXXXXXXXX`; + chomp($oldSshKey); + my $oldSshPrivateKey= `/bin/mktemp -p /root/.ssh/ id_rsa_OldMachineXXXXXXXX`; + chomp($oldSshPrivateKey); + + print "Making backup copies of current xCAT SSH keys\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "cp \-p /root/.ssh/id_rsa.pub $copySshKey"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to use cp to copy /root/.ssh/id_rsa.pub to $copySshKey\n"; + print "$err\n"; + exit 1; + } + ( $out, $err, $returnValue ) = eval { capture { system( "cp \-p /root/.ssh/id_rsa $copySshPrivateKey"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to use cp to copy /root/.ssh/id_rsa to $copySshPrivateKey\n"; + print "$err\n"; + exit 1; + } + + # Save appliance backup keys + ( $out, $err, $returnValue ) = eval { capture { system( "cp \-p /etc/ssh/ssh_host_rsa_key.pub $copyHostSshKey"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to use cp to copy /etc/ssh/ssh_host_rsa_key.pub to $copyHostSshKey\n"; + print "$err\n"; + exit 1; + } + ( $out, $err, $returnValue ) = eval { capture { system( "cp \-p /etc/ssh/ssh_host_rsa_key $copyHostSshPrivateKey"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to use cp to copy /etc/ssh/ssh_host_rsa_key to $copyHostSshPrivateKey\n"; + print "$err\n"; + exit 1; + } + + # Copy the old public key and make sure the permissions are 644 + print "Copying old xCAT SSH keys (renamed) from /persistent2 to /root/.ssh\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "cp /persistent2/root/.ssh/id_rsa.pub $oldSshKey"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to use cp to copy /persistent2/root/.ssh/id_rsa.pub to $oldSshKey\n"; + print "$err\n"; + exit 1; + } + ( $out, $err, $returnValue ) = eval { capture { system( "chmod 644 $oldSshKey"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to chmod 644 $oldSshKey\n"; + print "$err\n"; + exit 1; + } + + # Copy the private key and make sure the permissions are 600 + ( $out, $err, $returnValue ) = eval { capture { system( "cp /persistent2/root/.ssh/id_rsa $oldSshPrivateKey"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to use cp to copy /persistent2/root/.ssh/id_rsa to $oldSshPrivateKey\n"; + print "$err\n"; + exit 1; + } + ( $out, $err, $returnValue ) = eval { capture { system( "chmod 600 $oldSshPrivateKey"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to chmod 600 $oldSshPrivateKey\n"; + print "$err\n"; + exit 1; + } + + # Now compare the IP of xCAT to zHCP . + # If they are the same, then only the private and public key in xCAT needs to be changed. + # If zhcp is on a different machine, then the first thing to be done is add the old xCAT key + # to the zhcp authorized_keys files, then do the switch on xcat of public and private keys + + my $xcatIp; + my $zhcpIp; + my $zhcpHostName; + my $zhcpNode; + my $xcatNodeName; + my @propNames; + my $propVals; + my @entries; + my $rc = 0; + + # Scan the xCAT tables to get the zhcp node name + # Print out a message and stop if any errors found + @entries = xCAT::TableUtils->get_site_attribute("master"); + $xcatIp = $entries[0]; + if ( !$xcatIp ) { + print "xCAT site table is missing a master with ip address\n"; + exit 1; + } + + # Get xcat node name from 'hosts' table using IP as key + @propNames = ( 'node'); + $propVals = xCAT::zvmUtils->getTabPropsByKey('hosts', 'ip', $xcatIp, @propNames); + $xcatNodeName = $propVals->{'node'}; + if ( !$xcatNodeName ) { + print "xCAT hosts table is missing a node with ip address of $xcatIp\n"; + exit 1; + } + + # Get hcp hostname for xcat from the zvm table using xcat node name + @propNames = ( 'hcp'); + $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $xcatNodeName, @propNames ); + $zhcpHostName = $propVals->{'hcp'}; + if ( !$zhcpHostName ) { + print "xCAT zvm table is missing hcp value for $xcatNodeName\n"; + exit 1; + } + + # Get zhcp IP and node from 'hosts' table using hostname as key + @propNames = ( 'ip', 'node'); + $propVals = xCAT::zvmUtils->getTabPropsByKey('hosts', 'hostnames', $zhcpHostName, @propNames); + $zhcpIp = $propVals->{'ip'}; + if ( !$zhcpIp ) { + print "xCAT hosts table is missing a zhcp node IP with hostname of $zhcpHostName\n"; + exit 1; + } + $zhcpNode = $propVals->{'node'}; + if ( !$zhcpNode ) { + print "xCAT hosts table is missing a zhcp node with hostname of $zhcpHostName\n"; + exit 1; + } + + if ($zhcpIp eq $xcatIp) { + print "xCAt and zhcp are on same IP, only need to update public and private keys\n"; + } else { + # Need to append the old SSH key to zhcp authorized_keys file + my $target = "$::SUDOER\@$zhcpHostName"; + print "Copying old SSH key to zhcp\n"; + ( $out, $err, $returnValue ) = eval { capture { system( "scp $oldSshKey $target:$oldSshKey"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to use scp to copy $oldSshKey to zhcp $oldSshKey\n"; + print "$err\n"; + exit 1; + } + # Adding the old SSH key to the authorized_keys file + # Make a copy of the old authorized_users file + my $suffix = '_' . substr($oldSshKey, -8); + ( $out, $err, $returnValue ) = eval { capture { system( "ssh $target cp \"/root/.ssh/authorized_keys /root/.ssh/authorized_keys$suffix\""); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to make a copy of the /root/.ssh/authorized_keys file\n"; + print "$err\n"; + exit 1; + } + # Add the key to zhcp authorized_keys file + ( $out, $err, $returnValue ) = eval { capture { system( "ssh $target cat \"$oldSshKey >> /root/.ssh/authorized_keys\""); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to append zhcp $oldSshKey to /root/.ssh/authorized_keys\n"; + print "$err\n"; + exit 1; + } + } + # We need to replace the xCAT public and private key with the old keys + # and add the old key to the authorized_keys on xCAT + ( $out, $err, $returnValue ) = eval { capture { system( "cat $oldSshKey >> /root/.ssh/authorized_keys"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to append xcat $oldSshKey to /root/.ssh/authorized_keys\n"; + print "$err\n"; + exit 1; + } + ( $out, $err, $returnValue ) = eval { capture { system( "cp \-f $oldSshKey /root/.ssh/id_rsa.pub"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to replace the /root/.ssh/id_rsa.pub with the $oldSshKey\n"; + print "$err\n"; + exit 1; + } + ( $out, $err, $returnValue ) = eval { capture { system( "cp \-f $oldSshPrivateKey /root/.ssh/id_rsa"); } }; + chompall(\$out, \$err, \$returnValue); + #printreturndata(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to replace the /root/.ssh/id_rsa with the $oldSshPrivateKey\n"; + print "$err\n"; + exit 1; + } + # Copy old keys into appliance saved key locations + ( $out, $err, $returnValue ) = eval { capture { system( "cp \-f $oldSshKey /etc/ssh/ssh_host_rsa_key.pub"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to replace the /etc/ssh/ssh_host_rsa_key.pub with the $oldSshKey\n"; + print "$err\n"; + exit 1; + } + ( $out, $err, $returnValue ) = eval { capture { system( "cp \-f $oldSshPrivateKey /etc/ssh/ssh_host_rsa_key"); } }; + chompall(\$out, \$err, \$returnValue); + if ($returnValue) { + print "Error rv:$returnValue trying to replace the /etc/ssh/ssh_host_rsa_key with the $oldSshPrivateKey\n"; + print "$err\n"; + exit 1; + } + + print "Old xCAT SSH keys have replaced current SSH keys. Previous key data saved in unique names.\n"; +} + +exit 0; diff --git a/xCAT-client/openstack.versions b/xCAT-client/openstack.versions new file mode 100644 index 000000000..eedfd2571 --- /dev/null +++ b/xCAT-client/openstack.versions @@ -0,0 +1,9 @@ +# This file maps the OpenStack version numbers to their OpenStack release name. +15. OCATA +14. NEWTON +13. MIKATA +12. LIBERTY +2015. KILO +2014.2. JUNO +2014.1. ICEHOUSE +2013.2. HAVANA diff --git a/xCAT-client/pods/man1/pgsqlsetup.1.pod b/xCAT-client/pods/man1/pgsqlsetup.1.pod index 3115b1bc8..45c736d91 100644 --- a/xCAT-client/pods/man1/pgsqlsetup.1.pod +++ b/xCAT-client/pods/man1/pgsqlsetup.1.pod @@ -52,7 +52,7 @@ This option is used to specify additional IP addresses on which the PostgreSQL d =item B<-a|--access> I
                                                  -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. =item B<-P|--PCM> diff --git a/xCAT-client/pods/man1/rspconfig.1.pod b/xCAT-client/pods/man1/rspconfig.1.pod index 3f88d1152..a61149197 100644 --- a/xCAT-client/pods/man1/rspconfig.1.pod +++ b/xCAT-client/pods/man1/rspconfig.1.pod @@ -24,7 +24,7 @@ B I B=I