diff --git a/data/setupDisk b/data/setupDisk index 71f3562f7..1d1ec4620 100755 --- a/data/setupDisk +++ b/data/setupDisk @@ -1,5 +1,6 @@ #!/bin/bash ############################################################################### +# Copyright 2025 Contributors to the Feilong Project # Copyright 2017 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -28,7 +29,7 @@ function getOsVersion { # None # @Output: # os - Variable set with OS and version information. For example: - # "rhel62" or "sles11sp2" + # "rhel89" or "sles12sp5" # @Code: if [[ -e "/etc/os-release" ]]; then os=`cat /etc/os-release | grep "^ID=" | sed \ @@ -39,34 +40,6 @@ function getOsVersion { -e 's/"//g' \ -e 's/\.//'` os=$os$version - - #The /etc/SuSE-release file will be deprecated in sles11.4 and later release - elif [[ -e "/etc/SuSE-release" ]]; then - os='sles' - version=`cat /etc/SuSE-release | grep "VERSION =" | sed \ - -e 's/^.*VERSION =//' \ - -e 's/\s*$//' \ - -e 's/.//' \ - -e 's/[^0-9]*([0-9]+).*/$1/'` - os=$os$version - - # Append service level - level=`echo "/etc/SuSE-release" | grep "LEVEL =" | sed \ - -e 's/^.*LEVEL =//' \ - -e 's/\s*$//' \ - -e 's/.//' \ - -e 's/[^0-9]*([0-9]+).*/$1/'` - os=$os'sp'$level - - #The /etc/redhat-release file will be deprecated in rhel7 and later release - elif [[ -e "/etc/redhat-release" ]]; then - os='rhel' - version=`cat /etc/redhat-release | grep -i "Red Hat Enterprise Linux Server" | sed \ - -e 's/[A-Za-z\/\.\(\)]//g' \ - -e 's/^ *//g' \ - -e 's/ *$//g' \ - -e 's/\s.*$//'` - os=$os$version fi return } diff --git a/doc/source/makeimage.rst b/doc/source/makeimage.rst index d58be5bb5..90e79c741 100644 --- a/doc/source/makeimage.rst +++ b/doc/source/makeimage.rst @@ -17,16 +17,17 @@ These are the requirements for an image to be captured and deployed by Feilong: 1. The supported Linux distributions are: -- RHEL 6.x - RHEL 7.x -- RHEL 8.1 -- SLES 11.x +- RHEL 8.x +- RHEL 9.x - SLES 12.x -- SELS 15 -- Ubuntu 16.04 +- SLES 15.x +- SLES 16.x - Ubuntu 20.04 +- Ubuntu 22.04 +- Ubuntu 24.04 -Where x is the zLinux's minor release number +where x is the zLinux's minor release number. **Note**: FBA as root disk type is not supported for RHEL 8.1 @@ -79,14 +80,13 @@ Install Linux on z Systems(zLinux) in a Virtual Machine ------------------------------------------------------- 1. Prepare a Linux on z Systems virtual server in the z/VM system. You will - have to make adjustments to the procedures that are documented in the below cook + have to make adjustments to the procedures that are documented in the below cook book in order to keep the resulting virtual server within the bounds of the above image requirements. -- For RHEL6.4 and SLES 11 SP3 installation, see http://www.vm.ibm.com/pubs/redbooks/sg248147/files/24814700.pdf -- For RHEL 7 installation, see http://www.redbooks.ibm.com/abstracts/sg248303.html?Open -- For SLES 12 installation, see http://www.redbooks.ibm.com/abstracts/sg248890.html?Open -- For Ubuntu 16.04 installation, see http://www.redbooks.ibm.com/redbooks/pdfs/sg248354.pdf +- For RHEL 8.2 installation, see http://www.redbooks.ibm.com/abstracts/sg248303.html +- For SLES 12 installation, see http://www.redbooks.ibm.com/abstracts/sg248890.html +- For Ubuntu 16.04 installation, see http://www.redbooks.ibm.com/abstracts/sg248354.html 2. Install the mkisofs and openssl modules on it. @@ -96,7 +96,7 @@ Install Linux on z Systems(zLinux) in a Virtual Machine 4. Set UseDNS no in /etc/ssh/sshd_config file in order to improve the inventory collection efficiency. -5. For Ubuntu 16.04, you must enable root ssh access. By default, root ssh access +5. For Ubuntu, you must enable root ssh access. By default, root ssh access is not enabled. Installation and Configuration of IUCV service in zLinux @@ -132,14 +132,14 @@ steps to install and configure IUCV service. Setting the authorized client userid to be: OPNCLOUD IUCV server daemon is configured and started successfully - you may get the detail usage of iucvserverdaemoninstaller.sh by command: + You may get the detailed usage of iucvserverdaemoninstaller.sh by command: .. code-block:: text ./iucvserverdaemoninstaller.sh -h -3. Logon your BYOL, run a simple command to check the if the iucv - channel is set up correctly by commands: +3. Logon your BYOL, run a simple command to check if the iucv + channel is set up correctly by command: .. code-block:: text @@ -155,7 +155,7 @@ Configuration of cloud-init in zLinux ------------------------------------- To do useful work with the user data, the zLinux image must be configured to run a service that retrieves the user data passed from the Feilong -and then takes some actions based on the contents of that data. This task can +and then takes some actions based on the contents of that data. This task can be done by cloud-init. For zLinux images that deployed by Feilong, zvmguestconfigure must @@ -191,69 +191,8 @@ down or the virtual machine is logged off. The changes to zLinux are implemented using zvmguestconfigure that is run when Linux is booted the next time. The steps of how to install zvmguestconfigure is described in subsequent sections. -Configuration of zvmguestconfigure on RHEL6.x and SLES11.x -.......................................................... - -Perform the following steps: - -1. Log on your BYOL, and copy the zvmguestconfigure script that is located at - /python-zvm-sdk/tools/share/zvmguestconfigure to your - zLinux, where zvmsdk_path can be found at section z/VM SDK install - -2. Logon on your zLinux, change the script to specify the authorizedSenders in - zvmguestconfigure file. It is recommended that this be set to a list of user IDs - which are allowed to transmit changes to the machine. At a minimum, this list - should include the userid of BYOL, which is usually OPNCLOUD. (It can be set - to '*', which indicates any virtual machine on the same LPAR may - send configuration requests to it) - -3. zvmguestconfigure is configured to run with run level 2, 3 and 5. It is not - configured to run as part of custom run level 4. If that run level is going to - be used, then the # Default-Start: line at the beginning of the file should be - updated to specify run level 4 in addition to the current run levels. - -4. Copy the zvmguestconfigure file to /etc/init.d and make it executable - -5. Add the zvmguestconfigure as a service by issuing: - - .. code-block:: text - - chkconfig --add zvmguestconfigure - -6. Activate the script by issuing: - - .. code-block:: text - - chkconfig zvmguestconfigure on - - If you wish to run with custom run level 4, then add 4 to the list of levels: - - .. code-block:: text - - chkconfig --level 2345 zvmguestconfigure on - -7. Verify that you installed the correct version of zvmguestconfigure on the - target machine. Do this by issuing the following service command: - - .. code-block:: text - - service zvmguestconfigure version - zvmguestconfigure version: 1.0 - -8. Verify that zvmguestconfigure on the target machine is configured to handle - requests from the server specified at step 2. Do this by issuing the following - service command: - - .. code-block:: text - - service zvmguestconfigure status - zvmguestconfigure is enabled to accept configuration reader files from: OPNCLOUD - - If zvmguestconfigure is not enabled to accept configuration reader files then verify - that you followed Step 2. - -Configuration of zvmguestconfigure on RHEL 7.x and SLES 12.x -............................................................ +Configuration of zvmguestconfigure on RHEL and SLES +................................................... Perform the following steps: @@ -261,7 +200,7 @@ Perform the following steps: script that are located at /python-zvm-sdk/tools/share/ folder to your zLinux, where zvmsdk_path can be found at the section z/VM SDK install. -2. Logon on your zLinux, change the script to specify the authorizedSenders in +2. Logon on your zLinux, change the script to specify the authorizedSenders in zvmguestconfigure file. It is recommended that this be set to a list of user IDs which are allowed to transmit changes to the machine. At a minimum, this list should include the userid of BYOL, which is usually OPNCLOUD. (It can be set @@ -271,9 +210,9 @@ Perform the following steps: 4. Install the zvmguestconfigure.service in the target zLinux: -- If the target Linux machine is RHEL7.x, copy the zvmguestconfigureconf4z.service file to: /lib/systemd/system +- If the target Linux machine is RHEL, copy the zvmguestconfigureconf4z.service file to: /lib/systemd/system -- If the target Linux machine is SLES12.x and SLES15, copy the zvmguestconfigure.service file to: /usr/lib/systemd/system +- If the target Linux machine is SLES, copy the zvmguestconfigure.service file to: /usr/lib/systemd/system and it is recommended that you change the NetworkManager.service to be wicked.service in the zvmguestconfigure.service 5. Enable the zvmguestconfigure service by issuing: @@ -288,14 +227,14 @@ Perform the following steps: systemctl start zvmguestconfigure.service -Configuration of zvmguestconfigure on Ubuntu 16.04 and Ubuntu 20.04 -................................................................... +Configuration of zvmguestconfigure on Ubuntu +............................................ 1. Logon your BYOL, and copy the zvmguestconfigure and zvmguestconfigure.service - script that are located at /python-zvm-sdk/tools/share/zvmguestconfigure + script that are located at /python-zvm-sdk/tools/share/zvmguestconfigure to your zLinux, where zvmsdk_path can be found at the section z/VM SDK install -2. Logon your zLinux, change the script to specify the authorizedSenders in +2. Logon your zLinux, change the script to specify the authorizedSenders in zvmguestconfigure file. It is recommended that this be set to a list of user IDs which are allowed to transmit changes to the machine. At a minimum, this list should include the userid of BYOL. (It can be set to '*', which indicates any @@ -305,7 +244,7 @@ Configuration of zvmguestconfigure on Ubuntu 16.04 and Ubuntu 20.04 it executable. 4. Install the zvmguestconfigure.service in the target Ubuntu machine, tailor the - zvmguestconfigure.service file for an Ubuntu 16.04 image by modifying the file + zvmguestconfigure.service file for an Ubuntu image by modifying the file contents as follows: .. code-block:: text @@ -322,8 +261,8 @@ Configuration of zvmguestconfigure on Ubuntu 16.04 and Ubuntu 20.04 [Install] WantedBy=multi-user.target - After that, copy the zvmguestconfigure.service file to /lib/systemd/system. If the - target Linux machine is Ubuntu 20.04, copy the zvmguestconfigure.service.ubuntu file + After that, copy the zvmguestconfigure.service file to /lib/systemd/system. If the + target Linux machine is Ubuntu 20.04, copy the zvmguestconfigure.service.ubuntu file to: /lib/systemd/system, and rename to zvmguestconfigure.service. 5. Enable the zvmguestconfigure service by issuing: @@ -357,262 +296,27 @@ cloud-init is installed correctly. cloud-init init --local Installation and configuration of cloud-init differs among different Linux -distributions, and cloud-init source code may change. This section provides +distributions, and cloud-init source code may change. This section provides general information, but you may have to tailor cloud-init to meet the needs of your Linux distribution. You can find a community-maintained list of dependencies at http://ibm.biz/cloudinitLoZ. -The z/VM OpenStack support has been tested with cloud-init 0.7.4 and 0.7.5 for -RHEL6.x and SLES11.x, 0.7.6 for RHEL7.x and SLES12.x, and 18.4 for SLES15, and -18.5 for RHEL8.1, and 0.7.8 for Ubuntu 16.04. +The z/VM OpenStack support has been tested with: +- cloud-init 0.7.6 for RHEL 7.x and SLES 12.x +- cloud-init 18.4 for SLES 15 +- cloud-init 18.5 for RHEL 8.1 +- cloud-init 20.1 for Ubuntu 20.04. If you are using a different version of cloud-init, you should change your -specification of the indicated commands accordingly.During cloud-init +specification of the indicated commands accordingly. During cloud-init installation, some dependency packages may be required. You can use yum/zypper and python setuptools to easily resolve these dependencies. See https://pypi.python.org/pypi/setuptools for more information. -Installation and Configuration of cloud-init on RHEL 6.x -........................................................ - -1. Download the cloud-init tar file from Init scripts for use on cloud images - https://launchpad.net/cloud-init/+download - -2. Using the file cloud-init-0.7.5 as an example, - untar this file by issuing the following command: - - .. code-block:: text - - tar -zxvf cloud-init-0.7.5.tar.gz - -3. Issue the following to install cloud-init: - - .. code-block:: text - - cd ./cloud-init-0.7.5 - python setup.py build - python setup.py install - cp ./sysvinit/redhat/* /etc/init.d - -4. Update /etc/init.d/cloud-init-local to ensure that it starts after the - zvmguestconfigure and sshd services. On RHEL 6, change the # Required-Start - line in the ### BEGIN INIT INFO section from: - - .. code-block:: text - - ### BEGIN INIT INFO - # Provides: cloud-init-local - # Required-Start: $local_fs $remote_fs - # Should-Start: $time - # Required-Stop: - - to: - - .. code-block:: text - - ### BEGIN INIT INFO - # Provides: cloud-init-local - # Required-Start: $local_fs $remote_fs zvmguestconfigure sshd - # Should-Start: $time - # Required-Stop: - -5. The default configuration file /etc/cloud/cloud.cfg is for ubuntu, not RHEL. - To tailor it for RHEL: - - a. Replace distro:ubuntu with distro:rhel at around line 79. - - b. Change the default user name, password and gecos as you wish, at around lines 82 to 84 - - c. Change the groups tag to remove user groups that are not available for this distribution. - After the change, the groups tag at around line 85 should appear similar to the following: - groups: [adm, audio, cdrom, dialout, floppy, video, dip] - - For more information on how to configure cloud-init, please check the cloud-init documentation - http://cloudinit.readthedocs.org/. - -6. Cloud-init will try to add user syslog to group adm. This needs to be - changed. RHEL does not have a syslog user by default, so issue: - - .. code-block:: text - - useradd syslog - -7. Add the cloud-init related service with the following commands: - - .. code-block:: text - - chkconfig --add cloud-init-local - chkconfig --add cloud-init - chkconfig --add cloud-config - chkconfig --add cloud-final - -8. Then start them with the following sequence: - - .. code-block:: text - - chkconfig cloud-init-local on - chkconfig cloud-init on - chkconfig cloud-config on - chkconfig cloud-final on - - You can issue ls -l /etc/rc5.d/ | grep -e xcat -e cloud to find the services. - (Make sure that zvmguestconfigure starts before any cloud-init service.) - - .. code-block:: text - - lrwxrwxrwx. 1 root root 22 Jun 13 04:39 S50xcatconfinit -> ../init.d/zvmguestconfigure - lrwxrwxrwx. 1 root root 26 Jun 13 04:39 S51cloud-init-local -> ../init.d/cloud-init-local - lrwxrwxrwx. 1 root root 20 Jun 13 04:39 S52cloud-init -> ../init.d/cloud-init - lrwxrwxrwx. 1 root root 22 Jun 13 04:39 S53cloud-config -> ../init.d/cloud-config - lrwxrwxrwx. 1 root root 21 Jun 13 04:39 S54cloud-final -> ../init.d/cloud-final - -9. To verify cloud-init configuration, issue: cloud-init init --local - - .. code-block:: text - - cloud-init init --local - - Make sure that no errors occur. The following warning messages can be ignored: - - /usr/lib/python2.6/site-packages/Cheetah-2.4.4-py2.6.egg/Cheetah/Compiler.py:1509: UserWarning: - You don’t have the C version of NameMapper installed! I’m disabling Cheetah’s useStackFrames - option as it is painfully slow with the Python version of NameMapper. You should get a copy - of Cheetah with the compiled C version of NameMapper. You don’t have the C version of NameMapper installed! - -10. Issue following command, if this file exists, or cloud-init will not work after reboot. - - .. code-block:: text - - rm -rf /var/lib/cloud - -Installation and Configuration of cloud-init on SLES11.x -........................................................ - -1. Download the cloud-init tar file from https://launchpad.net/cloud-init/+download. - -2. Using the file cloud-init-0.7.5 as an example, untar this file by issuing - the following command: - - .. code-block:: text - - tar -zxvf cloud-init-0.7.5.tar.gz - - -3. Issue the following commands to install cloud-init: - - .. code-block:: text - - cd ./cloud-init-0.7.5 - python setup.py build - python setup.py install - - **NOTE:**: After you issue the command tar -zxvf cloud-init-0.7.5.tar.gz, - the directory ./sysvinit/sles/ does not exist. So you have to copy the - cloud-init related services from ./sysvinit/redhat/* to /etc/init.d/: - - .. code-block:: text - - cp ./sysvinit/redhat/* /etc/init.d - - You will find that four scripts, cloud-init-local, cloud-init, cloud-config, - and cloud-final are added to /etc/init.d/. Modify each of them by replacing - the variable: - - .. code-block:: text - - cloud_init="/usr/bin/cloud-init" - - with: - - .. code-block:: text - - cloud_init="/usr/local/bin/cloud-init" - -4. Update /etc/init.d/cloud-init-local to ensure that it starts after the - zvmguestconfigure service. On SLES, change the # Required-Start line in the - ### BEGIN INIT INFO section from: - - .. code-block:: text - - ### BEGIN INIT INFO - # Provides: cloud-init-local - # Required-Start: $local_fs $remote_fs - # Should-Start: $time - # Required-Stop: - - to: - - .. code-block:: text - - ### BEGIN INIT INFO - # Provides: cloud-init-local - # Required-Start: $local_fs $remote_fs zvmguestconfigure - # Should-Start: $time - # Required-Stop: - -5. The default configuration file /etc/cloud/cloud.cfg is for ubuntu, not SLES. To tailor it for SLES: - - a. Replace distro:ubuntu with distro:sles at around line 79. - - b. Change the default user name, password and gecos as you wish, at around lines 82 to 84. - - c. Change the groups at around line 85: groups: [adm, audio, cdrom, dialout, floppy, video, dip] - - d. Cloud-init will try to add user syslog to group adm. This needs to be changed. For SLES, issue the following commands: - - .. code-block:: text - - useradd syslog - groupadd adm - - For more information on changing these values, see the cloud-init documentation http://cloudinit.readthedocs.org/ - -6. Start the cloud-init related services with the following commands, - ignoring the error “insserv: Service network is missed in the runlevels 4 - to use service cloud-init” if it occurs: - - .. code-block:: text - - insserv cloud-init-local - insserv cloud-init - insserv cloud-config - insserv cloud-final - - At this point, you should find that the services in /etc/init.d/rcX.d appear as - you would expect (make sure that zvmguestconfigure starts before any cloud-init service): - - .. code-block:: text - - lrwxrwxrwx. 1 root root 22 Jun 13 04:39 S50xcatconfinit -> ../init.d/zvmguestconfigure - lrwxrwxrwx. 1 root root 26 Jun 13 04:39 S51cloud-init-local -> ../init.d/cloud-init-local - lrwxrwxrwx. 1 root root 20 Jun 13 04:39 S52cloud-init -> ../init.d/cloud-init - lrwxrwxrwx. 1 root root 22 Jun 13 04:39 S53cloud-config -> ../init.d/cloud-config - lrwxrwxrwx. 1 root root 21 Jun 13 04:39 S54cloud-final -> ../init.d/cloud-final - -7. To verify cloud-init configuration, issue: - - .. code-block:: text - - cloud-init init --local - - Make sure that no errors occur. The following warning messages can be ignored: - /usr/lib/python2.6/site-packages/Cheetah-2.4.4-py2.6.egg/Cheetah/Compiler.py:1509: - UserWarning: - You don’t have the C version of NameMapper installed! I’m disabling Cheetah’s useStackFrames - option as it is painfully slow with the Python version of NameMapper. You should get a copy - of Cheetah with the compiled C version of NameMapper. - You don’t have the C version of NameMapper installed! - -8. Issue following command, if this file exists, or cloud-init will not work after reboot. - - .. code-block:: text - - rm -rf /var/lib/cloud - -Installation and Configuration of cloud-init on RHEL 7.x and SLES 12.x -...................................................................... +Installation and Configuration of cloud-init on RHEL 7 and SLES 12 +.................................................................. -1. Download cloud-init0.7.6 from https://launchpad.net/cloud-init/+download. +1. Download cloud-init (for example 0.7.6) from https://launchpad.net/cloud-init/+download. 2. Untar it with this command: @@ -640,7 +344,7 @@ Installation and Configuration of cloud-init on RHEL 7.x and SLES 12.x # # metadata_urls: [ ’blah.com’ ] # - # timeout: 5 # (defaults to 50 seconds) + # timeout: 5 # (defaults to 50 seconds) # # max_wait: 10 # (defaults to 120 seconds) datasource_list: [ ConfigDrive, None ] @@ -689,7 +393,7 @@ Installation and Configuration of cloud-init on RHEL 7.x and SLES 12.x [Install] WantedBy=multi-user.target -6. Manually create the cloud-init-tmpfiles.conf file: +6. Manually create the cloud-init-tmpfiles.conf file: .. code-block:: text @@ -701,7 +405,7 @@ Installation and Configuration of cloud-init on RHEL 7.x and SLES 12.x echo "d /run/cloud-init 0700 root root - -" > /etc/tmpfiles.d/cloud-init-tmpfiles.conf -7. Because RHEL does not have a syslog user by default, you have to add it manually: +7. Because RHEL does not have a syslog user by default, you have to add it manually: .. code-block:: text @@ -771,7 +475,7 @@ Installation and Configuration of cloud-init on RHEL 7.x and SLES 12.x name: sles lock_passwd: false plain_text_passwd: ’sles’ - gecos: sles12user + gecos: sles15user groups: users sudo: ["ALL=(ALL) NOPASSWD:ALL"] shell: /bin/bash @@ -812,26 +516,26 @@ Installation and Configuration of cloud-init on RHEL 7.x and SLES 12.x systemctl status multipathd 14. Remove the /var/lib/cloud directory (if it exists), so that cloud-init will - not run after a reboot: + not run after a reboot: .. code-block:: text rm -rf /var/lib/cloud -Installation and Configuration of cloud-init on RHEL8.1 and SLES15 -.................................................................. +Installation and Configuration of cloud-init on RHEL 8, RHEL 9, SLES 15, and SLES 16 +.................................................................................... -Enable the system repositories of the RHEL8.1 and SLES15 to ensure that they can install software via yum and zypper. +Enable the system repositories of the RHEL8, RHEL9, SLES15, and SLES16 to ensure that they can install software via yum and zypper. 1. Install cloud-init by the command: - a. For the RHEL8.1: + a. For RHEL: .. code-block:: text - yum install cloud-init + yum install cloud-init - b. For the SLES15: + b. For SLES: .. code-block:: text @@ -839,7 +543,7 @@ Enable the system repositories of the RHEL8.1 and SLES15 to ensure that they can 2. OpenStack on z/VM uses ConfigDrive as the data source during the installation process. You must add the following lines to the - default configuration file, /etc/cloud/cloud.cfg. Remember to disable network + default configuration file, /etc/cloud/cloud.cfg. Remember to disable network configuration because network configuration is done by zvmguestconfigure. .. code-block:: text @@ -850,7 +554,7 @@ Enable the system repositories of the RHEL8.1 and SLES15 to ensure that they can # # metadata_urls: [ ’blah.com’ ] # - # timeout: 5 # (defaults to 50 seconds) + # timeout: 5 # (defaults to 50 seconds) # # max_wait: 10 # (defaults to 120 seconds) datasource_list: [ ConfigDrive, None ] @@ -866,7 +570,7 @@ Enable the system repositories of the RHEL8.1 and SLES15 to ensure that they can .. code-block:: text - disable_root: false + disable_root: false 4. Enable and start the cloud-init related services by issuing the following commands: @@ -891,44 +595,21 @@ Enable the system repositories of the RHEL8.1 and SLES15 to ensure that they can systemctl status cloud-init-local.service systemctl status cloud-init.service systemctl status cloud-config.service - systemctl status cloud-final.service + systemctl status cloud-final.service 6. Remove the /var/lib/cloud directory (if it exists), so that cloud-init will - not run after a reboot: + not run after a reboot: .. code-block:: text rm -rf /var/lib/cloud -Installation and Configuration of cloud-init on Ubuntu 16.04 and Ubuntu 20.04 -............................................................................. - -For Ubuntu 16.04, cloud-init0.7.8 or higher is required. The examples in this -section use cloud-init0.7.8. - -For Ubuntu 20.04, cloud-init20.1-10 is installed by default, can ignore below step1-2. +Installation and Configuration of cloud-init on Ubuntu +...................................................... -1. Download cloud-init0.7.8 from https://launchpad.net/cloud-init/+download. - Untar it with this command: +For Ubuntu, cloud-init is installed by default. - .. code-block:: text - - tar -zxvf cloud-init-0.7.8.tar.gz - -2. Issue the following commands to install cloud-init: - - .. code-block:: text - - cd ./cloud-init-0.7.8 - python3 setup.py build - python3 setup.py install --init-system systemd - - **NOTE:** You might have to install all the dependencies that cloud-init - requires according to your source z/VM environment. For example, you might - have to install setuptools before installing cloud-init. For more information, - see https://pypi.python.org/pypi/setuptools. - -3. OpenStack on z/VM uses ConfigDrive as the data source during the +1. OpenStack on z/VM uses ConfigDrive as the data source during the installation process. You must add the following lines to the default configuration file, /etc/cloud/cloud.cfg: @@ -940,7 +621,7 @@ For Ubuntu 20.04, cloud-init20.1-10 is installed by default, can ignore below st # # metadata_urls: [ ’blah.com’ ] # - # timeout: 5 # (defaults to 50 seconds) + # timeout: 5 # (defaults to 50 seconds) # # max_wait: 10 # (defaults to 120 seconds) datasource_list: [ ConfigDrive, None ] @@ -951,13 +632,13 @@ For Ubuntu 20.04, cloud-init20.1-10 is installed by default, can ignore below st **NOTE:** please pay attention to the indentation, otherwise, cloud-init may not work as expected. -4. Enable root login by configuring the /etc/cloud/cloud.cfg file: +2. Enable root login by configuring the /etc/cloud/cloud.cfg file: .. code-block:: text disable_root: false -5. Optionally, you can tailor the modules that run during the cloud-config +3. Optionally, you can tailor the modules that run during the cloud-config stage or the cloud-final stage by modifying cloud_config_modules or cloud_final_modules in /etc/cloud/cloud.cfg file. Enable and start the cloud-init related services by issuing the following commands: @@ -974,7 +655,7 @@ For Ubuntu 20.04, cloud-init20.1-10 is installed by default, can ignore below st systemctl enable cloud-final.service systemctl start cloud-final.service -6. Ensure all cloud-init services are in active status by issuing the following commands: +4. Ensure all cloud-init services are in active status by issuing the following commands: .. code-block:: text @@ -983,7 +664,7 @@ For Ubuntu 20.04, cloud-init20.1-10 is installed by default, can ignore below st systemctl status cloud-config.service systemctl status cloud-final.service -7. If you intend to use persistent disks, start the multipath service: +5. If you intend to use persistent disks, start the multipath service: .. code-block:: text @@ -991,7 +672,7 @@ For Ubuntu 20.04, cloud-init20.1-10 is installed by default, can ignore below st systemctl start multipathd systemctl status multipathd -8. Remove the /var/lib/cloud directory (if it exists), so that cloud-init will +6. Remove the /var/lib/cloud directory (if it exists), so that cloud-init will not run after a reboot: .. code-block:: text @@ -1011,8 +692,8 @@ Logon your BYOL, type the command: /opt/zthin/bin/creatediskimage Where: - is the userid of the zLinux, - is the device number for capture, + is the userid of the zLinux, + is the device number for capture, is the image's store location @@ -1024,7 +705,7 @@ Type the following command: .. code-block:: text - # curl http://1.2.3.4:8080/images -H "Content-Type:application/json" -H 'X-Auth-Token:' -X POST -d '{"image": {"url": "file:///var/lib/zvmsdk/images/0100", "image_meta": {"os_version": "rhel6.7"}, "image_name": "0100", "remote_host": "root@6.7.8.9"}}' + # curl http://1.2.3.4:8080/images -H "Content-Type:application/json" -H 'X-Auth-Token:' -X POST -d '{"image": {"url": "file:///var/lib/zvmsdk/images/0100", "image_meta": {"os_version": "rhel8.1"}, "image_name": "0100", "remote_host": "root@6.7.8.9"}}' {"rs": 0, "overallRC": 0, "modID": null, "rc": 0, "output": "", "errmsg": ""} Please note that if the source image is located at same server as BYOL, there is no need @@ -1036,7 +717,7 @@ Verify the import result by command: .. code-block:: text # curl http://127.0.0.1:8080/images?imagename=0100 -X GET -H "Content-Type:application/json" -H 'X-Auth-Token:' - {"rs": 0, "overallRC": 0, "modID": null, "rc": 0, "output": [{"image_size_in_bytes": "236435482", "disk_size_units": "1100:CYL", "md5sum": "26ddd19301d4f9c8a85e812412164bb8", "comments": null, "imagename": "0100", "imageosdistro": "rhel6.7", "type": "rootonly"}], "errmsg": ""} + {"rs": 0, "overallRC": 0, "modID": null, "rc": 0, "output": [{"image_size_in_bytes": "236435482", "disk_size_units": "1100:CYL", "md5sum": "26ddd19301d4f9c8a85e812412164bb8", "comments": null, "imagename": "0100", "imageosdistro": "rhel8.1", "type": "rootonly"}], "errmsg": ""} During image import you may meet following error: diff --git a/doc/source/parameters.yaml b/doc/source/parameters.yaml index 5c67626a2..f028f6674 100644 --- a/doc/source/parameters.yaml +++ b/doc/source/parameters.yaml @@ -728,9 +728,9 @@ image_metadata: description: | The metadata that describes the image. The valid keys are os_version, md5sum, and disk_type. - os_version is a required key, the valid values are: ``rhel6.x``, - ``rhel7.x``, ``rhel8.x``, ``rhel9.x``, ``sles11.x``, ``sles12.x``, - ``sles15.x``, ``ubuntu16.x``, ``ubuntu20.x``, ``ubuntu22.x``, and ``rhcos4.x``, + os_version is a required key, the valid values are: ``rhel7.x``, + ``rhel8.x``, ``rhel9.x``, `sles12.x``, ``sles15.x``, ``sles16.x``, + ``ubuntu20.x``, ``ubuntu22.x``, ``ubuntu24.x``, and ``rhcos4.x``, all case insensitive. Please contact your cloud administrator if you don't know the image's OS version. disk_type is required if os_version is ``rhcos4``, the valid disk_type values are: DASD, SCSI. @@ -1072,11 +1072,11 @@ network_interface_info: type: dict guest_os_version: description: | - Operating system version. The valid values are: ``rhel6.x``, - ``rhel7.x``, ``rhel8.x``, ``rhel9.x``, ``sles11.x``, ``sles12.x``, - ``sles15.x``, ``ubuntu16.x``, ``ubuntu20.x``, ``ubuntu22.x``, and ``rhcos4.x``, - all case insensitive. Please contact your cloud administrator if you don't know - the guest's OS version. + Operating system version. The valid values are: ``rhel7.x``, + ``rhel8.x``, ``rhel9.x``, ``sles12.x``, ``sles15.x``, ``sles16.x``, + ``ubuntu20.x``, ``ubuntu22.x``, ``ubuntu24.x``, and ``rhcos4.x``, + all case insensitive. Please contact your cloud administrator + if you don't know the guest's OS version. in: body required: true type: string diff --git a/smtLayer/smtTest.py b/smtLayer/smtTest.py index aed579861..90f3dfacc 100644 --- a/smtLayer/smtTest.py +++ b/smtLayer/smtTest.py @@ -1,10 +1,9 @@ #!/usr/bin/env python -# Copyright Contributors to the Feilong Project. -# SPDX-License-Identifier: Apache-2.0 - # Test logic for Systems Management Ultra Thin Layer # -# Copyright 2017 IBM Corp. +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017 IBM Corp. +# SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -66,7 +65,7 @@ '<<>>': '/install/zvm/POC/testImages/cfgdrive.tgz', # Simple tar file for the config drive '<<>>': '/install/zvm/POC/testImages/' + - 'rhel67eckd_small_1100cyl.img', # Small image file + 'rhel89eckd_small_1100cyl.img', # Small image file '<<>>': '/opt/zthin/bin/unpackdiskimage', # Location of unpackdiskimage '<<>>': longstring, diff --git a/zthin-parts/zthin/bin/IUCV/iucvserverdaemoninstaller.sh b/zthin-parts/zthin/bin/IUCV/iucvserverdaemoninstaller.sh index 9590a9a94..58faa9a3e 100644 --- a/zthin-parts/zthin/bin/IUCV/iucvserverdaemoninstaller.sh +++ b/zthin-parts/zthin/bin/IUCV/iucvserverdaemoninstaller.sh @@ -1,7 +1,7 @@ #!/bin/bash -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - +# +# Copyright 2025 Contributors to the Feilong Project. # Copyright 2017,2022 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -35,7 +35,7 @@ function getOsVersion { # None # @Output: # os - Variable set with OS and version information. For example: - # "rhel62" or "sles11sp2" + # "rhel89" or "sles15sp6" # @Code: if [[ -e "/etc/os-release" ]]; then os=`cat /etc/os-release | grep "^ID=" | sed \ @@ -46,36 +46,8 @@ function getOsVersion { -e 's/"//g' \ -e 's/\.//'` os=$os$version - - #The /etc/SuSE-release file will be deprecated in sles11.4 and later release - elif [[ -e "/etc/SuSE-release" ]]; then - os='sles' - version=`cat /etc/SuSE-release | grep "VERSION =" | sed \ - -e 's/^.*VERSION =//' \ - -e 's/\s*$//' \ - -e 's/.//' \ - -e 's/[^0-9]*([0-9]+).*/$1/'` - os=$os$version - - # Append service level - level=`echo "/etc/SuSE-release" | grep "LEVEL =" | sed \ - -e 's/^.*LEVEL =//' \ - -e 's/\s*$//' \ - -e 's/.//' \ - -e 's/[^0-9]*([0-9]+).*/$1/'` - os=$os'sp'$level - - #The /etc/redhat-release file will be deprecated in rhel7 and later release - elif [[ -e "/etc/redhat-release" ]]; then - os='rhel' - version=`cat /etc/redhat-release | grep -i "Red Hat Enterprise Linux Server" | sed \ - -e 's/[A-Za-z\/\.\(\)]//g' \ - -e 's/^ *//g' \ - -e 's/ *$//g' \ - -e 's/\s.*$//'` - os=$os$version fi - #echo "Detect the running os version is: "$os + #echo "The running OS version is: "$os return } @@ -111,15 +83,11 @@ function installIucvserver { cp iucvserv /usr/bin/iucvserv # Install the service file according to linux distro - if [[ $os == sles11* || $os == rhel6* ]]; then - COPY_SERVICE_CMD="cp iucvserd /etc/init.d/" - REGISTER_SERVICE_CMD="chkconfig --add iucvserd" - START_SERVICE_CMD="service iucvserd start" - elif [[ $os == ubuntu* || $os == rhel7* || $os == rhel8* || $os == rhel9* || $os == rhel10* ]]; then + if [[ $os == ubuntu* || $os == rhel* ]]; then COPY_SERVICE_CMD="cp iucvserd.service /lib/systemd/system/" REGISTER_SERVICE_CMD="systemctl enable iucvserd.service" START_SERVICE_CMD="systemctl start iucvserd.service" - elif [[ $os == sles12* || $os == sles15* ]]; then + elif [[ $os == sles* ]]; then COPY_SERVICE_CMD="cp iucvserd.service /usr/lib/systemd/system/" REGISTER_SERVICE_CMD="systemctl enable iucvserd.service" START_SERVICE_CMD="systemctl start iucvserd.service" diff --git a/zthin-parts/zthin/bin/IUCV/iucvupgrade.sh b/zthin-parts/zthin/bin/IUCV/iucvupgrade.sh index b69b8a6ef..eb17cc365 100644 --- a/zthin-parts/zthin/bin/IUCV/iucvupgrade.sh +++ b/zthin-parts/zthin/bin/IUCV/iucvupgrade.sh @@ -1,8 +1,8 @@ #!/bin/bash -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - -# Copyright 2017 IBM Corp. +# +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -16,8 +16,6 @@ # License for the specific language governing permissions and limitations # under the License. # -# Change Activity: -# # Get linux version name=`cat /etc/*release|egrep -i 'Red Hat|Suse|Ubuntu'` @@ -27,18 +25,7 @@ lnx_version=`echo $version|grep -o '[0-9]\+'|head -1` echo $lnx_name $lnx_version >>/var/log/messages -rollback_rhel6_sles11(){ - echo "Enter rollback" >>/var/log/messages - if [ -f /etc/init.d/iucvserd.old ]; then - mv /etc/init.d/iucvserd.old /etc/init.d/iucvserd 2>/dev/nul >>/var/log/messages - fi - if [ -f /usr/bin/iucvserv.old ]; then - mv /usr/bin/iucvserv.old /usr/bin/iucvserv 2>/dev/nul >>/var/log/messages - fi - service iucvserd restart >>/var/log/messages -} - -rollback_rhel7_ubuntu(){ +rollback_rhel_ubuntu(){ echo "Enter rollback" >>/var/log/messages if [ -f /lib/systemd/system/iucvserd.service.old ]; then mv /lib/systemd/system/iucvserd.service.old /lib/systemd/system/iucvserd.service 2>/dev/nul >>/var/log/messages @@ -49,7 +36,7 @@ rollback_rhel7_ubuntu(){ systemctl restart iucvserd >>/var/log/messages } -rollback_sles12(){ +rollback_sles(){ if [ -f /usr/lib/systemd/system/iucvserd.service.old ]; then mv /usr/lib/systemd/system/iucvserd.service.old /lib/systemd/system/iucvserd.service 2>/dev/nul >>/var/log/messages fi @@ -60,63 +47,28 @@ rollback_sles12(){ } # Replace iucvserver files -# Rhel6 and Sles11 -if [[ "$lnx_name" = "Red" && $lnx_version -lt 7 ]] || [[ "$lnx_name" = "SUSE" && $lnx_version -lt 12 ]]; then - echo "target system: rhel6 or sles11" >>/var/log/messages - service iucvserd stop >>/var/log/messages - mv /etc/init.d/iucvserd /etc/init.d/iucvserd.old 2>/dev/nul >>/var/log/messages - if [ $? -ne 0 ]; then - rollback_rhel6_sles11 - exit 1 - fi - mv /usr/bin/iucvserv /usr/bin/iucvserv.old 2>/dev/nul >>/var/log/messages - if [ $? -ne 0 ]; then - rollback_rhel6_sles11 - exit 1 - fi - mv /usr/bin/iucvserv.new /usr/bin/iucvserv 2>/dev/nul >>/var/log/messages - if [ $? -ne 0 ]; then - rollback_rhel6_sles11 - exit 1 - fi - mv /etc/init.d/iucvserd.new /etc/init.d/iucvserd 2>/dev/nul >>/var/log/messages - if [ $? -ne 0 ]; then - rollback_rhel6_sles11 - exit 1 - fi - ps -ef|grep iucv >>/var/log/messages - netstat -napo|grep iucvserv >>/var/log/messages - service iucvserd restart >>/var/log/messages - - # roll back - ps_iucv=`ps -ef|grep -c iucvserv` - if [[ $ps_iucv -lt 2 ]]; then - rollback_rhel6_sles11 - exit 1 - fi - -# Above Rhel7 and Ubuntu -elif [[ "$lnx_name" = "Red" && $lnx_version -ge 7 ]] || [[ "$lnx_name" = "Ubuntu" ]]; then - echo "target system: rhel7 or ubuntu" >>/var/log/messages +# RHEL and Ubuntu +if [[ "$lnx_name" = "Red" ]] || [[ "$lnx_name" = "Ubuntu" ]]; then + echo "target system: rhel or ubuntu" >>/var/log/messages pkill iucvserv >>/var/log/messages mv /lib/systemd/system/iucvserd.service /lib/systemd/system/iucvserd.service.old 2>/dev/nul >>/var/log/messages if [ $? -ne 0 ]; then - rollback_rhel7_ubuntu + rollback_rhel_ubuntu exit 1 fi mv /usr/bin/iucvserv /usr/bin/iucvserv.old 2>/dev/nul >>/var/log/messages if [ $? -ne 0 ]; then - rollback_rhel7_ubuntu + rollback_rhel_ubuntu exit 1 fi mv /usr/bin/iucvserv.new /usr/bin/iucvserv 2>/dev/nul >>/var/log/messages if [ $? -ne 0 ]; then - rollback_rhel7_ubuntu + rollback_rhel_ubuntu exit 1 fi mv /lib/systemd/system/iucvserd.service.new /lib/systemd/system/iucvserd.service 2>/dev/nul >>/var/log/messages if [ $? -ne 0 ]; then - rollback_rhel7_ubuntu + rollback_rhel_ubuntu exit 1 fi systemctl daemon-reload >>/var/log/messages @@ -125,32 +77,32 @@ elif [[ "$lnx_name" = "Red" && $lnx_version -ge 7 ]] || [[ "$lnx_name" = "Ubuntu # roll back ps_iucv=`ps -ef|grep -c iucvserv` if [[ $ps_iucv -lt 2 ]]; then - rollback_rhel7_ubuntu + rollback_rhel_ubuntu exit 1 fi -# Above Sles12 -elif [[ "$lnx_name" = "SUSE" && $lnx_version -ge 12 ]]; then - echo "target system: sles12" >>/var/log/messages +# SLES +elif [[ "$lnx_name" = "SUSE" ]]; then + echo "target system: sles" >>/var/log/messages pkill iucvserv >>/var/log/messages mv /usr/lib/systemd/system/iucvserd.service /usr/lib/systemd/system/iucvserd.service.old 2>/dev/nul >>/var/log/messages if [ $? -ne 0 ]; then - rollback_sles12 + rollback_sles exit 1 fi mv /usr/bin/iucvserv /usr/bin/iucvserv.old 2>/dev/nul >>/var/log/messages if [ $? -ne 0 ]; then - rollback_sles12 + rollback_sles exit 1 fi mv /usr/bin/iucvserv.new /usr/bin/iucvserv 2>/dev/nul >>/var/log/messages if [ $? -ne 0 ]; then - rollback_sles12 + rollback_sles exit 1 fi mv /usr/lib/systemd/system/iucvserd.service.new /usr/lib/systemd/system/iucvserd.service 2>/dev/nul >>/var/log/messages if [ $? -ne 0 ]; then - rollback_sles12 + rollback_sles exit 1 fi systemctl daemon-reload >>/var/log/messages @@ -159,7 +111,7 @@ elif [[ "$lnx_name" = "SUSE" && $lnx_version -ge 12 ]]; then # roll back ps_iucv=`ps -ef|grep -c iucvserv` if [[ $ps_iucv -lt 2 ]]; then - rollback_sles12 + rollback_sles exit 1 fi fi diff --git a/zthin-parts/zthin/bin/unpackdiskimage b/zthin-parts/zthin/bin/unpackdiskimage index 73db44dc5..22e9db454 100644 --- a/zthin-parts/zthin/bin/unpackdiskimage +++ b/zthin-parts/zthin/bin/unpackdiskimage @@ -1,9 +1,10 @@ #!/bin/bash -# Copyright Contributors to the Feilong Project. -# SPDX-License-Identifier: Apache-2.0 ############################################################################### -# Copyright 2017,2020 IBM Corp. +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017,2020 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -16,7 +17,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -# # +# ############################################################################### # COMPONENT: unpackdiskimage # # # @@ -321,8 +322,8 @@ function resizePartition { out=`e2fsck -yf ${lastPartition} 2>&1` rc=$? - #Considering that the e2fsck version of rhel77 is too low to support - #the rhel8 guest VM, so the return value of 8 is ignored. + # Considering that the e2fsck version of rhel77 is too low to support + # the rhel8 and rhel9 guest VMs, the return value of 8 is ignored. if (( rc != 0 && rc != 1 && rc != 2 && rc != 8 )); then printError "'e2fsck -f ${lastPartition}' returns rc: $rc, out: $out" return 1 @@ -745,8 +746,6 @@ function deployDiskImage { #Get target os version local osRelease="$deviceMountPoint/etc/os-release" - local slesRelease="$deviceMountPoint/etc/SuSE-release" - local rhelRelease="$deviceMountPoint/etc/redhat-release" if [[ -e $osRelease ]]; then os=`cat $osRelease | grep "^ID=" | sed \ @@ -757,38 +756,10 @@ function deployDiskImage { -e 's/"//g' \ -e 's/\.//'` os=$os$version - - #The /etc/SuSE-release file will be deprecated in sles11.4 and later release - elif [[ -e $slesRelease ]]; then - os='sles' - version=`cat $slesRelease | grep "VERSION =" | sed \ - -e 's/^.*VERSION =//' \ - -e 's/\s*$//' \ - -e 's/.//' \ - -e 's/[^0-9]*([0-9]+).*/$1/'` - os=$os$version - - # Append service level - level=`echo $slesRelease | grep "LEVEL =" | sed \ - -e 's/^.*LEVEL =//' \ - -e 's/\s*$//' \ - -e 's/.//' \ - -e 's/[^0-9]*([0-9]+).*/$1/'` - os=$os'sp'$level - - #The /etc/redhat-release file will be deprecated in rhel7 and later release - elif [[ -e $rhelRelease ]]; then - os='rhel' - version=`cat $rhelRelease | grep -i "Red Hat Enterprise Linux Server" | sed \ - -e 's/[A-Za-z\/\.\(\)]//g' \ - -e 's/^ *//g' \ - -e 's/ *$//g' \ - -e 's/\s.*$//'` - os=$os$version fi # Exec zipl command to prepare device for initial problem load - if [[ $os == sles12* || $os == sles15* ]]; then + if [[ $os == sles* ]]; then out=`chroot $deviceMountPoint /sbin/zipl -c /boot/zipl/config 2>&1` rc=$? if (( rc != 0 )); then @@ -797,7 +768,7 @@ function deployDiskImage { rm -rf $deviceMountPoint return 1 fi - elif [[ $os == sles11* || $os == rhel* || $os == ubuntu* ]]; then + elif [[ $os == rhel* || $os == ubuntu* ]]; then out=`chroot $deviceMountPoint /sbin/zipl 2>&1` rc=$? if (( rc != 0 )); then diff --git a/zthin-parts/zthin/src/IUCV/iucvserver.c b/zthin-parts/zthin/src/IUCV/iucvserver.c index dd3aa3834..a431fddb2 100644 --- a/zthin-parts/zthin/src/IUCV/iucvserver.c +++ b/zthin-parts/zthin/src/IUCV/iucvserver.c @@ -1,8 +1,8 @@ /* - * Copyright Contributors to the Feilong Project. * SPDX-License-Identifier: Apache-2.0 * - * * Copyright 2017 IBM Corporation + * Copyright 2025 Contributors to the Feilong Project. + * Copyright 2017 IBM Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -249,7 +249,7 @@ struct lnx_dist get_linux_version() bzero((char *) &linux_dist, sizeof(linux_dist)); // Get linux name - strcpy(buffer, "echo `cat /etc/*release|egrep -i 'Red|Suse|Ubuntu'`"); + strcpy(buffer, "echo `cat /etc/os-release | egrep -i 'Red|Suse|Ubuntu'`"); if (NULL != (fp=popen(buffer, "r"))) { bzero(buffer, BUFFER_SIZE); @@ -262,10 +262,6 @@ struct lnx_dist get_linux_version() if (strstr(buffer, "RED") != NULL) { strcpy(linux_dist.name, "Rhel"); - // For rhel65, it doesn't have a "VERSION" line. - if (strstr(buffer, "6")!= NULL){ - linux_dist.version = 6; - } } else if (strstr(buffer, "SUSE") != NULL) { @@ -279,7 +275,7 @@ struct lnx_dist get_linux_version() } } // Get linux version - strcpy(buffer, "echo `cat /etc/*release|grep ^VERSION`"); + strcpy(buffer, "echo `cat /etc/os-release | grep ^VERSION`"); if ((linux_dist.version == 0) && (NULL != (fp=popen(buffer, "r")))) { bzero(buffer, BUFFER_SIZE); diff --git a/zvmsdk/api.py b/zvmsdk/api.py index 8cec5e393..b05f2b582 100755 --- a/zvmsdk/api.py +++ b/zvmsdk/api.py @@ -1,6 +1,7 @@ # Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 +# Copyright 2025 Contributors to the Feilong Project # Copyright 2017,2025 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -516,7 +517,7 @@ def image_import(self, image_name, url, image_meta, remote_host=None): :param dict image_meta: a dictionary to describe the image info, such as md5sum, os_version. For example: - {'os_version': 'rhel6.2', + {'os_version': 'rhel8.9', 'md5sum': ' 46f199c336eab1e35a72fa6b5f6f11f5', 'disk_type': 'DASD'} :param string remote_host: diff --git a/zvmsdk/dist.py b/zvmsdk/dist.py index 585fa42ad..66d2cd00c 100755 --- a/zvmsdk/dist.py +++ b/zvmsdk/dist.py @@ -1,6 +1,7 @@ # Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 +# Copyright 2025 Contributors to the Feilong Project # Copyright 2017,2022 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -36,9 +37,9 @@ class LinuxDist(object): """Linux distribution base class - Due to we need to interact with linux dist and inject different files - according to the dist version. Currently RHEL6, RHEL7, SLES11, SLES12 - , UBUNTU16 and RHCOS4 are supported. + We need to interact with linux distributions and inject different files + according to the distribution version. Currently, RHEL7, RHEL8, RHEL9, RHCOS4, + SLES12, SLES15, SLES16, UBUNTU20, UBUNTU22, and UBUNTU24 are supported. """ def __init__(self): self._smtclient = smtclient.get_smtclient() @@ -78,10 +79,11 @@ def create_network_configuration_files(self, file_path, guest_networks, clean_cmd: if first is true, it is used to erase the previous network interface configuration, will be put into invokeScript file - net_enable_cmd: 'ip addr' and 'ip link' command to enable the - new network interface + net_enable_cmd: commands to enable the new network interface + vdev_list: list of vdevs of the new network interfaces """ cfg_files = [] + vdev_list = [] cmd_strings = '' udev_cfg_str = '' dns_cfg_str = '' @@ -100,6 +102,7 @@ def create_network_configuration_files(self, file_path, guest_networks, # Mark 1st network in guest_networks as primary network['primary'] = True if idx == 0 else False base_vdev = network['nic_vdev'].lower() + vdev_list.append(base_vdev) file_name = self._get_device_filename(base_vdev) (cfg_str, cmd_str, dns_str, route_str, net_cmd) = self._generate_network_configuration( @@ -126,7 +129,7 @@ def create_network_configuration_files(self, file_path, guest_networks, file_name_route, route_cfg_str, udev_cfg_str, first) - return cfg_files, cmd_strings, clean_cmd, net_enable_cmd + return cfg_files, cmd_strings, clean_cmd, net_enable_cmd, vdev_list def _generate_network_configuration(self, network, vdev, active=False): method = 'static' @@ -247,7 +250,7 @@ def _get_route_str(self, method, gateway_v4): @abc.abstractmethod def _enable_network_interface(self, device, ip, broadcast): - """construct a router string.""" + """construct a command to bring up an interface.""" pass @abc.abstractmethod @@ -266,8 +269,8 @@ def _get_dns_filename(self): pass @abc.abstractmethod - def get_znetconfig_contents(self): - """construct znetconfig file will be called during first boot.""" + def get_znetconfig_contents(self, vdev_list): + """construct znetconfig file that will be called during first boot.""" pass @abc.abstractmethod @@ -398,81 +401,8 @@ def _delete_vdev_info(self, vdev): return '' -class rhel6(rhel): - def get_znetconfig_contents(self): - return '\n'.join(('cio_ignore -R', - 'znetconf -R -n', - 'udevadm trigger', - 'udevadm settle', - 'sleep 2', - 'znetconf -A', - 'service network restart', - 'cio_ignore -u')) - - def _get_device_filename(self, vdev): - return 'ifcfg-eth' + str(vdev).zfill(4) - - def _get_all_device_filename(self): - return 'ifcfg-eth*' - - def _get_device_name(self, vdev): - return 'eth' + str(vdev).zfill(4) - - def get_scp_string(self, root, fcp, wwpn, lun): - return ("=root=%(root)s selinux=0 " - "rd_ZFCP=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s") % { - 'root': root, 'fcp': fcp, 'wwpn': wwpn, 'lun': lun} - - def get_zipl_script_lines(self, image, ramdisk, root, fcp, wwpn, lun): - return ['#!/bin/bash\n', - ('echo -e "[defaultboot]\\n' - 'timeout=5\\n' - 'default=boot-from-volume\\n' - 'target=/boot/\\n' - '[boot-from-volume]\\n' - 'image=%(image)s\\n' - 'ramdisk=%(ramdisk)s\\n' - 'parameters=\\"root=%(root)s ' - 'rd_ZFCP=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s selinux=0\\""' - '>/etc/zipl_volume.conf\n' - 'zipl -c /etc/zipl_volume.conf') - % {'image': image, 'ramdisk': ramdisk, 'root': root, - 'fcp': fcp, 'wwpn': wwpn, 'lun': lun}] - - def create_active_net_interf_cmd(self): - return 'service zvmguestconfigure start' - - def _get_clean_command(self): - files = os.path.join(self._get_network_file_path(), - self._get_all_device_filename()) - return '\nrm -f %s\n' % files - - def generate_set_hostname_script(self, hostname): - lines = ['#!/bin/bash\n', - 'sed -i "s/^HOSTNAME=.*/HOSTNAME=%s/" ' - '/etc/sysconfig/network\n' % hostname, - '/bin/hostname %s\n' % hostname] - return lines - - def get_volume_attach_configuration_cmds(self, fcp_list, target_wwpns, - target_lun, multipath, - mount_point): - "generate punch script for attachment configuration" - func_name = 'get_volume_attach_configuration_cmds' - raise exception.SDKFunctionNotImplementError(func=func_name, - modID='volume') - - def get_volume_detach_configuration_cmds(self, fcp_list, target_wwpns, - target_lun, multipath, - mount_point, connections): - "generate punch script for detachment configuration" - func_name = 'get_volume_detach_configuration_cmds' - raise exception.SDKFunctionNotImplementError(func=func_name, - modID='volume') - - class rhel7(rhel): - def get_znetconfig_contents(self): + def get_znetconfig_contents(self, vdev_list): return '\n'.join(('cio_ignore -R', 'znetconf -R -n', 'udevadm trigger', @@ -564,8 +494,6 @@ def get_volume_detach_configuration_cmds(self, fcp_list, target_wwpns, class rhel8(rhel7): - """docstring for rhel8""" - def _get_device_filename(self, vdev): return 'ifcfg-enc' + str(vdev).zfill(4) @@ -613,18 +541,52 @@ def get_volume_detach_configuration_cmds(self, fcp_list, target_wwpns, return content -class rhel9(rhel8): - pass +class rhel9(rhel): + def _get_clean_command(self): + # TODO(eric): ADD MODERN DISTRIBUTIONS + pass + + def _get_device_filename(self, vdev): + # TODO(eric): ADD MODERN DISTRIBUTIONS + pass + + def create_active_net_interf_cmd(self): + # TODO(eric): ADD MODERN DISTRIBUTIONS + pass + + def get_scp_string(self, root, fcp, wwpn, lun): + # TODO(eric): ADD MODERN DISTRIBUTIONS + pass + + def get_zipl_script_lines(self, image, ramdisk, root, fcp, wwpn, lun): + # TODO(eric): ADD MODERN DISTRIBUTIONS + pass + + def get_znetconfig_contents(self, vdev_list): + # TODO(eric): ADD MODERN DISTRIBUTIONS + pass + + def get_volume_attach_configuration_cmds(self, fcp_list, target_wwpns, + target_lun, multipath, + mount_point): + # TODO(eric): ADD MODERN DISTRIBUTIONS + pass + + def get_volume_detach_configuration_cmds(self, fcp_list, target_wwpns, + target_lun, multipath, + mount_point, connections): + # TODO(eric): ADD MODERN DISTRIBUTIONS + pass -class rhel10(rhel8): +class rhel10(rhel9): + # TODO(eric): ADD MODERN DISTRIBUTIONS pass class rhcos(LinuxDist): def create_coreos_parameter(self, network_info, userid=''): try: - # TODO: fix the limitation that assuming the first NIC configured vif = network_info[0] ip_addr = vif['ip_addr'] gateway_addr = vif['gateway_addr'] @@ -753,7 +715,7 @@ def get_scp_string(self, root, fcp, wwpn, lun): def get_zipl_script_lines(self, image, ramdisk, root, fcp, wwpn, lun): pass - def get_znetconfig_contents(self): + def get_znetconfig_contents(self, vdev_list): pass @@ -762,32 +724,6 @@ class rhcos4(rhcos): class sles(LinuxDist): - def _get_network_file_path(self): - return '/etc/sysconfig/network/' - - def _get_cfg_str(self, device, method, broadcast_v4, gateway_v4, ip_v4, - netmask_v4, address_read, subchannels, dns_v4, mtu): - cfg_str = "BOOTPROTO=\'%s\'\n" % method - if method == 'static': - cfg_str += "IPADDR=\'%s\'\n" % ip_v4 - cfg_str += "NETMASK=\'%s\'\n" % netmask_v4 - cfg_str += "BROADCAST=\'%s\'\n" % broadcast_v4 - cfg_str += "STARTMODE=\'onboot\'\n" - cfg_str += ("NAME=\'OSA Express Network card (%s)\'\n" % - address_read) - cfg_str += "MTU=\'%s\'\n" % mtu - if (dns_v4 is not None) and (len(dns_v4) > 0): - self.dns_v4 = dns_v4 - else: - self.dns_v4 = None - return cfg_str - - def _get_route_str(self, method, gateway_v4): - route_str = '' - if method == 'static': - route_str = 'default %s - -\n' % gateway_v4 - return route_str - def _get_cmd_str(self, address_read, address_write, address_data): cmd_str = 'qeth_configure -l 0.0.%s ' % address_read.lower() cmd_str += '0.0.%(write)s 0.0.%(data)s 1\n' % {'write': @@ -801,12 +737,6 @@ def _get_cmd_str(self, address_read, address_write, address_data): def _get_dns_filename(self): return '/etc/resolv.conf' - def _get_device_filename(self, vdev): - return 'ifcfg-eth' + str(vdev).zfill(4) - - def _get_all_device_filename(self): - return 'ifcfg-eth*' - def _get_device_name(self, vdev): return 'eth' + str(vdev).zfill(4) @@ -894,7 +824,7 @@ def _get_udev_rules(self, channel_read, channel_write, channel_data): return rules_str def get_scp_string(self, root, fcp, wwpn, lun): - return ("=root=%(root)s " + return ("=root=%(root)s zfcp.allow_lun_scan=0 " "zfcp.device=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s") % { 'root': root, 'fcp': fcp, 'wwpn': wwpn, 'lun': lun} @@ -907,15 +837,25 @@ def get_zipl_script_lines(self, image, ramdisk, root, fcp, wwpn, lun): 'target = /boot/zipl\\n' 'ramdisk=%(ramdisk)s\\n' 'parameters=\\"root=%(root)s ' - 'zfcp.device=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s\\""' + 'zfcp.device=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s ' + 'zfcp.allow_lun_scan=0\\""' '>/etc/zipl_volume.conf\n' 'mkinitrd\n' 'zipl -c /etc/zipl_volume.conf') % {'image': image, 'ramdisk': ramdisk, 'root': root, 'fcp': fcp, 'wwpn': wwpn, 'lun': lun}] + def create_active_net_interf_cmd(self): + return 'systemctl start zvmguestconfigure.service' + def _enable_network_interface(self, device, ip, broadcast): - return '' + if len(broadcast) > 0: + activeIP_str = 'ip addr add %s broadcast %s dev %s\n' % (ip, + broadcast, device) + else: + activeIP_str = 'ip addr add %s dev %s\n' % (ip, device) + activeIP_str += 'ip link set dev %s up\n' % device + return activeIP_str def _get_clean_command(self): files = os.path.join(self._get_network_file_path(), @@ -972,24 +912,40 @@ def get_volume_detach_configuration_cmds(self, fcp_list, target_wwpns, return content -class sles11(sles): - def get_znetconfig_contents(self): - return '\n'.join(('cio_ignore -R', - 'znetconf -R -n', - 'sleep 2', - 'udevadm trigger', - 'udevadm settle', - 'sleep 2', - 'znetconf -A', - 'service network restart', - 'cio_ignore -u')) +class sles12(sles): + def _get_network_file_path(self): + return '/etc/sysconfig/network/' - def create_active_net_interf_cmd(self): - return 'service zvmguestconfigure start' + def _get_device_filename(self, vdev): + return 'ifcfg-eth' + str(vdev).zfill(4) + def _get_all_device_filename(self): + return 'ifcfg-eth*' -class sles12(sles): - def get_znetconfig_contents(self): + def _get_cfg_str(self, device, method, broadcast_v4, gateway_v4, ip_v4, + netmask_v4, address_read, subchannels, dns_v4, mtu): + cfg_str = "BOOTPROTO=\'%s\'\n" % method + if method == 'static': + cfg_str += "IPADDR=\'%s\'\n" % ip_v4 + cfg_str += "NETMASK=\'%s\'\n" % netmask_v4 + cfg_str += "BROADCAST=\'%s\'\n" % broadcast_v4 + cfg_str += "STARTMODE=\'onboot\'\n" + cfg_str += ("NAME=\'OSA Express Network card (%s)\'\n" % + address_read) + cfg_str += "MTU=\'%s\'\n" % mtu + if (dns_v4 is not None) and (len(dns_v4) > 0): + self.dns_v4 = dns_v4 + else: + self.dns_v4 = None + return cfg_str + + def _get_route_str(self, method, gateway_v4): + route_str = '' + if method == 'static': + route_str = 'default %s - -\n' % gateway_v4 + return route_str + + def get_znetconfig_contents(self, vdev_list): remove_route = 'rm -f %s/ifroute-eth*' % self._get_network_file_path() return '\n'.join(('cio_ignore -R', 'znetconf -R -n', @@ -1002,44 +958,9 @@ def get_znetconfig_contents(self): 'cio_ignore -u', 'wicked ifreload all')) - def get_scp_string(self, root, fcp, wwpn, lun): - return ("=root=%(root)s zfcp.allow_lun_scan=0 " - "zfcp.device=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s") % { - 'root': root, 'fcp': fcp, 'wwpn': wwpn, 'lun': lun} - - def get_zipl_script_lines(self, image, ramdisk, root, fcp, wwpn, lun): - return ['#!/bin/bash\n', - ('echo -e "[defaultboot]\\n' - 'default=boot-from-volume\\n' - '[boot-from-volume]\\n' - 'image=%(image)s\\n' - 'target = /boot/zipl\\n' - 'ramdisk=%(ramdisk)s\\n' - 'parameters=\\"root=%(root)s ' - 'zfcp.device=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s ' - 'zfcp.allow_lun_scan=0\\""' - '>/etc/zipl_volume.conf\n' - 'mkinitrd\n' - 'zipl -c /etc/zipl_volume.conf') - % {'image': image, 'ramdisk': ramdisk, 'root': root, - 'fcp': fcp, 'wwpn': wwpn, 'lun': lun}] - - def create_active_net_interf_cmd(self): - return 'systemctl start zvmguestconfigure.service' - - def _enable_network_interface(self, device, ip, broadcast): - if len(broadcast) > 0: - activeIP_str = 'ip addr add %s broadcast %s dev %s\n' % (ip, - broadcast, device) - else: - activeIP_str = 'ip addr add %s dev %s\n' % (ip, device) - activeIP_str += 'ip link set dev %s up\n' % device - return activeIP_str - class sles15(sles12): - """docstring for sles15""" - def get_znetconfig_contents(self): + def get_znetconfig_contents(self, vdev_list): remove_route = 'rm -f %s/ifroute-eth*' % self._get_network_file_path() replace_var = 'NETCONFIG_DNS_STATIC_SERVERS' replace_file = '/etc/sysconfig/network/config' @@ -1077,6 +998,53 @@ def get_znetconfig_contents(self): 'wicked ifreload all')) +class sles16(sles): + def _get_network_file_path(self): + return '/etc/NetworkManager/system-connections/' + + def _get_cfg_str(self, device, method, broadcast_v4, gateway_v4, ip_v4, + netmask_v4, address_read, subchannels, dns_v4, mtu): + # TODO(eric): SUPPORT FIXED ADDRESS AND OTHER PARAMETERS + return '\n'.join(('[connection]', + 'id=' + device, + 'type=ethernet', + 'interface-name=' + device, + 'autoconnect=true', + '', + '[ipv4]', + 'method=auto', + '', + '[ipv6]', + 'method=auto', + '')) + + def _get_route_str(self, method, gateway_v4): + return '' + + def _get_device_filename(self, vdev): + return 'eth' + str(vdev).zfill(4) + '.nmconnection' + + def _get_all_device_filename(self): + return 'eth*.nmconnection' + + def get_znetconfig_contents(self, vdev_list): + znetcfg = '\n'.join(('cio_ignore -R', + 'znetconf -R -n', + 'sleep 2', + 'udevadm trigger', + 'udevadm settle', + 'sleep 2', + 'znetconf -A', + 'cio_ignore -u', + '')) + for vdev in vdev_list: + device = self._get_device_name(vdev) + znetcfg += '\n'.join(('chmod go-r /etc/NetworkManager/system-connections/' + device + '.nmconnection', + 'nmcli connection reload', + 'nmcli connection up ' + device)) + return znetcfg + + class ubuntu(LinuxDist): def create_network_configuration_files(self, file_path, guest_networks, first, active=False): @@ -1106,38 +1074,70 @@ def create_network_configuration_files(self, file_path, guest_networks, 'nic_vdev': '1004', 'mac_addr': '02:00:00:ab:cd:ef'} ] + :returns cfg_files: the network interface configuration file name + and file content + cmd_strings: shell command, helps to enable the network + interface, will be put into znetconfig file + clean_cmd: if first is true, it is used to erase the previous + network interface configuration, will be put into + invokeScript file + net_enable_cmd: commands to enable the new network interface + vdev_list: list of vdevs of the new network interfaces """ cfg_files = [] + vdev_list = [] cmd_strings = '' network_config_file_name = self._get_network_file() - network_cfg_str = 'auto lo\n' - network_cfg_str += 'iface lo inet loopback\n' net_enable_cmd = '' if first: clean_cmd = self._get_clean_command() else: clean_cmd = '' - network_cfg_str = '' + device_cfg = {} for idx, network in enumerate(guest_networks): # Mark 1st network in guest_networks as primary network['primary'] = True if idx == 0 else False + base_vdev = network['nic_vdev'].lower() - network_hw_config_fname = self._get_device_filename(base_vdev) - network_hw_config_str = self._get_network_hw_config_str(base_vdev) - cfg_files.append((network_hw_config_fname, network_hw_config_str)) - (cfg_str, dns_str) = self._generate_network_configuration(network, + vdev_list.append(base_vdev) + device = self._get_device_name(base_vdev) + + device_cfg_str = self._generate_network_configuration(network, base_vdev) - LOG.debug('Network configure file content is: %s', cfg_str) - network_cfg_str += cfg_str - if len(dns_str) > 0: - network_cfg_str += dns_str + device_cfg[device] = device_cfg_str + # For Ubuntu20 and Ubuntu 22, when there are multi NICs, + # there is still 1 network config yml file, all NICs are + # written in this file, example is: + # network: + # ethernets: + # enc1000: + # addresses: + # - 172.26.54.179/17 + # gateway4: 172.26.0.1 + # mtu: '1500' + # enc1003: + # addresses: + # - 192.168.6.5/24 + # gateway4: '192.168.6.1' + # mtu: '1500' + # version: 2 + cfg_str = {'network': + {'version': 2, + 'ethernets': device_cfg + } + } + LOG.debug('Network configure file content is: %s', cfg_str) + if first: - cfg_files.append((network_config_file_name, network_cfg_str)) + cfg_files.append((network_config_file_name, cfg_str)) else: - cmd_strings = ('echo "%s" >>%s\n' % (network_cfg_str, - network_config_file_name)) - return cfg_files, cmd_strings, clean_cmd, net_enable_cmd + # TODO(haolp): create interface with cmd_strings after VM deployed + raise Exception('Ubuntu is not supported to create interface' + 'after VM deployed.') + + return cfg_files, cmd_strings, clean_cmd, net_enable_cmd, vdev_list + def get_network_configuration_files(self, vdev): vdev = vdev.lower() @@ -1168,7 +1168,7 @@ def _delete_vdev_info(self, vdev): return cmd def _get_network_file(self): - return '/etc/network/interfaces' + return '/etc/netplan/00-zvmguestconfigure-config.yaml' def _get_cfg_str(self, device, method, broadcast_v4, gateway_v4, ip_v4, netmask_v4, mtu): @@ -1183,44 +1183,45 @@ def _get_cfg_str(self, device, method, broadcast_v4, gateway_v4, ip_v4, return cfg_str def _generate_network_configuration(self, network, vdev): - method = 'static' ip_v4 = dns_str = gateway_v4 = '' - netmask_v4 = broadcast_v4 = '' - if (('method' in network.keys()) and - (network['method'] is not None)): - method = network['method'] - + cidr = mtu = '' + dns_v4 = [] if (('ip_addr' in network.keys()) and (network['ip_addr'] is not None)): ip_v4 = network['ip_addr'] if (('gateway_addr' in network.keys()) and - (network['gateway_addr'] is not None) and network['primary']): + (network['gateway_addr'] is not None)): gateway_v4 = network['gateway_addr'] if (('dns_addr' in network.keys()) and (network['dns_addr'] is not None) and (len(network['dns_addr']) > 0)): for dns in network['dns_addr']: - dns_str += 'dns-nameservers ' + dns + '\n' + dns_str += 'nameserver ' + dns + '\n' + dns_v4.append(dns) if (('cidr' in network.keys()) and (network['cidr'] is not None)): - ip_cidr = network['cidr'] - netmask_v4 = str(netaddr.IPNetwork(ip_cidr).netmask) - broadcast_v4 = str(netaddr.IPNetwork(ip_cidr).broadcast) - if broadcast_v4 == 'None': - broadcast_v4 = '' + cidr = network['cidr'].split('/')[1] if (('mtu' in network.keys()) and (network['mtu'] is not None)): mtu = str(network['mtu']) - device = self._get_device_name(vdev) - cfg_str = self._get_cfg_str(device, method, broadcast_v4, gateway_v4, - ip_v4, netmask_v4, mtu) - - return cfg_str, dns_str + if dns_v4: + cfg_str = {'addresses': [ip_v4 + '/' + cidr], + 'gateway4': gateway_v4, + 'mtu': mtu, + 'nameservers': + {'addresses': dns_v4} + } + else: + cfg_str = {'addresses': [ip_v4 + '/' + cidr], + 'gateway4': gateway_v4, + 'mtu': mtu + } + return cfg_str def _get_route_str(self, method, gateway_v4): return '' @@ -1238,7 +1239,7 @@ def _get_dns_filename(self): return '' def _get_device_filename(self, device_num): - return '/etc/sysconfig/hardware/config-ccw-0.0.' + str(device_num) + return '/etc/netplan/' + str(device_num) + '.yaml' def _get_network_hw_config_str(self, base_vdev): ccwgroup_chans_str = ' '.join(( @@ -1249,9 +1250,9 @@ def _get_network_hw_config_str(self, base_vdev): 'QETH_OPTIONS=layer2')) def _get_network_file_path(self): - pass + return '/etc/netplan/' - def get_znetconfig_contents(self): + def get_znetconfig_contents(self, vdev_list): return '\n'.join(('cio_ignore -R', 'znetconf -R -n', 'sleep 2', @@ -1259,7 +1260,7 @@ def get_znetconfig_contents(self): 'udevadm settle', 'sleep 2', 'znetconf -A', - '/etc/init.d/networking restart', + 'netplan apply', 'cio_ignore -u')) def _get_udev_configuration(self, device, dev_channel): @@ -1366,152 +1367,8 @@ def get_volume_detach_configuration_cmds(self, fcp_list, target_wwpns, return content -class ubuntu16(ubuntu): - pass - - class ubuntu20(ubuntu): - def _get_device_filename(self, device_num): - return '/etc/netplan/' + str(device_num) + '.yaml' - - def _get_network_file(self): - return '/etc/netplan/00-zvmguestconfigure-config.yaml' - - def _get_network_file_path(self): - return '/etc/netplan/' - - def get_znetconfig_contents(self): - return '\n'.join(('cio_ignore -R', - 'znetconf -R -n', - 'sleep 2', - 'udevadm trigger', - 'udevadm settle', - 'sleep 2', - 'znetconf -A', - 'netplan apply', - 'cio_ignore -u')) - - def create_network_configuration_files(self, file_path, guest_networks, - first, active=False): - """Generate network configuration files for guest VM - :param list guest_networks: a list of network info for the guest. - It has one dictionary that contain some of the below keys for - each network, the format is: - {'method': (str) NIC initialization method, - 'ip_addr': (str) IP address, - 'dns_addr': (list) DNS addresses, - 'gateway_addr': (str) gateway address, - 'cidr': (str) CIDR format - 'nic_vdev': (str) VDEV of the NIC} - - Example for guest_networks: - [{'ip_addr': '192.168.95.10', - 'dns_addr': ['9.0.2.1', '9.0.3.1'], - 'gateway_addr': '192.168.95.1', - 'cidr': "192.168.95.0/24", - 'nic_vdev': '1000'}, - {'ip_addr': '192.168.96.10', - 'dns_addr': ['9.0.2.1', '9.0.3.1'], - 'gateway_addr': '192.168.96.1', - 'cidr': "192.168.96.0/24", - 'nic_vdev': '1003'}, - {'method': 'dhcp' - 'nic_vdev': '1004', - 'mac_addr': '02:00:00:ab:cd:ef'} - ] - """ - cfg_files = [] - cmd_strings = '' - network_config_file_name = self._get_network_file() - net_enable_cmd = '' - if first: - clean_cmd = self._get_clean_command() - else: - clean_cmd = '' - - device_cfg = {} - for idx, network in enumerate(guest_networks): - # Mark 1st network in guest_networks as primary - network['primary'] = True if idx == 0 else False - - base_vdev = network['nic_vdev'].lower() - device = self._get_device_name(base_vdev) - - device_cfg_str = self._generate_network_configuration(network, - base_vdev) - device_cfg[device] = device_cfg_str - # For Ubuntu20 and Ubuntu 22, when there are multi NICs, - # there is still 1 network config yml file, all NICs are - # written in this file, example is: - # network: - # ethernets: - # enc1000: - # addresses: - # - 172.26.54.179/17 - # gateway4: 172.26.0.1 - # mtu: '1500' - # enc1003: - # addresses: - # - 192.168.6.5/24 - # gateway4: '192.168.6.1' - # mtu: '1500' - # version: 2 - cfg_str = {'network': - {'version': 2, - 'ethernets': device_cfg - } - } - LOG.debug('Network configure file content is: %s', cfg_str) - - if first: - cfg_files.append((network_config_file_name, cfg_str)) - else: - # TODO: create interface with cmd_strings after VM deployed - raise Exception('Ubuntu20 is not supported to create interface' - 'after VM deployed.') - - return cfg_files, cmd_strings, clean_cmd, net_enable_cmd - - def _generate_network_configuration(self, network, vdev): - ip_v4 = dns_str = gateway_v4 = '' - cidr = mtu = '' - dns_v4 = [] - if (('ip_addr' in network.keys()) and - (network['ip_addr'] is not None)): - ip_v4 = network['ip_addr'] - - if (('gateway_addr' in network.keys()) and - (network['gateway_addr'] is not None)): - gateway_v4 = network['gateway_addr'] - - if (('dns_addr' in network.keys()) and - (network['dns_addr'] is not None) and - (len(network['dns_addr']) > 0)): - for dns in network['dns_addr']: - dns_str += 'nameserver ' + dns + '\n' - dns_v4.append(dns) - - if (('cidr' in network.keys()) and - (network['cidr'] is not None)): - cidr = network['cidr'].split('/')[1] - - if (('mtu' in network.keys()) and - (network['mtu'] is not None)): - mtu = str(network['mtu']) - - if dns_v4: - cfg_str = {'addresses': [ip_v4 + '/' + cidr], - 'gateway4': gateway_v4, - 'mtu': mtu, - 'nameservers': - {'addresses': dns_v4} - } - else: - cfg_str = {'addresses': [ip_v4 + '/' + cidr], - 'gateway4': gateway_v4, - 'mtu': mtu - } - return cfg_str + pass class ubuntu22(ubuntu20): @@ -1519,10 +1376,12 @@ class ubuntu22(ubuntu20): class ubuntu24(ubuntu20): + # TODO(eric): ADD MODERN DISTRIBUTIONS pass class ubuntu25(ubuntu20): + # TODO(eric): ADD MODERN DISTRIBUTIONS pass @@ -1532,18 +1391,18 @@ def get_linux_dist(self, os_version): return globals()[distro + release] def _parse_release(self, os_version, distro, remain): - supported = {'rhel': ['6', '7', '8', '9', '10'], - 'sles': ['11', '12', '15'], - 'ubuntu': ['16', '20', '22', '24', '25'], + supported = {'rhel': ['7', '8', '9', '10'], + 'sles': ['12', '15', '16'], + 'ubuntu': ['20', '22', '24', '25'], 'rhcos': ['4']} releases = supported[distro] for r in releases: if remain.startswith(r): return r - else: - msg = 'Can not handle os: %s' % os_version - raise exception.ZVMException(msg=msg) + + msg = 'Can not handle os: %s' % os_version + raise exception.ZVMException(msg=msg) def parse_dist(self, os_version): """Separate os and version from os_version. @@ -1552,14 +1411,14 @@ def parse_dist(self, os_version): ('rhel', x.y) and ('sles', x.y) where x.y may not be digits """ supported = {'rhel': ['rhel', 'redhat', 'red hat'], - 'sles': ['suse', 'sles'], - 'ubuntu': ['ubuntu'], - 'rhcos': ['rhcos', 'coreos', 'red hat coreos']} + 'sles': ['suse', 'sles'], + 'ubuntu': ['ubuntu'], + 'rhcos': ['rhcos', 'coreos', 'red hat coreos']} os_version = os_version.lower() for distro, patterns in supported.items(): for i in patterns: if os_version.startswith(i): - # Not guarrentee the version is digital + # No guarantee the version is a number remain = os_version.split(i, 2)[1] release = self._parse_release(os_version, distro, remain) return distro, release diff --git a/zvmsdk/networkops.py b/zvmsdk/networkops.py index 4c3ce7f39..dcc5a4db1 100644 --- a/zvmsdk/networkops.py +++ b/zvmsdk/networkops.py @@ -159,7 +159,8 @@ def _generate_network_doscript(self, userid, os_version, network_info, first, active=active) (net_conf_files, net_conf_cmds, - clean_cmd, net_enable_cmd) = files_and_cmds + clean_cmd, net_enable_cmd, + vdev_list) = files_and_cmds # Add network configure files to path_contents if len(net_conf_files) > 0: @@ -171,6 +172,7 @@ def _generate_network_doscript(self, userid, os_version, network_info, net_cmd_file = self._create_znetconfig(net_conf_cmds, linuxdist, net_enable_cmd, + vdev_list, active=active) # Add znetconfig file to path_contents if len(net_cmd_file) > 0: @@ -206,12 +208,12 @@ def _add_yaml_file(self, file_name, data): yaml.dump(data, stream) def _create_znetconfig(self, commands, linuxdist, append_cmd, - active=False): + vdev_list, active=False): LOG.debug('Creating znetconfig file') if active: znet_content = linuxdist.get_simple_znetconfig_contents() else: - znet_content = linuxdist.get_znetconfig_contents() + znet_content = linuxdist.get_znetconfig_contents(vdev_list) net_cmd_file = [] if znet_content: if len(commands) == 0: @@ -292,7 +294,7 @@ def delete_network_configuration(self, userid, os_version, vdev, cmd += linuxdist.delete_vdev_info(vdev) net_cmd_file = self._create_znetconfig(cmd, linuxdist, '', - active=active) + [vdev], active=active) del_file = 'DEL%s.sh' % str(vdev).zfill(4) file_name = os.path.join(network_file_path, del_file) file_content = net_cmd_file[0][1] diff --git a/zvmsdk/sdkwsgi/validation/parameter_types.py b/zvmsdk/sdkwsgi/validation/parameter_types.py index 7e3245bf3..1936ea9ce 100644 --- a/zvmsdk/sdkwsgi/validation/parameter_types.py +++ b/zvmsdk/sdkwsgi/validation/parameter_types.py @@ -1,6 +1,7 @@ # Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 +# Copyright 2025 Contributors to the Feilong Project # Copyright 2017,2022 IBM Corp. # Copyright 2013 NEC Corporation. # All rights reserved. @@ -444,34 +445,40 @@ def valid_char(char): } } -# For redhat linux, it will match rhelX, rhelX.Y, redhatX, redhatX.Y, -# where X is 6 or 7, Y is 0 to 9, all case insensitive -# For suse linux, it will match slesX, slesX.Y, slesXspY, suseX, -# suseX.Y, suseXspY, where X is 11 or 12, Y is 0 to 9, -# all case insensitive -# For ubuntu linux, it will match ubuntuX, ubuntuX.Y, ubuntuX.Y.Z, -# where X is 16, Y is 01 to 10, Z is 0 to 9, such as ubuntu16.04.3, -# all case insensitive -# For red hat cores linux, it will match rhcosX, rhcosX.Y and rhcosX.Y.Z, -# where X is 4, such as rhcos4, rhcos4.6, rhcos4.6.8, -# all case insensitive +# For Red Hat Enterprise Linux, +# it will match rhelX, rhelX.Y, redhatX, redhatX.Y, +# where X is 7, 8 or 9, Y is 0 to 9, all case insensitive +# +# For SUSE Linux Enterprise Server, +# it will match slesX, slesX.Y, slesXspY, suseX, suseX.Y, suseXspY, +# where X is 12, 15 or 16, Y is 0 to 9, all case insensitive +# +# For Ubuntu Linux, +# it will match ubuntuX, ubuntuX.Y, ubuntuX.Y.Z, +# where X is 20, 22, or 24, Y is 01 to 12, Z is 0 to 9, +# such as ubuntu16.04.3, all case insensitive +# +# For Red Hat CoreOS Linux, +# it will match rhcosX, rhcosX.Y and rhcosX.Y.Z, +# where X is 4, +# such as rhcos4, rhcos4.12, rhcos4.7.23, all case insensitive os_version = { 'oneOf': [ {'type': 'string', 'pattern': - '^((r|R)(h|H)(e|E)(l|L))(6|7|8|9|10){1}([.][0-9]{1,2})?$'}, + '^((r|R)(h|H)(e|E)(l|L))(7|8|9|10){1}([.][0-9]{1,2})?$'}, {'type': 'string', 'pattern': - '^((r|R)(e|E)(d|D)(h|H)(a|A)(t|T))(6|7){1}([.][0-9]{1,2})?$'}, + '^((r|R)(e|E)(d|D)(h|H)(a|A)(t|T))(7|8|9){1}([.][0-9]{1,2})?$'}, {'type': 'string', 'pattern': - '^((s|S)(l|L)(e|E)(s|S))(11|12|15){1}(([.]|((s|S)(p|P)))[0-9])?$'}, + '^((s|S)(l|L)(e|E)(s|S))(12|15|16){1}(([.]|((s|S)(p|P)))[0-9])?$'}, {'type': 'string', 'pattern': - '^((s|S)(u|U)(s|S)(e|E))(11|12|15){1}(([.]|((s|S)(p|P)))[0-9])?$'}, + '^((s|S)(u|U)(s|S)(e|E))(12|15|16){1}(([.]|((s|S)(p|P)))[0-9])?$'}, {'type': 'string', 'pattern': - '^((u|U)(b|B)(u|U)(n|N)(t|T)(u|U))(16|20|22|24|25){1}([.][0-9]{2})?([.][0-9])?$'}, + '^((u|U)(b|B)(u|U)(n|N)(t|T)(u|U))(20|22|24|25){1}([.][0-9]{2})?([.][0-9])?$'}, {'type': 'string', 'pattern': '^((r|R)(h|H)(c|C)(o|O)(s|S))(4){1}([.][0-9]{1,2})?([.][0-9]{1,2})?$'} @@ -487,7 +494,7 @@ def valid_char(char): 'type': 'object', 'properties': { 'os_version': os_version, - # md5 shoule be 32 hexadeciaml numbers + # md5 should be 32 hexadecimal digits 'md5sum': {'type': 'string', 'pattern': '^[0-9a-fA-F]{32}$'}, 'disk_type': disk_type }, diff --git a/zvmsdk/smtclient.py b/zvmsdk/smtclient.py index 11c31071c..d8702a01f 100644 --- a/zvmsdk/smtclient.py +++ b/zvmsdk/smtclient.py @@ -1,6 +1,7 @@ # Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 +# Copyright 2025 Contributors to the Feilong Project # Copyright 2017,2024 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -1438,35 +1439,6 @@ def guest_get_os_version(self, userid): version = eval(version) os_version = '%s%s' % (distro, version) - elif '/etc/redhat-release' in release_file: - # The output looks like: - # "Red Hat Enterprise Linux Server release 6.7 (Santiago)" - distro = 'rhel' - release_info = self.execute_cmd(userid, 'grep -v ^# /etc/redhat-release') - distro_version = release_info[0].split()[6] - os_version = ''.join((distro, distro_version)) - - elif '/etc/SuSE-release' in release_file: - # The output for this file looks like: - # SUSE Linux Enterprise Server 11 (s390x) - # VERSION = 11 - # PATCHLEVEL = 3 - distro = 'sles' - release_info = self.execute_cmd(userid, 'grep -v ^# /etc/SuSE-release') - LOG.debug('OS release info is %s' % release_info) - release_version = '.'.join((release_info[1].split('=')[1].strip(), - release_info[2].split('=')[1].strip())) - os_version = ''.join((distro, release_version)) - - elif '/etc/system-release' in release_file: - # For some rhel6.7 system, it only have system-release file and - # the output looks like: - # "Red Hat Enterprise Linux Server release 6.7 (Santiago)" - distro = 'rhel' - release_info = self.execute_cmd(userid, 'grep -v ^# /etc/system-release') - distro_version = release_info[0].split()[6] - os_version = ''.join((distro, distro_version)) - return os_version except Exception as e: if e.results['rc'] in (1, 4): diff --git a/zvmsdk/tests/fvt/README.rst b/zvmsdk/tests/fvt/README.rst index f051b5f0a..b4a3b5cb7 100644 --- a/zvmsdk/tests/fvt/README.rst +++ b/zvmsdk/tests/fvt/README.rst @@ -28,9 +28,7 @@ options: - images: Test image file path plus operating system version, separated by ':'. Several images can be specified to test, separated by ','. Sample value: - - * "/var/lib/zvmsdk/images/netboot/rhel6.7/46a4aea3_54b6_4b1c_8a49_01f302e70c60:rhel6.7" - * "/var/lib/zvmsdk/images/netboot/rhel6.7/test_image1:rhel6.7, /var/lib/zvmsdk/images/netboot/sles12/test_image2:sles12" + '/var/lib/zvmsdk/images/netboot/rhel8.9/test_image1:rhel8.9, /var/lib/zvmsdk/images/netboot/sles15/test_image2:sles15' - vswitch: The vswitch that test guests connect to. diff --git a/zvmsdk/tests/fvt/api_templates/test_image_create_req.tpl b/zvmsdk/tests/fvt/api_templates/test_image_create_req.tpl index 62a7e774e..fff03bb8e 100644 --- a/zvmsdk/tests/fvt/api_templates/test_image_create_req.tpl +++ b/zvmsdk/tests/fvt/api_templates/test_image_create_req.tpl @@ -3,7 +3,7 @@ { "image_name": "image1", "url": "file:///image1", - "image_meta": {"os_version": "rhel6.2"}, + "image_meta": {"os_version": "rhel8.9"}, "remote_host": "nova@9.x.x.x" } } diff --git a/zvmsdk/tests/fvt/api_templates/test_image_export.tpl b/zvmsdk/tests/fvt/api_templates/test_image_export.tpl index cbb096d88..c93b65e0b 100644 --- a/zvmsdk/tests/fvt/api_templates/test_image_export.tpl +++ b/zvmsdk/tests/fvt/api_templates/test_image_export.tpl @@ -6,6 +6,6 @@ "errmsg": "", "output": {"image_name": "name1", "image_path": "/tmp/images/name1", - "os_version": "rhel6", + "os_version": "rhel8", "md5sum": "121212314231"} } diff --git a/zvmsdk/tests/fvt/api_templates/test_image_export_res.tpl b/zvmsdk/tests/fvt/api_templates/test_image_export_res.tpl index cbb096d88..c93b65e0b 100644 --- a/zvmsdk/tests/fvt/api_templates/test_image_export_res.tpl +++ b/zvmsdk/tests/fvt/api_templates/test_image_export_res.tpl @@ -6,6 +6,6 @@ "errmsg": "", "output": {"image_name": "name1", "image_path": "/tmp/images/name1", - "os_version": "rhel6", + "os_version": "rhel8", "md5sum": "121212314231"} } diff --git a/zvmsdk/tests/fvt/test_guest.py b/zvmsdk/tests/fvt/test_guest.py index a452dd6d7..90484a742 100644 --- a/zvmsdk/tests/fvt/test_guest.py +++ b/zvmsdk/tests/fvt/test_guest.py @@ -1,7 +1,7 @@ -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - -# Copyright 2017,2018 IBM Corp. +# +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017,2018 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -419,12 +419,12 @@ def test_guest_vswitch_couple_uncouple_userid_not_exist(self): def test_guest_vif_create_not_exist(self): resp = self.client.guest_create_network_interface('notexist', - 'rhel6.7', []) + 'rhel8.9', []) self.assertEqual(404, resp.status_code) def test_guest_vif_delete_not_exist(self): resp = self.client.guest_delete_network_interface(userid='notexist', - os_version='rhel6.7') + os_version='rhel8.9') self.assertEqual(404, resp.status_code) def test_guest_nic_query_not_exist(self): @@ -636,7 +636,7 @@ def test_guest_create_deploy_capture_delete(self, case_name, resp.content) # Use softstop instend of stop to avoid the data lose with guest_stop - # when testing the sles12 image. + # when testing the sles image. resp = self.client.guest_softstop(userid) self.assertEqual(200, resp.status_code) self.assertTrue(self.utils.wait_until_guest_in_power_state(userid, diff --git a/zvmsdk/tests/fvt/test_restclient.py b/zvmsdk/tests/fvt/test_restclient.py index 4c5a5d1ab..4d664d13c 100644 --- a/zvmsdk/tests/fvt/test_restclient.py +++ b/zvmsdk/tests/fvt/test_restclient.py @@ -1,7 +1,7 @@ -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - -# Copyright 2017,2018 IBM Corp. +# +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017,2018 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -88,7 +88,7 @@ def _guest_stop(self, conn_type): def _guest_deploy(self, conn_type, vdev=None, image=None): api_name = 'guest_deploy' if image is None: - image = 'rhel67eckd_small_1100cyl.img' + image = 'rhel89eckd_small_1100cyl.img' if vdev is None: vdev = '100' if conn_type == CONN_REST: @@ -105,7 +105,7 @@ def _image_create(self, conn_type): image_fname = 'rhel67eckd_small_1100cyl.img' image_fpath = self.image_path url = "file://" + image_fpath - image_meta = {"os_version": "rhel6.7"} + image_meta = {"os_version": "rhel8.9"} api_name = 'image_import' if conn_type == CONN_REST: res = self.restclient.send_request(api_name, image_fname, url, @@ -137,7 +137,7 @@ def _guest_delete_nic(self, conn_type, vdev="1000"): def _guest_create_network_interface(self, conn_type): api_name = 'guest_create_network_interface' - os_version = "rhel6.7" + os_version = "rhel8.9" guest_network = [{'ip_addr': '192.168.95.10', 'dns_addr': ['9.0.2.1', '9.0.3.1'], 'gateway_addr': '192.168.95.1', @@ -156,7 +156,7 @@ def _guest_create_network_interface(self, conn_type): def _guest_delete_network_interface(self, conn_type, vdev="3000"): api_name = 'guest_delete_network_interface' - os_version = "rhel6.7" + os_version = "rhel8.9" if conn_type == CONN_REST: userid = self.userid_rest res = self.restclient.send_request(api_name, userid, os_version, diff --git a/zvmsdk/tests/unit/base.py b/zvmsdk/tests/unit/base.py index c7a3c61a8..8d10cef1c 100755 --- a/zvmsdk/tests/unit/base.py +++ b/zvmsdk/tests/unit/base.py @@ -1,7 +1,7 @@ -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - -# Copyright 2017 IBM Corp. +# +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain diff --git a/zvmsdk/tests/unit/sdkwsgi/handlers/test_guest.py b/zvmsdk/tests/unit/sdkwsgi/handlers/test_guest.py index 5362c5fb2..8fd931cd1 100644 --- a/zvmsdk/tests/unit/sdkwsgi/handlers/test_guest.py +++ b/zvmsdk/tests/unit/sdkwsgi/handlers/test_guest.py @@ -1,7 +1,7 @@ -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - -# Copyright 2017,2018 IBM Corp. +# +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017,2018 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -839,14 +839,14 @@ def test_guest_create_nic_invalid_mac_addr(self): @mock.patch.object(util, 'wsgi_path_item') @mock.patch('zvmconnector.connector.ZVMConnector.send_request') def test_guest_create_network_interface(self, mock_interface, mock_userid): - os_version = 'rhel6' + os_version = 'rhel8' guest_networks = [{'ip_addr': '192.168.12.34', 'dns_addr': ['9.1.2.3'], 'gateway_addr': '192.168.95.1', 'cidr': '192.168.95.0/24', 'nic_vdev': '1000', 'mac_addr': '02:00:00:12:34:56'}] - bstr = """{"interface": {"os_version": "rhel6", + bstr = """{"interface": {"os_version": "rhel8", "guest_networks": [ {"ip_addr": "192.168.12.34", "dns_addr": ["9.1.2.3"], @@ -870,7 +870,7 @@ def test_guest_create_network_interface(self, mock_interface, mock_userid): @mock.patch('zvmconnector.connector.ZVMConnector.send_request') def test_guest_create_network_interface_OSA(self, mock_interface, mock_userid): - os_version = 'rhel6' + os_version = 'rhel8' guest_networks = [{'ip_addr': '192.168.12.34', 'dns_addr': ['9.1.2.3'], 'gateway_addr': '192.168.95.1', @@ -878,7 +878,7 @@ def test_guest_create_network_interface_OSA(self, mock_interface, 'nic_vdev': '1000', 'mac_addr': '02:00:00:12:34:56', 'osa_device': 'AABB'}] - bstr = """{"interface": {"os_version": "rhel6", + bstr = """{"interface": {"os_version": "rhel8", "guest_networks": [ {"ip_addr": "192.168.12.34", "dns_addr": ["9.1.2.3"], @@ -903,9 +903,9 @@ def test_guest_create_network_interface_OSA(self, mock_interface, @mock.patch.object(util, 'wsgi_path_item') @mock.patch('zvmconnector.connector.ZVMConnector.send_request') def test_guest_delete_network_interface(self, mock_interface, mock_userid): - os_version = 'rhel6' + os_version = 'rhel8' vdev = '1000' - bstr = """{"interface": {"os_version": "rhel6", + bstr = """{"interface": {"os_version": "rhel8", "vdev": "1000", "active": "True"}}""" self.req.body = bstr mock_userid.return_value = FAKE_USERID @@ -1237,7 +1237,7 @@ def test_guests_get_nic_info_with_vswitch(self, mock_interface): def test_guest_create_network_interface_invalid_cidr(self, mock_userid): # / not in cidr - bstr = """{"interface": {"os_version": "rhel6", + bstr = """{"interface": {"os_version": "rhel8", "guest_networks": [ {"ip_addr": "192.168.12.34", "dns_addr": ["9.1.2.3"], diff --git a/zvmsdk/tests/unit/test_api.py b/zvmsdk/tests/unit/test_api.py index 5efd9af5d..0aa6a8608 100644 --- a/zvmsdk/tests/unit/test_api.py +++ b/zvmsdk/tests/unit/test_api.py @@ -1,7 +1,7 @@ -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - -# Copyright 2017,2022 IBM Corp. +# +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017,2022 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -153,7 +153,7 @@ def test_guest_deploy(self, guest_deploy): def test_image_import(self, image_import): image_name = '95a4da37-9f9b-4fb2-841f-f0bb441b7544' url = "file:///install/temp/test.img" - image_meta = {'os_version': "rhel6.7"} + image_meta = {'os_version': "rhel8.9"} self.api.image_import(image_name, url, image_meta) image_import.assert_called_once_with(image_name, url, image_meta, diff --git a/zvmsdk/tests/unit/test_database.py b/zvmsdk/tests/unit/test_database.py index 76cf78afe..de2f77f4c 100755 --- a/zvmsdk/tests/unit/test_database.py +++ b/zvmsdk/tests/unit/test_database.py @@ -1,7 +1,7 @@ -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - -# Copyright 2017, 2023 IBM Corp. +# +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017, 2023 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -2322,7 +2322,7 @@ def tearDownClass(cls): def test_image_add_query_delete_record(self): imagename = 'test' - imageosdistro = 'rhel6.5' + imageosdistro = 'rhel8.9' md5sum = 'c73ce117eef8077c3420bfc8f473ac2f' disk_size_units = '3338:CYL' image_size_in_bytes = '5120000' @@ -2336,7 +2336,7 @@ def test_image_add_query_delete_record(self): self.assertEqual(1, len(image_record)) self.assertListEqual( [{'imagename': u'test', - 'imageosdistro': u'rhel6.5', + 'imageosdistro': u'rhel8.9', 'md5sum': u'c73ce117eef8077c3420bfc8f473ac2f', 'disk_size_units': u'3338:CYL', 'image_size_in_bytes': u'5120000', @@ -2351,7 +2351,7 @@ def test_image_add_query_delete_record(self): def test_image_add_record_with_existing_imagename(self): imagename = 'test' - imageosdistro = 'rhel6.5' + imageosdistro = 'rhel8.9' md5sum = 'c73ce117eef8077c3420bfc8f473ac2f' disk_size_units = '3338:CYL' image_size_in_bytes = '5120000' @@ -2371,7 +2371,7 @@ def test_image_add_record_with_existing_imagename(self): def test_image_query_record_multiple_image(self): imagename1 = 'testimage1' imagename2 = 'testimage2' - imageosdistro = 'rhel6.5' + imageosdistro = 'rhel8.9' md5sum = 'c73ce117eef8077c3420bfc8f473ac2f' disk_size_units = '3338:CYL' image_size_in_bytes = '5120000' @@ -2389,14 +2389,14 @@ def test_image_query_record_multiple_image(self): self.assertEqual(2, len(image_records)) self.assertListEqual( [{'imagename': u'testimage1', - 'imageosdistro': u'rhel6.5', + 'imageosdistro': u'rhel8.9', 'md5sum': u'c73ce117eef8077c3420bfc8f473ac2f', 'disk_size_units': u'3338:CYL', 'image_size_in_bytes': u'5120000', 'type': u'netboot', 'comments': None}, {'imagename': u'testimage2', - 'imageosdistro': u'rhel6.5', + 'imageosdistro': u'rhel8.9', 'md5sum': u'c73ce117eef8077c3420bfc8f473ac2f', 'disk_size_units': u'3338:CYL', 'image_size_in_bytes': u'5120000', diff --git a/zvmsdk/tests/unit/test_dist.py b/zvmsdk/tests/unit/test_dist.py index 5d2d38b47..d5397450d 100644 --- a/zvmsdk/tests/unit/test_dist.py +++ b/zvmsdk/tests/unit/test_dist.py @@ -1,7 +1,7 @@ -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - -# Copyright 2017,2021 IBM Corp. +# +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017,2021 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -14,6 +14,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + import mock import os @@ -366,18 +367,17 @@ def test_read_coreos_parameter(self, guest_path): 'enc1000:none:10.10.0.250:10.10.0.51;1000') -class SLESTestCase(base.SDKTestCase): +class SLES15TestCase(base.SDKTestCase): @classmethod def setUpClass(cls): - super(SLESTestCase, cls).setUpClass() + super(SLES15TestCase, cls).setUpClass() + cls.os_version = 'sles15' def setUp(self): - super(SLESTestCase, self).setUp() + super(SLES15TestCase, self).setUp() self.dist_manager = dist.LinuxDistManager() - self.sles11_dist = self.dist_manager.get_linux_dist('sles11')() - self.sles12_dist = self.dist_manager.get_linux_dist('sles12')() - self.sles15_dist = self.dist_manager.get_linux_dist('sles15')() + self.linux_dist = self.dist_manager.get_linux_dist(self.os_version)() def test_create_network_configuration_files(self): guest_networks = [{'ip_addr': '192.168.95.10', @@ -387,7 +387,7 @@ def test_create_network_configuration_files(self): 'mtu': 8000}] file_path = '/etc/sysconfig/network/' first = False - files_and_cmds = self.sles15_dist.create_network_configuration_files( + files_and_cmds = self.linux_dist.create_network_configuration_files( file_path, guest_networks, first, active=False) (net_conf_files, net_conf_cmds, clean_cmd, net_enable_cmd) = files_and_cmds @@ -413,7 +413,7 @@ def test_create_network_configuration_files_multi_nics(self): 'mtu': 1500}] file_path = '/etc/sysconfig/network/' first = False - files_and_cmds = self.sles15_dist.create_network_configuration_files( + files_and_cmds = self.linux_dist.create_network_configuration_files( file_path, guest_networks, first, active=False) (net_conf_files, net_conf_cmds, clean_cmd, net_enable_cmd) = files_and_cmds @@ -445,9 +445,9 @@ def test_get_volume_attach_configuration_cmds(self, get_template, multipath = True mount_point = '/dev/sdz' get_template.return_value = Template('fake template {{fcp}}') - self.sles15_dist.get_volume_attach_configuration_cmds(fcp_list, wwpns, - lun, multipath, - mount_point) + self.linux_dist.get_volume_attach_configuration_cmds(fcp_list, wwpns, + lun, multipath, + mount_point) # check function called assertions get_template.assert_called_once_with("volumeops", "sles_attach_volume.j2") @@ -470,9 +470,9 @@ def test_get_volume_detach_configuration_cmds_1(self, mount_point = '/dev/sdz' get_template.return_value = Template('fake template {{fcp}}') # connections == 2 - self.sles15_dist.get_volume_detach_configuration_cmds(fcp_list, wwpns, - lun, multipath, - mount_point, 2) + self.linux_dist.get_volume_detach_configuration_cmds(fcp_list, wwpns, + lun, multipath, + mount_point, 2) get_template.assert_called_once_with( "volumeops", "sles_detach_volume.j2") @@ -496,9 +496,9 @@ def test_get_volume_detach_configuration_cmds_2(self, mount_point = '/dev/sdz' get_template.return_value = Template('fake template {{fcp}}') # connections == 0 and is_last_volume shoud be 1 - self.sles15_dist.get_volume_detach_configuration_cmds(fcp_list, wwpns, - lun, multipath, - mount_point, 0) + self.linux_dist.get_volume_detach_configuration_cmds(fcp_list, wwpns, + lun, multipath, + mount_point, 0) get_template.assert_called_once_with( "volumeops", "sles_detach_volume.j2") @@ -509,29 +509,17 @@ def test_get_volume_detach_configuration_cmds_2(self, is_last_volume=1) -class UBUNTUTestCase(base.SDKTestCase): - - @classmethod - def setUpClass(cls): - super(UBUNTUTestCase, cls).setUpClass() - - def setUp(self): - super(UBUNTUTestCase, self).setUp() - self.dist_manager = dist.LinuxDistManager() - self.linux_dist = self.dist_manager.get_linux_dist('ubuntu16')() - self.ubuntu20_dist = self.dist_manager.get_linux_dist('ubuntu20')() - - -class UBUNTU20TestCase(base.SDKTestCase): +class UBUNTU22TestCase(base.SDKTestCase): @classmethod def setUpClass(cls): - super(UBUNTU20TestCase, cls).setUpClass() + super(UBUNTU22TestCase, cls).setUpClass() + cls.os_version = 'ubuntu22' def setUp(self): - super(UBUNTU20TestCase, self).setUp() + super(UBUNTU22TestCase, self).setUp() self.dist_manager = dist.LinuxDistManager() - self.linux_dist = self.dist_manager.get_linux_dist('ubuntu20')() + self.linux_dist = self.dist_manager.get_linux_dist(self.os_version)() def test_create_network_configuration_files(self): guest_networks = [{'ip_addr': '192.168.95.10', diff --git a/zvmsdk/tests/unit/test_smtclient.py b/zvmsdk/tests/unit/test_smtclient.py index 66455221e..336d146a0 100644 --- a/zvmsdk/tests/unit/test_smtclient.py +++ b/zvmsdk/tests/unit/test_smtclient.py @@ -1,7 +1,7 @@ -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - -# Copyright 2017,2024 IBM Corp. +# +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017,2024 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -2747,12 +2747,12 @@ def test_image_import(self, image_query, create_path, image_import, image_add_record, rename): image_name = 'testimage' url = 'file:///tmp/testdummyimg' - image_meta = {'os_version': 'rhel6.5', + image_meta = {'os_version': 'rhel8.9', 'md5sum': 'c73ce117eef8077c3420bfc8f473ac2f'} - import_image_fpath = '/home/netboot/rhel6.5/testimage/testdummyimg' - final_image_fpath = '/home/netboot/rhel6.5/testimage/0100' + import_image_fpath = '/home/netboot/rhel8.9/testimage/testdummyimg' + final_image_fpath = '/home/netboot/rhel8.9/testimage/0100' image_query.return_value = [] - create_path.return_value = '/home/netboot/rhel6.5/testimage' + create_path.return_value = '/home/netboot/rhel8.9/testimage' get_md5sum.return_value = 'c73ce117eef8077c3420bfc8f473ac2f' disk_size_units.return_value = '3338:CYL' image_size.return_value = '512000' @@ -2765,7 +2765,7 @@ def test_image_import(self, image_query, create_path, image_import, disk_size_units.assert_called_once_with(final_image_fpath) image_size.assert_called_once_with(final_image_fpath) image_add_record.assert_called_once_with(image_name, - 'rhel6.5', + 'rhel8.9', 'c73ce117eef8077c3420bfc8f473ac2f', '3338:CYL', '512000', @@ -2818,9 +2818,9 @@ def test_image_import_image_already_exist(self, image_query, get_image_path): image_name = 'testimage' url = 'file:///tmp/testdummyimg' - image_meta = {'os_version': 'rhel6.5', + image_meta = {'os_version': 'rhel8.9', 'md5sum': 'c73ce117eef8077c3420bfc8f473ac2f'} - image_query.return_value = [(u'testimage', u'rhel6.5', + image_query.return_value = [(u'testimage', u'rhel8.9', u'c73ce117eef8077c3420bfc8f473ac2f', u'3338:CYL', u'5120000', u'netboot', None)] self.assertRaises(exception.SDKImageOperationError, @@ -2836,7 +2836,7 @@ def test_image_import_invalid_md5sum(self, image_query, image_import, get_md5sum): image_name = 'testimage' url = 'file:///tmp/testdummyimg' - image_meta = {'os_version': 'rhel6.5', + image_meta = {'os_version': 'rhel8.9', 'md5sum': 'c73ce117eef8077c3420bfc8f473ac2f'} image_query.return_value = [] get_md5sum.return_value = 'c73ce117eef8077c3420bfc000000' @@ -2946,7 +2946,7 @@ def test_image_export(self, image_export, image_query): remote_host = 'nova@9.x.x.x' image_query.return_value = [ {'imagename': u'testimage', - 'imageosdistro': u'rhel6.5', + 'imageosdistro': u'rhel8.9', 'md5sum': u'c73ce117eef8077c3420bfc8f473ac2f', 'disk_size_units': u'3338:CYL', 'image_size_in_bytes': u'5120000', @@ -2955,7 +2955,7 @@ def test_image_export(self, image_export, image_query): expect_return = { 'image_name': u'testimage', 'image_path': u'file:///path/to/exported/image', - 'os_version': u'rhel6.5', + 'os_version': u'rhel8.9', 'md5sum': u'c73ce117eef8077c3420bfc8f473ac2f', 'comments': None } @@ -3200,9 +3200,7 @@ def test_guest_capture_get_capture_devices_ubuntu(self, execcmd): @mock.patch.object(smtclient.SMTClient, 'execute_cmd') def test_guest_capture_get_os_version_rh7(self, execcmd): userid = 'fakeid' - execcmd.side_effect = [['/etc/os-release', '/etc/redhat-release', - '/etc/system-release'], - ['NAME="Red Hat Enterprise Linux Server"', + execcmd.side_effect = [['NAME="Red Hat Enterprise Linux Server"', 'VERSION="7.0 (Maipo)"', 'ID="rhel"', 'ID_LIKE="fedora"', @@ -3216,34 +3214,24 @@ def test_guest_capture_get_os_version_rh7(self, execcmd): result = self._smtclient.guest_get_os_version(userid) self.assertEqual(result, 'rhel7.0') - @mock.patch.object(smtclient.SMTClient, 'execute_cmd') - def test_guest_capture_get_os_version_rhel67_sles11(self, execcmd): - userid = 'fakeid' - execcmd.side_effect = [['/etc/redhat-release', - '/etc/system-release'], - ['Red Hat Enterprise Linux Server release 6.7' - ' (Santiago)']] - result = self._smtclient.guest_get_os_version(userid) - self.assertEqual(result, 'rhel6.7') - @mock.patch.object(smtclient.SMTClient, 'execute_cmd') def test_guest_capture_get_os_version_ubuntu(self, execcmd): userid = 'fakeid' - execcmd.side_effect = [['/etc/lsb-release', - '/etc/os-release'], - ['NAME="Ubuntu"', - 'VERSION="16.04 (Xenial Xerus)"', + execcmd.side_effect = [['PRETTY_NAME="Ubuntu 24.04.2 LTS"', + 'NAME="Ubuntu"', + 'VERSION_ID="24.04"', + 'VERSION="24.04.2 LTS (Noble Numbat)"', + 'VERSION_CODENAME=noble', 'ID=ubuntu', 'ID_LIKE=debian', - 'PRETTY_NAME="Ubuntu 16.04"', - 'VERSION_ID="16.04"', - 'HOME_URL="http://www.ubuntu.com/"', - 'SUPPORT_URL="http://help.ubuntu.com/"', - 'BUG_REPORT_URL="http://bugs.launchpad.net' - '/ubuntu/"', - 'UBUNTU_CODENAME=xenial']] + 'HOME_URL="https://www.ubuntu.com/"', + 'SUPPORT_URL="https://help.ubuntu.com/"', + 'BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"', + 'PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"', + 'UBUNTU_CODENAME=noble', + 'LOGO=ubuntu-logo']] result = self._smtclient.guest_get_os_version(userid) - self.assertEqual(result, 'ubuntu16.04') + self.assertEqual(result, 'ubuntu24.04') @mock.patch.object(database.GuestDbOperator, 'get_guest_metadata_with_userid') diff --git a/zvmsdk/tests/unit/test_utils.py b/zvmsdk/tests/unit/test_utils.py index 9574c4489..382fb9c2a 100644 --- a/zvmsdk/tests/unit/test_utils.py +++ b/zvmsdk/tests/unit/test_utils.py @@ -656,7 +656,7 @@ def test_get_zhypinfo(self, mock_check_output): "Failed to run command zhypinfo: " "No such file or directory: \'/usr/bin/zhypinfo\'. " "To run zhypinfo, you must install the package of " - "qclib \(Query Capacity Library\)", + "qclib (Query Capacity Library)", zvmutils.get_zhypinfo, filter='lpar') diff --git a/zvmsdk/tests/unit/test_vmops.py b/zvmsdk/tests/unit/test_vmops.py index 02b1bd5a7..80ce347cd 100644 --- a/zvmsdk/tests/unit/test_vmops.py +++ b/zvmsdk/tests/unit/test_vmops.py @@ -1,7 +1,6 @@ -# Copyright Contributors to the Feilong Project. # SPDX-License-Identifier: Apache-2.0 - -# Copyright 2017,2025 IBM Corp. +# Copyright 2025 Contributors to the Feilong Project. +# Copyright 2017,2025 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -430,7 +429,7 @@ def test_guest_deploy(self, image_get_os_distro, deploy_image_to_vm, img_query, get_atime): image_get_os_distro.return_value = 'fake-distro' get_atime.return_value = 1581910539.3330014 - img_query.return_value = [{'imageosdistro': 'rhel6.7'}] + img_query.return_value = [{'imageosdistro': 'rhel8.9'}] self.vmops.guest_deploy('fakevm', 'fakeimg', '/test/transport.tgz') image_get_os_distro.assert_called_once_with('fakeimg') @@ -445,7 +444,7 @@ def test_guest_deploy(self, image_get_os_distro, deploy_image_to_vm, def test_guest_deploy_sethostname(self, deploy_image_to_vm, img_query, set_hostname, get_atime): fake_hostname = 'fakehost' - img_query.return_value = [{'imageosdistro': 'rhel6.7'}] + img_query.return_value = [{'imageosdistro': 'rhel8.9'}] get_atime.return_value = 1581910539.3330014 self.vmops.guest_deploy('fakevm', 'fakeimg', hostname=fake_hostname) @@ -453,7 +452,7 @@ def test_guest_deploy_sethostname(self, deploy_image_to_vm, img_query, None, False) img_query.assert_called_once_with('fakeimg') set_hostname.assert_called_once_with('fakevm', fake_hostname, - 'rhel6.7') + 'rhel8.9') @mock.patch("zvmsdk.smtclient.SMTClient.guest_capture") def test_guest_capture(self, guest_capture): diff --git a/zvmsdk/tests/unit/test_volumeop.py b/zvmsdk/tests/unit/test_volumeop.py index b22675cd3..afdfa0c08 100755 --- a/zvmsdk/tests/unit/test_volumeop.py +++ b/zvmsdk/tests/unit/test_volumeop.py @@ -524,7 +524,7 @@ def test__check_missing_pchids(self, m_get_pchids_by_tmpl): 'BBBB': {'allocated': 109, 'max': 110}} self.fcpops._check_missing_pchids(assigner_id, fcp_template_id, pchid_info_correct) self.assertRaisesRegex(exception.SDKVolumeOperationError, - ".*the statistics of PCHIDs \[\'02C0\', \'02E0\'\] " + ".*the statistics of PCHIDs [\'02C0\', \'02E0\'] " "are missing.*", self.fcpops._check_missing_pchids, assigner_id, fcp_template_id, pchid_info_missing) @@ -2124,7 +2124,7 @@ def test_get_volume_connector_reserve_with_template_not_exist(self, m_get_zvm_na sp_name = 'v7k60' pchid_info = dict() self.assertRaisesRegex(exception.SDKVolumeOperationError, - "FCP Multipath Template \(id: 0001\) does not exist.", + "FCP Multipath Template (id: 0001) does not exist.", self.volumeops.get_volume_connector, assigner_id, True, fcp_template_id, sp_name, pchid_info)