diff options
24 files changed, 235 insertions, 93 deletions
diff --git a/doc/source/admin/console.rst b/doc/source/admin/console.rst index 618954799..b8821248e 100644 --- a/doc/source/admin/console.rst +++ b/doc/source/admin/console.rst @@ -33,11 +33,7 @@ The web console can be configured in Bare Metal service in the following way: sudo apt-get install shellinabox - RHEL7/CentOS7:: - - sudo yum install shellinabox - - Fedora:: + RHEL8/CentOS8/Fedora:: sudo dnf install shellinabox @@ -52,11 +48,7 @@ The web console can be configured in Bare Metal service in the following way: sudo apt-get install openssl - RHEL7/CentOS7:: - - sudo yum install openssl - - Fedora:: + RHEL8/CentOS8/Fedora:: sudo dnf install openssl @@ -182,11 +174,7 @@ Serial consoles can be configured in the Bare Metal service as follows: sudo apt-get install socat - RHEL7/CentOS7:: - - sudo yum install socat - - Fedora:: + RHEL8/CentOS8/Fedora:: sudo dnf install socat diff --git a/doc/source/install/configure-cleaning.rst b/doc/source/install/configure-cleaning.rst index 8579f53b0..b7a29e320 100644 --- a/doc/source/install/configure-cleaning.rst +++ b/doc/source/install/configure-cleaning.rst @@ -29,7 +29,7 @@ Configure the Bare Metal service for cleaning .. code-block:: console - Fedora/RHEL7/CentOS7/SUSE: + Fedora/RHEL8/CentOS8/SUSE: sudo systemctl restart openstack-ironic-conductor Ubuntu: diff --git a/doc/source/install/configure-compute.rst b/doc/source/install/configure-compute.rst index 631cb0b6e..299b4a5ea 100644 --- a/doc/source/install/configure-compute.rst +++ b/doc/source/install/configure-compute.rst @@ -137,7 +137,7 @@ service's controller nodes and compute nodes. .. code-block:: console - Fedora/RHEL7/CentOS7/SUSE: + Fedora/RHEL8/CentOS8/SUSE: sudo systemctl restart openstack-nova-scheduler Ubuntu: @@ -148,7 +148,7 @@ service's controller nodes and compute nodes. .. code-block:: console - Fedora/RHEL7/CentOS7/SUSE: + Fedora/RHEL8/CentOS8/SUSE: sudo systemctl restart openstack-nova-compute Ubuntu: diff --git a/doc/source/install/configure-pxe.rst b/doc/source/install/configure-pxe.rst index 56f345eff..8769375f4 100644 --- a/doc/source/install/configure-pxe.rst +++ b/doc/source/install/configure-pxe.rst @@ -58,11 +58,7 @@ set up on the Bare Metal service nodes which run the ``ironic-conductor``. sudo apt-get install xinetd tftpd-hpa - RHEL7/CentOS7:: - - sudo yum install tftp-server xinetd - - Fedora:: + RHEL8/CentOS8/Fedora:: sudo dnf install tftp-server xinetd @@ -94,7 +90,7 @@ set up on the Bare Metal service nodes which run the ``ironic-conductor``. sudo service xinetd restart - Fedora/RHEL7/CentOS7/SUSE:: + Fedora/RHEL8/CentOS8/SUSE:: sudo systemctl restart xinetd @@ -130,11 +126,7 @@ the PXE UEFI environment. sudo apt-get install grub-efi-amd64-signed shim-signed - RHEL7/CentOS7:: - - sudo yum install grub2-efi shim - - Fedora:: + RHEL8/CentOS8/Fedora:: sudo dnf install grub2-efi shim @@ -154,7 +146,7 @@ the PXE UEFI environment. sudo cp /boot/efi/EFI/fedora/shim.efi /tftpboot/bootx64.efi sudo cp /boot/efi/EFI/fedora/grubx64.efi /tftpboot/grubx64.efi - RHEL7/CentOS7:: + RHEL8/CentOS8:: sudo cp /boot/efi/EFI/centos/shim.efi /tftpboot/bootx64.efi sudo cp /boot/efi/EFI/centos/grubx64.efi /tftpboot/grubx64.efi @@ -174,7 +166,7 @@ the PXE UEFI environment. GRUB_DIR=/tftpboot/EFI/fedora - RHEL7/CentOS7: Create grub.cfg under ``/tftpboot/EFI/centos`` directory:: + RHEL8/CentOS8: Create grub.cfg under ``/tftpboot/EFI/centos`` directory:: GRUB_DIR=/tftpboot/EFI/centos @@ -221,11 +213,7 @@ mode, perform these additional steps on the ironic conductor node. sudo apt-get install syslinux-common pxelinux - RHEL7/CentOS7:: - - sudo yum install syslinux-tftpboot - - Fedora:: + RHEL8/CentOS8/Fedora:: sudo dnf install syslinux-tftpboot @@ -239,7 +227,7 @@ mode, perform these additional steps on the ironic conductor node. sudo cp /usr/lib/PXELINUX/pxelinux.0 /tftpboot - RHEL7/CentOS7/SUSE:: + RHEL8/CentOS8/SUSE:: sudo cp /usr/share/syslinux/pxelinux.0 /tftpboot @@ -254,7 +242,7 @@ mode, perform these additional steps on the ironic conductor node. sudo cp /boot/extlinux/chain.c32 /tftpboot - RHEL7/CentOS7/SUSE:: + RHEL8/CentOS8/SUSE:: sudo cp /usr/share/syslinux/chain.c32 /tftpboot/ @@ -337,11 +325,7 @@ on the Bare Metal service node(s) where ``ironic-conductor`` is running. apt-get install ipxe - RHEL7/CentOS7:: - - yum install ipxe-bootimgs - - Fedora:: + RHEL8/CentOS8/Fedora:: dnf install ipxe-bootimgs @@ -359,7 +343,7 @@ on the Bare Metal service node(s) where ``ironic-conductor`` is running. cp /usr/lib/ipxe/{undionly.kpxe,ipxe.efi} /tftpboot - Fedora/RHEL7/CentOS7:: + Fedora/RHEL8/CentOS8:: cp /usr/share/ipxe/{undionly.kpxe,ipxe.efi} /tftpboot @@ -434,7 +418,7 @@ on the Bare Metal service node(s) where ``ironic-conductor`` is running. #. Restart the ``ironic-conductor`` process: - Fedora/RHEL7/CentOS7/SUSE:: + Fedora/RHEL8/CentOS8/SUSE:: sudo systemctl restart openstack-ironic-conductor diff --git a/doc/source/install/configure-tenant-networks.rst b/doc/source/install/configure-tenant-networks.rst index 37656483b..aa4bf44ae 100644 --- a/doc/source/install/configure-tenant-networks.rst +++ b/doc/source/install/configure-tenant-networks.rst @@ -141,7 +141,7 @@ provisioning will happen in a multi-tenant environment (which means using the #. Restart the ironic-conductor and ironic-api services after the modifications: - - Fedora/RHEL7/CentOS7:: + - Fedora/RHEL8/CentOS8:: sudo systemctl restart openstack-ironic-api sudo systemctl restart openstack-ironic-conductor diff --git a/doc/source/install/enabling-https.rst b/doc/source/install/enabling-https.rst index 81abbc121..3b49ffd58 100644 --- a/doc/source/install/enabling-https.rst +++ b/doc/source/install/enabling-https.rst @@ -34,7 +34,7 @@ It can be enabled by making the following changes to ``/etc/glance/glance-api.co #. Restart the glance-api service:: - Fedora/RHEL7/CentOS7/SUSE: + Fedora/RHEL8/CentOS8/SUSE: sudo systemctl restart openstack-glance-api Debian/Ubuntu: @@ -86,7 +86,7 @@ To enable secure HTTPS communication between Bare Metal service and Image servic #. Restart ironic-conductor service:: - Fedora/RHEL7/CentOS7/SUSE: + Fedora/RHEL8/CentOS8/SUSE: sudo systemctl restart openstack-ironic-conductor Debian/Ubuntu: diff --git a/doc/source/install/include/configure-ironic-api-mod_wsgi.inc b/doc/source/install/include/configure-ironic-api-mod_wsgi.inc index e881a0769..235cf1baa 100644 --- a/doc/source/install/include/configure-ironic-api-mod_wsgi.inc +++ b/doc/source/install/include/configure-ironic-api-mod_wsgi.inc @@ -6,11 +6,7 @@ Bare Metal service comes with an example file for configuring the #. Install the apache service: - RHEL7/CentOS7:: - - sudo yum install httpd - - Fedora:: + Fedora/RHEL8/CentOS8:: sudo dnf install httpd @@ -27,7 +23,7 @@ Bare Metal service comes with an example file for configuring the `Ironic project tree <https://opendev.org/openstack/ironic/raw/branch/master/etc/apache2/ironic>`_ and copy it to the apache sites: - Fedora/RHEL7/CentOS7:: + Fedora/RHEL8/CentOS8:: sudo cp etc/apache2/ironic /etc/httpd/conf.d/ironic.conf @@ -58,7 +54,7 @@ Bare Metal service comes with an example file for configuring the #. Enable the apache ``ironic`` in site and reload: - Fedora/RHEL7/CentOS7:: + Fedora/RHEL8/CentOS8:: sudo systemctl reload httpd diff --git a/doc/source/install/include/configure-ironic-api.inc b/doc/source/install/include/configure-ironic-api.inc index 301558a4b..713ef2b9c 100644 --- a/doc/source/install/include/configure-ironic-api.inc +++ b/doc/source/install/include/configure-ironic-api.inc @@ -120,7 +120,7 @@ Configuring ironic-api service #. Restart the ironic-api service: - Fedora/RHEL7/CentOS7/SUSE:: + Fedora/RHEL8/CentOS8/SUSE:: sudo systemctl restart openstack-ironic-api diff --git a/doc/source/install/install-obs.rst b/doc/source/install/install-obs.rst index be50d39ca..8dcef32cb 100644 --- a/doc/source/install/install-obs.rst +++ b/doc/source/install/install-obs.rst @@ -21,7 +21,7 @@ Install and configure components .. code-block:: console - # zypper install openstack-ironic-api openstack-ironic-conductor python-ironicclient + # zypper install openstack-ironic-api openstack-ironic-conductor python3-ironicclient #. Enable services diff --git a/doc/source/install/install-rdo.rst b/doc/source/install/install-rdo.rst index ccf3fc133..e1e53beed 100644 --- a/doc/source/install/install-rdo.rst +++ b/doc/source/install/install-rdo.rst @@ -6,26 +6,18 @@ Install and configure for Red Hat Enterprise Linux and CentOS This section describes how to install and configure the Bare Metal service -for Red Hat Enterprise Linux 7 and CentOS 7. +for Red Hat Enterprise Linux 8 and CentOS 8. .. include:: include/common-prerequisites.inc Install and configure components ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#. Install from packages +#. Install from packages (using dnf) - - Using ``dnf`` - - .. code-block:: console - - # dnf install openstack-ironic-api openstack-ironic-conductor python-ironicclient - - - Using ``yum`` - - .. code-block:: console + .. code-block:: console - # yum install openstack-ironic-api openstack-ironic-conductor python-ironicclient + # dnf install openstack-ironic-api openstack-ironic-conductor python3-ironicclient #. Enable services diff --git a/doc/source/install/install-ubuntu.rst b/doc/source/install/install-ubuntu.rst index 92c8fc6d3..2d7e6faf2 100644 --- a/doc/source/install/install-ubuntu.rst +++ b/doc/source/install/install-ubuntu.rst @@ -16,7 +16,7 @@ Install and configure components .. code-block:: console - # apt-get install ironic-api ironic-conductor python-ironicclient + # apt-get install ironic-api ironic-conductor python3-ironicclient #. Enable services diff --git a/ironic/common/pxe_utils.py b/ironic/common/pxe_utils.py index 5e27107d6..6f7a666c7 100644 --- a/ironic/common/pxe_utils.py +++ b/ironic/common/pxe_utils.py @@ -112,8 +112,9 @@ def _link_mac_pxe_configs(task, ipxe_enabled=False): create_link(_get_pxe_mac_path(port.address, client_id=client_id, ipxe_enabled=ipxe_enabled)) # Grub2 MAC address only - create_link(_get_pxe_grub_mac_path(port.address, - ipxe_enabled=ipxe_enabled)) + for path in _get_pxe_grub_mac_path(port.address, + ipxe_enabled=ipxe_enabled): + create_link(path) def _link_ip_address_pxe_configs(task, ipxe_enabled=False): @@ -156,7 +157,9 @@ def _link_ip_address_pxe_configs(task, ipxe_enabled=False): def _get_pxe_grub_mac_path(mac, ipxe_enabled=False): root_dir = get_ipxe_root_dir() if ipxe_enabled else get_root_dir() - return os.path.join(root_dir, mac + '.conf') + yield os.path.join(root_dir, "%s-%s-%s" % + ("grub.cfg", "01", mac.replace(':', "-").lower())) + yield os.path.join(root_dir, mac + '.conf') def _get_pxe_mac_path(mac, delimiter='-', client_id=None, @@ -361,8 +364,9 @@ def clean_up_pxe_config(task, ipxe_enabled=False): _get_pxe_mac_path(port.address, client_id=client_id, ipxe_enabled=ipxe_enabled)) # Grub2 MAC address based confiuration - ironic_utils.unlink_without_raise( - _get_pxe_grub_mac_path(port.address, ipxe_enabled=ipxe_enabled)) + for path in _get_pxe_grub_mac_path(port.address, + ipxe_enabled=ipxe_enabled): + ironic_utils.unlink_without_raise(path) if ipxe_enabled: utils.rmtree_without_raise(os.path.join(get_ipxe_root_dir(), task.node.uuid)) diff --git a/ironic/drivers/modules/drac/management.py b/ironic/drivers/modules/drac/management.py index f595bea3b..ce864b79c 100644 --- a/ironic/drivers/modules/drac/management.py +++ b/ironic/drivers/modules/drac/management.py @@ -79,7 +79,7 @@ _DRAC_BOOT_MODES = ['Bios', 'Uefi'] _NON_PERSISTENT_BOOT_MODE = 'OneTime' # Clear job id's constant -_CLEAR_JOB_IDS = 'JID_CLEARALL_FORCE' +_CLEAR_JOB_IDS = 'JID_CLEARALL' # Clean steps constant _CLEAR_JOBS_CLEAN_STEPS = ['clear_job_queue', 'known_good_state'] diff --git a/ironic/drivers/modules/redfish/management.py b/ironic/drivers/modules/redfish/management.py index 69ad88673..676749ad0 100644 --- a/ironic/drivers/modules/redfish/management.py +++ b/ironic/drivers/modules/redfish/management.py @@ -81,12 +81,26 @@ def _set_boot_device(task, system, device, persistent=False): Default: False. :raises: SushyError on an error from the Sushy library """ - desired_enabled = BOOT_DEVICE_PERSISTENT_MAP_REV[persistent] - current_enabled = system.boot.get('enabled') - # NOTE(etingof): this can be racy, esp if BMC is not RESTful - enabled = (desired_enabled - if desired_enabled != current_enabled else None) + # The BMC handling of the persistent setting is vendor specific. + # Some vendors require that it not be set if currently equal to + # desired state (see https://storyboard.openstack.org/#!/story/2007355). + # Supermicro BMCs handle it in the opposite manner - the + # persistent setting must be set when setting the boot device + # (see https://storyboard.openstack.org/#!/story/2008547). + vendor = task.node.properties.get('vendor', None) + if vendor and vendor.lower() == 'supermicro': + enabled = BOOT_DEVICE_PERSISTENT_MAP_REV[persistent] + LOG.debug('Setting BootSourceOverrideEnable to %(enable)s ' + 'on Supermicro BMC, node %(node)s', + {'enable': enabled, 'node': task.node.uuid}) + else: + desired_enabled = BOOT_DEVICE_PERSISTENT_MAP_REV[persistent] + current_enabled = system.boot.get('enabled') + + # NOTE(etingof): this can be racy, esp if BMC is not RESTful + enabled = (desired_enabled + if desired_enabled != current_enabled else None) try: system.set_system_boot_options(device, enabled=enabled) @@ -217,7 +231,12 @@ class RedfishManagement(base.ManagementInterface): # Ensure that boot mode is synced with what is set. # Some BMCs reset it to default (BIOS) when changing the boot device. - boot_mode_utils.sync_boot_mode(task) + # It should only be synced on these vendors as other vendor + # implementations will result in an error + # (see https://storyboard.openstack.org/#!/story/2008712) + vendor = task.node.properties.get('vendor', None) + if vendor and vendor.lower() == 'supermicro': + boot_mode_utils.sync_boot_mode(task) def get_boot_device(self, task): """Get the current boot device for a node. @@ -281,6 +300,19 @@ class RedfishManagement(base.ManagementInterface): {'node': task.node.uuid, 'mode': mode, 'error': e}) LOG.error(error_msg) + + # NOTE(sbaker): Some systems such as HPE Gen9 do not support + # getting or setting the boot mode. When setting failed and the + # mode attribute is missing from the boot field, raising + # UnsupportedDriverExtension will allow the deploy to continue. + if system.boot.get('mode') is None: + LOG.info(_('Attempt to set boot mode on node %(node)s ' + 'failed to set boot mode as the node does not ' + 'appear to support overriding the boot mode. ' + 'Possibly partial Redfish implementation?'), + {'node': task.node.uuid}) + raise exception.UnsupportedDriverExtension( + driver=task.node.driver, extension='set_boot_mode') raise exception.RedfishError(error=error_msg) def get_boot_mode(self, task): diff --git a/ironic/tests/unit/common/test_pxe_utils.py b/ironic/tests/unit/common/test_pxe_utils.py index 6a338267f..25847a325 100644 --- a/ironic/tests/unit/common/test_pxe_utils.py +++ b/ironic/tests/unit/common/test_pxe_utils.py @@ -247,16 +247,22 @@ class TestPXEUtils(db_base.DbTestCase): mock.call(u'../1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/tftpboot/pxelinux.cfg/01-11-22-33-44-55-66'), mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', + '/tftpboot/grub.cfg-01-11-22-33-44-55-66'), + mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/tftpboot/11:22:33:44:55:66.conf'), mock.call(u'../1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/tftpboot/pxelinux.cfg/01-11-22-33-44-55-67'), mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', + '/tftpboot/grub.cfg-01-11-22-33-44-55-67'), + mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/tftpboot/11:22:33:44:55:67.conf') ] unlink_calls = [ mock.call('/tftpboot/pxelinux.cfg/01-11-22-33-44-55-66'), + mock.call('/tftpboot/grub.cfg-01-11-22-33-44-55-66'), mock.call('/tftpboot/11:22:33:44:55:66.conf'), mock.call('/tftpboot/pxelinux.cfg/01-11-22-33-44-55-67'), + mock.call('/tftpboot/grub.cfg-01-11-22-33-44-55-67'), mock.call('/tftpboot/11:22:33:44:55:67.conf') ] with task_manager.acquire(self.context, self.node.uuid) as task: @@ -286,16 +292,22 @@ class TestPXEUtils(db_base.DbTestCase): mock.call(u'../1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/tftpboot/pxelinux.cfg/20-11-22-33-44-55-66'), mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', + '/tftpboot/grub.cfg-01-11-22-33-44-55-66'), + mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/tftpboot/11:22:33:44:55:66.conf'), mock.call(u'../1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/tftpboot/pxelinux.cfg/20-11-22-33-44-55-67'), mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', + '/tftpboot/grub.cfg-01-11-22-33-44-55-67'), + mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/tftpboot/11:22:33:44:55:67.conf') ] unlink_calls = [ mock.call('/tftpboot/pxelinux.cfg/20-11-22-33-44-55-66'), + mock.call('/tftpboot/grub.cfg-01-11-22-33-44-55-66'), mock.call('/tftpboot/11:22:33:44:55:66.conf'), mock.call('/tftpboot/pxelinux.cfg/20-11-22-33-44-55-67'), + mock.call('/tftpboot/grub.cfg-01-11-22-33-44-55-67'), mock.call('/tftpboot/11:22:33:44:55:67.conf') ] with task_manager.acquire(self.context, self.node.uuid) as task: @@ -318,16 +330,22 @@ class TestPXEUtils(db_base.DbTestCase): mock.call(u'../1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/httpboot/pxelinux.cfg/11-22-33-44-55-66'), mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', + '/httpboot/grub.cfg-01-11-22-33-44-55-66'), + mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/httpboot/11:22:33:44:55:66.conf'), mock.call(u'../1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/httpboot/pxelinux.cfg/11-22-33-44-55-67'), mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', + '/httpboot/grub.cfg-01-11-22-33-44-55-67'), + mock.call(u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', '/httpboot/11:22:33:44:55:67.conf') ] unlink_calls = [ mock.call('/httpboot/pxelinux.cfg/11-22-33-44-55-66'), + mock.call('/httpboot/grub.cfg-01-11-22-33-44-55-66'), mock.call('/httpboot/11:22:33:44:55:66.conf'), mock.call('/httpboot/pxelinux.cfg/11-22-33-44-55-67'), + mock.call('/httpboot/grub.cfg-01-11-22-33-44-55-67'), mock.call('/httpboot/11:22:33:44:55:67.conf'), ] with task_manager.acquire(self.context, self.node.uuid) as task: @@ -562,6 +580,7 @@ class TestPXEUtils(db_base.DbTestCase): ensure_calls = [ mock.call("/tftpboot/pxelinux.cfg/01-%s" % address.replace(':', '-')), + mock.call("/tftpboot/grub.cfg-01-aa-aa-aa-aa-aa-aa"), mock.call("/tftpboot/%s.conf" % address) ] @@ -759,6 +778,7 @@ class TestPXEUtils(db_base.DbTestCase): unlink_calls = [ mock.call('/tftpboot/10.10.0.1.conf'), mock.call('/tftpboot/pxelinux.cfg/01-aa-aa-aa-aa-aa-aa'), + mock.call('/tftpboot/grub.cfg-01-aa-aa-aa-aa-aa-aa'), mock.call('/tftpboot/' + address + '.conf') ] unlink_mock.assert_has_calls(unlink_calls) @@ -787,6 +807,7 @@ class TestPXEUtils(db_base.DbTestCase): mock.call('/tftpboot/10.10.0.1.conf'), mock.call('/tftpboot/pxelinux.cfg/01-%s' % address.replace(':', '-')), + mock.call('/tftpboot/grub.cfg-01-aa-aa-aa-aa-aa-aa'), mock.call('/tftpboot/' + address + '.conf') ] @@ -815,6 +836,7 @@ class TestPXEUtils(db_base.DbTestCase): unlink_calls = [ mock.call('/tftpboot/10.10.0.1.conf'), mock.call('/tftpboot/pxelinux.cfg/01-aa-aa-aa-aa-aa-aa'), + mock.call('/tftpboot/grub.cfg-01-aa-aa-aa-aa-aa-aa'), mock.call('/tftpboot/' + address + ".conf") ] unlink_mock.assert_has_calls(unlink_calls) @@ -864,12 +886,21 @@ class TestPXEUtils(db_base.DbTestCase): unlink_calls = [ mock.call('/tftpboot/pxelinux.cfg/01-%s' % address.replace(':', '-')), + mock.call('/tftpboot/grub.cfg-01-aa-aa-aa-aa-aa-aa'), mock.call('/tftpboot/aa:aa:aa:aa:aa:aa.conf') ] unlink_mock.assert_has_calls(unlink_calls) rmtree_mock.assert_called_once_with( os.path.join(CONF.pxe.tftp_root, self.node.uuid)) + def test__get_pxe_grub_mac_path(self): + self.config(tftp_root='/tftpboot-path/', group='pxe') + address = "aa:aa:aa:aa:aa:aa" + actual = pxe_utils._get_pxe_grub_mac_path(address) + self.assertEqual('/tftpboot-path/grub.cfg-01-aa-aa-aa-aa-aa-aa', + next(actual)) + self.assertEqual('/tftpboot-path/' + address + '.conf', next(actual)) + @mock.patch.object(ipxe.iPXEBoot, '__init__', lambda self: None) @mock.patch.object(pxe.PXEBoot, '__init__', lambda self: None) @@ -1751,6 +1782,7 @@ class iPXEBuildConfigOptionsTestCase(db_base.DbTestCase): ensure_calls = [ mock.call("/httpboot/pxelinux.cfg/%s" % address.replace(':', '-')), + mock.call("/httpboot/grub.cfg-01-aa-aa-aa-aa-aa-aa"), mock.call("/httpboot/%s.conf" % address) ] diff --git a/ironic/tests/unit/drivers/modules/drac/test_management.py b/ironic/tests/unit/drivers/modules/drac/test_management.py index 74f2ea372..4d9c791c2 100644 --- a/ironic/tests/unit/drivers/modules/drac/test_management.py +++ b/ironic/tests/unit/drivers/modules/drac/test_management.py @@ -806,7 +806,7 @@ class DracManagementTestCase(test_utils.BaseDracTest): mock_client.reset_idrac.assert_called_once_with( force=True, wait=True) mock_client.delete_jobs.assert_called_once_with( - job_ids=['JID_CLEARALL_FORCE']) + job_ids=['JID_CLEARALL']) self.assertIsNone(return_value) @@ -818,6 +818,6 @@ class DracManagementTestCase(test_utils.BaseDracTest): shared=False) as task: return_value = task.driver.management.clear_job_queue(task) mock_client.delete_jobs.assert_called_once_with( - job_ids=['JID_CLEARALL_FORCE']) + job_ids=['JID_CLEARALL']) self.assertIsNone(return_value) diff --git a/ironic/tests/unit/drivers/modules/redfish/test_management.py b/ironic/tests/unit/drivers/modules/redfish/test_management.py index fd2bdcd4b..d81fbc56f 100644 --- a/ironic/tests/unit/drivers/modules/redfish/test_management.py +++ b/ironic/tests/unit/drivers/modules/redfish/test_management.py @@ -98,8 +98,7 @@ class RedfishManagementTestCase(db_base.DbTestCase): # Asserts fake_system.set_system_boot_options.assert_has_calls( [mock.call(expected, - enabled=sushy.BOOT_SOURCE_ENABLED_ONCE), - mock.call(mode=sushy.BOOT_SOURCE_MODE_BIOS)]) + enabled=sushy.BOOT_SOURCE_ENABLED_ONCE)]) mock_get_system.assert_called_with(task.node) self.assertNotIn('redfish_boot_device', task.node.driver_internal_info) @@ -125,8 +124,7 @@ class RedfishManagementTestCase(db_base.DbTestCase): fake_system.set_system_boot_options.assert_has_calls( [mock.call(sushy.BOOT_SOURCE_TARGET_PXE, - enabled=expected), - mock.call(mode=sushy.BOOT_SOURCE_MODE_BIOS)]) + enabled=expected)]) mock_get_system.assert_called_with(task.node) self.assertNotIn('redfish_boot_device', task.node.driver_internal_info) @@ -153,8 +151,7 @@ class RedfishManagementTestCase(db_base.DbTestCase): task, boot_devices.PXE, persistent=target) fake_system.set_system_boot_options.assert_has_calls( - [mock.call(sushy.BOOT_SOURCE_TARGET_PXE, enabled=None), - mock.call(mode=sushy.BOOT_SOURCE_MODE_BIOS)]) + [mock.call(sushy.BOOT_SOURCE_TARGET_PXE, enabled=None)]) mock_get_system.assert_called_with(task.node) # Reset mocks @@ -240,6 +237,40 @@ class RedfishManagementTestCase(db_base.DbTestCase): sushy.BOOT_SOURCE_TARGET_PXE, task.node.driver_internal_info['redfish_boot_device']) + @mock.patch.object(redfish_utils, 'get_system', autospec=True) + def test_set_boot_device_persistency_vendor(self, mock_get_system): + fake_system = mock_get_system.return_value + fake_system.boot.get.return_value = \ + sushy.BOOT_SOURCE_ENABLED_CONTINUOUS + + values = [ + ('SuperMicro', sushy.BOOT_SOURCE_ENABLED_CONTINUOUS), + ('SomeVendor', None) + ] + + for vendor, expected in values: + properties = self.node.properties + properties['vendor'] = vendor + self.node.properties = properties + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.driver.management.set_boot_device( + task, boot_devices.PXE, persistent=True) + if vendor == 'SuperMicro': + fake_system.set_system_boot_options.assert_has_calls( + [mock.call(sushy.BOOT_SOURCE_TARGET_PXE, + enabled=expected), + mock.call(mode=sushy.BOOT_SOURCE_MODE_BIOS)]) + else: + fake_system.set_system_boot_options.assert_has_calls( + [mock.call(sushy.BOOT_SOURCE_TARGET_PXE, + enabled=expected)]) + + # Reset mocks + fake_system.set_system_boot_options.reset_mock() + mock_get_system.reset_mock() + def test_restore_boot_device(self): fake_system = mock.Mock() with task_manager.acquire(self.context, self.node.uuid, @@ -314,6 +345,12 @@ class RedfishManagementTestCase(db_base.DbTestCase): @mock.patch.object(redfish_utils, 'get_system', autospec=True) def test_set_boot_mode(self, mock_get_system): + boot_attribute = { + 'target': sushy.BOOT_SOURCE_TARGET_PXE, + 'enabled': sushy.BOOT_SOURCE_ENABLED_CONTINUOUS, + 'mode': sushy.BOOT_SOURCE_MODE_BIOS, + } + fake_system = mock.Mock(boot=boot_attribute) fake_system = mock.Mock() mock_get_system.return_value = fake_system with task_manager.acquire(self.context, self.node.uuid, @@ -338,7 +375,12 @@ class RedfishManagementTestCase(db_base.DbTestCase): @mock.patch.object(sushy, 'Sushy', autospec=True) @mock.patch.object(redfish_utils, 'get_system', autospec=True) def test_set_boot_mode_fail(self, mock_get_system, mock_sushy): - fake_system = mock.Mock() + boot_attribute = { + 'target': sushy.BOOT_SOURCE_TARGET_PXE, + 'enabled': sushy.BOOT_SOURCE_ENABLED_CONTINUOUS, + 'mode': sushy.BOOT_SOURCE_MODE_BIOS, + } + fake_system = mock.Mock(boot=boot_attribute) fake_system.set_system_boot_options.side_effect = ( sushy.exceptions.SushyError) mock_get_system.return_value = fake_system @@ -351,6 +393,27 @@ class RedfishManagementTestCase(db_base.DbTestCase): mode=boot_modes.UEFI) mock_get_system.assert_called_once_with(task.node) + @mock.patch.object(sushy, 'Sushy', autospec=True) + @mock.patch.object(redfish_utils, 'get_system', autospec=True) + def test_set_boot_mode_unsupported(self, mock_get_system, mock_sushy): + boot_attribute = { + 'target': sushy.BOOT_SOURCE_TARGET_PXE, + 'enabled': sushy.BOOT_SOURCE_ENABLED_CONTINUOUS, + } + fake_system = mock.Mock(boot=boot_attribute) + error = sushy.exceptions.BadRequestError('PATCH', '/', mock.Mock()) + fake_system.set_system_boot_options.side_effect = error + mock_get_system.return_value = fake_system + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + self.assertRaisesRegex( + exception.UnsupportedDriverExtension, + 'does not support set_boot_mode', + task.driver.management.set_boot_mode, task, boot_modes.UEFI) + fake_system.set_system_boot_options.assert_called_once_with( + mode=boot_modes.UEFI) + mock_get_system.assert_called_once_with(task.node) + @mock.patch.object(redfish_utils, 'get_system', autospec=True) def test_get_boot_mode(self, mock_get_system): boot_attribute = { diff --git a/ironic/tests/unit/drivers/third_party_driver_mocks.py b/ironic/tests/unit/drivers/third_party_driver_mocks.py index 62c3b4b89..8a76d87f3 100644 --- a/ironic/tests/unit/drivers/third_party_driver_mocks.py +++ b/ironic/tests/unit/drivers/third_party_driver_mocks.py @@ -234,6 +234,8 @@ if not sushy: type('MissingAttributeError', (sushy.exceptions.SushyError,), {})) sushy.exceptions.OEMExtensionNotFoundError = ( type('OEMExtensionNotFoundError', (sushy.exceptions.SushyError,), {})) + sushy.exceptions.BadRequestError = ( + type('BadRequestError', (sushy.exceptions.SushyError,), {})) sushy.auth = mock.MagicMock(spec_set=mock_specs.SUSHY_AUTH_SPEC) sys.modules['sushy.auth'] = sushy.auth diff --git a/releasenotes/notes/fix-grub2-config-file-name-88e689a982a21684.yaml b/releasenotes/notes/fix-grub2-config-file-name-88e689a982a21684.yaml new file mode 100644 index 000000000..df17585d1 --- /dev/null +++ b/releasenotes/notes/fix-grub2-config-file-name-88e689a982a21684.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixes the problem about grub2 config file. Some higher versions of + grub2 (e.g. 2.05 or 2.06-rc1) use grub.cfg-01-MAC, while another + lower versions of grub2 (e.g. 2.04) use MAC.conf, so we generate + both paths in order to be compatible with both. diff --git a/releasenotes/notes/redfish-boot-mode-override-not-present-handling-92e7263617e467c4.yaml b/releasenotes/notes/redfish-boot-mode-override-not-present-handling-92e7263617e467c4.yaml new file mode 100644 index 000000000..79f20e439 --- /dev/null +++ b/releasenotes/notes/redfish-boot-mode-override-not-present-handling-92e7263617e467c4.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Adds handling of Redfish BMC's which lack a ``BootSourceOverrideMode`` + flag, such that it is no longer a fatal error for a deployment if the BMC + does not support this field. This most common on BMCs which feature only + a partial implementation of the ``ComputerSystem`` resource ``boot``, + but may also be observable on some older generations of BMCs which + recieved updates to have partial Redfish support. diff --git a/releasenotes/notes/restrict-sync-mode-after-device-to-supermicro-218e8cb57735c685.yaml b/releasenotes/notes/restrict-sync-mode-after-device-to-supermicro-218e8cb57735c685.yaml new file mode 100644 index 000000000..0436b81e6 --- /dev/null +++ b/releasenotes/notes/restrict-sync-mode-after-device-to-supermicro-218e8cb57735c685.yaml @@ -0,0 +1,11 @@ +--- +fixes: + - | + The fix for story + `2008252 <https://storyboard.openstack.org/#!/story/2008252>`_ synced + the boot mode after changing the boot device because Supermicro nodes + reset the boot mode if not included in the boot device set. However this + can cause a problem on Dell nodes when changing the mode uefi->bios or + bios->uefi, see `story 2008712 + <https://storyboard.openstack.org/#!/story/2008712>`_ for details. + Restrict the syncing of the boot mode to Supermicro. diff --git a/releasenotes/notes/supermicro-redfish-override-enabled-aa51686ed33d3061.yaml b/releasenotes/notes/supermicro-redfish-override-enabled-aa51686ed33d3061.yaml new file mode 100644 index 000000000..f3af2a169 --- /dev/null +++ b/releasenotes/notes/supermicro-redfish-override-enabled-aa51686ed33d3061.yaml @@ -0,0 +1,15 @@ +--- +fixes: + - | + When Ironic configures the BootSourceOverrideTarget setting via Redfish, + on Supermicro BMCs it must always configure BootSourceOverrideEnabled or + that will revert to default (Once) on the BMC, see `story 2008547 + <https://storyboard.openstack.org/#!/story/2008547>`_ for details. + This is different than what is currently implemented for other BMCs in + which the BootSourceOverrideEnabled is not configured if it matches the + current setting (see `story 2007355 + <https://storyboard.openstack.org/#!/story/2007355>`_). + + This requires that node.properties['vendor'] be 'supermicro' which will + be set by Ironic from the Redfish system response or can be set + manually. diff --git a/releasenotes/notes/update-clear-job-id-constant-fix-c69cf96c55364bb3.yaml b/releasenotes/notes/update-clear-job-id-constant-fix-c69cf96c55364bb3.yaml new file mode 100644 index 000000000..9ecaac9f2 --- /dev/null +++ b/releasenotes/notes/update-clear-job-id-constant-fix-c69cf96c55364bb3.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixes an issue of powering off with the ``idrac-wsman`` management + interface while the execution of a clear job queue cleaning step is + proceeding. + Prior to this fix, the clean step would fail when powering off a node. diff --git a/tools/test-setup.sh b/tools/test-setup.sh index 186507e1d..c82f4716a 100755 --- a/tools/test-setup.sh +++ b/tools/test-setup.sh @@ -23,8 +23,8 @@ sudo -H mysqladmin -u root password $DB_ROOT_PW sudo -H mysql -u root -p$DB_ROOT_PW -h localhost -e " DELETE FROM mysql.user WHERE User=''; FLUSH PRIVILEGES; - GRANT ALL PRIVILEGES ON *.* - TO '$DB_USER'@'%' identified by '$DB_PW' WITH GRANT OPTION;" + CREATE USER '$DB_USER'@'%' IDENTIFIED BY '$DB_PW'; + GRANT ALL PRIVILEGES ON *.* TO '$DB_USER'@'%' WITH GRANT OPTION;" # Now create our database. mysql -u $DB_USER -p$DB_PW -h 127.0.0.1 -e " |