diff --git a/ironic/drivers/modules/ipxe.py b/ironic/drivers/modules/ipxe.py index 43c4e6ecc0..e1f6069e86 100644 --- a/ironic/drivers/modules/ipxe.py +++ b/ironic/drivers/modules/ipxe.py @@ -32,56 +32,22 @@ from ironic.drivers import base from ironic.drivers.modules import boot_mode_utils from ironic.drivers.modules import deploy_utils from ironic.drivers.modules import pxe +from ironic.drivers.modules import pxe_base from ironic.drivers import utils as driver_utils LOG = logging.getLogger(__name__) METRICS = metrics_utils.get_metrics_logger(__name__) -# TODO(TheJulia): Lets rip these out ASAP and move them to a pxe_common. -# One chunk moving at a time for sanity. -REQUIRED_PROPERTIES = { - 'deploy_kernel': _("UUID (from Glance) of the deployment kernel. " - "Required."), - 'deploy_ramdisk': _("UUID (from Glance) of the ramdisk that is " - "mounted at boot time. Required."), -} -OPTIONAL_PROPERTIES = { - 'force_persistent_boot_device': _("True to enable persistent behavior " - "when the boot device is set during " - "deploy and cleaning operations. " - "Defaults to False. Optional."), -} -RESCUE_PROPERTIES = { - 'rescue_kernel': _('UUID (from Glance) of the rescue kernel. This value ' - 'is required for rescue mode.'), - 'rescue_ramdisk': _('UUID (from Glance) of the rescue ramdisk with agent ' - 'that is used at node rescue time. This value is ' - 'required for rescue mode.'), -} -COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy() -COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES) -COMMON_PROPERTIES.update(RESCUE_PROPERTIES) -# TODO(TheJulia): Use these as the copy to move, no reason to touch pxe.py at -# the same time as doing the initial split out as deduplication goes on. +COMMON_PROPERTIES = pxe_base.COMMON_PROPERTIES -class iPXEBoot(base.BootInterface): +class iPXEBoot(pxe_base.PXEBaseMixin, base.BootInterface): capabilities = ['iscsi_volume_boot', 'ramdisk_boot', 'ipxe_boot'] def __init__(self): pxe_utils.create_ipxe_boot_script() - def get_properties(self): - """Return the properties of the interface. - - :returns: dictionary of : entries. - """ - # TODO(stendulker): COMMON_PROPERTIES should also include rescue - # related properties (RESCUE_PROPERTIES). We can add them in Rocky, - # when classic drivers get removed. - return COMMON_PROPERTIES - @METRICS.timer('iPXEBoot.validate') def validate(self, task): """Validate the PXE-specific info for booting deploy/instance images. @@ -212,33 +178,6 @@ class iPXEBoot(base.BootInterface): if pxe_info: pxe_utils.cache_ramdisk_kernel(task, pxe_info) - @METRICS.timer('iPXEBoot.clean_up_ramdisk') - def clean_up_ramdisk(self, task): - """Cleans up the boot of ironic ramdisk. - - This method cleans up the PXE environment that was setup for booting - the deploy or rescue ramdisk. It unlinks the deploy/rescue - kernel/ramdisk in the node's directory in tftproot and removes it's PXE - config. - - :param task: a task from TaskManager. - :param mode: Label indicating a deploy or rescue operation - was carried out on the node. Supported values are 'deploy' and - 'rescue'. Defaults to 'deploy', indicating deploy operation was - carried out. - :returns: None - """ - node = task.node - mode = deploy_utils.rescue_or_deploy_mode(node) - try: - images_info = pxe_utils.get_image_info(node, mode=mode) - except exception.MissingParameterValue as e: - LOG.warning('Could not get %(mode)s image info ' - 'to clean up images for node %(node)s: %(err)s', - {'mode': mode, 'node': node.uuid, 'err': e}) - else: - pxe_utils.clean_up_pxe_env(task, images_info) - @METRICS.timer('iPXEBoot.prepare_instance') def prepare_instance(self, task): """Prepares the boot of instance. @@ -346,13 +285,3 @@ class iPXEBoot(base.BootInterface): {'node': node.uuid, 'err': e}) else: pxe_utils.clean_up_pxe_env(task, images_info) - - @METRICS.timer('iPXEBoot.validate_rescue') - def validate_rescue(self, task): - """Validate that the node has required properties for rescue. - - :param task: a TaskManager instance with the node being checked - :raises: MissingParameterValue if node is missing one or more required - parameters - """ - pxe_utils.parse_driver_info(task.node, mode='rescue') diff --git a/ironic/drivers/modules/pxe.py b/ironic/drivers/modules/pxe.py index 91fe87403d..017a63199b 100644 --- a/ironic/drivers/modules/pxe.py +++ b/ironic/drivers/modules/pxe.py @@ -33,32 +33,13 @@ from ironic.drivers import base from ironic.drivers.modules import agent from ironic.drivers.modules import boot_mode_utils from ironic.drivers.modules import deploy_utils +from ironic.drivers.modules import pxe_base from ironic.drivers import utils as driver_utils LOG = logging.getLogger(__name__) METRICS = metrics_utils.get_metrics_logger(__name__) -REQUIRED_PROPERTIES = { - 'deploy_kernel': _("UUID (from Glance) of the deployment kernel. " - "Required."), - 'deploy_ramdisk': _("UUID (from Glance) of the ramdisk that is " - "mounted at boot time. Required."), -} -OPTIONAL_PROPERTIES = { - 'force_persistent_boot_device': _("True to enable persistent behavior " - "when the boot device is set during " - "deploy and cleaning operations. " - "Defaults to False. Optional."), -} -RESCUE_PROPERTIES = { - 'rescue_kernel': _('UUID (from Glance) of the rescue kernel. This value ' - 'is required for rescue mode.'), - 'rescue_ramdisk': _('UUID (from Glance) of the rescue ramdisk with agent ' - 'that is used at node rescue time. This value is ' - 'required for rescue mode.'), -} -COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy() -COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES) +COMMON_PROPERTIES = pxe_base.COMMON_PROPERTIES # NOTE(TheJulia): This was previously a public method to the code being # moved. This mapping should be removed in the T* cycle. @@ -67,8 +48,11 @@ TFTPImageCache = pxe_utils.TFTPImageCache # NOTE(TheJulia): End section of mappings for migrated common pxe code. -class PXEBoot(base.BootInterface): +class PXEBoot(pxe_base.PXEBaseMixin, base.BootInterface): + # TODO(TheJulia): iscsi_volume_boot should be removed from + # the list below once ipxe support is removed from the PXE + # interface. capabilities = ['iscsi_volume_boot', 'ramdisk_boot', 'ipxe_boot', 'pxe_boot'] @@ -78,16 +62,6 @@ class PXEBoot(base.BootInterface): if CONF.pxe.ipxe_enabled: pxe_utils.create_ipxe_boot_script() - def get_properties(self): - """Return the properties of the interface. - - :returns: dictionary of : entries. - """ - # TODO(stendulker): COMMON_PROPERTIES should also include rescue - # related properties (RESCUE_PROPERTIES). We can add them in Rocky, - # when classic drivers get removed. - return COMMON_PROPERTIES - @METRICS.timer('PXEBoot.validate') def validate(self, task): """Validate the PXE-specific info for booting deploy/instance images. @@ -211,33 +185,6 @@ class PXEBoot(base.BootInterface): if pxe_info: pxe_utils.cache_ramdisk_kernel(task, pxe_info) - @METRICS.timer('PXEBoot.clean_up_ramdisk') - def clean_up_ramdisk(self, task): - """Cleans up the boot of ironic ramdisk. - - This method cleans up the PXE environment that was setup for booting - the deploy or rescue ramdisk. It unlinks the deploy/rescue - kernel/ramdisk in the node's directory in tftproot and removes it's PXE - config. - - :param task: a task from TaskManager. - :param mode: Label indicating a deploy or rescue operation - was carried out on the node. Supported values are 'deploy' and - 'rescue'. Defaults to 'deploy', indicating deploy operation was - carried out. - :returns: None - """ - node = task.node - mode = deploy_utils.rescue_or_deploy_mode(node) - try: - images_info = pxe_utils.get_image_info(node, mode=mode) - except exception.MissingParameterValue as e: - LOG.warning('Could not get %(mode)s image info ' - 'to clean up images for node %(node)s: %(err)s', - {'mode': mode, 'node': node.uuid, 'err': e}) - else: - pxe_utils.clean_up_pxe_env(task, images_info) - @METRICS.timer('PXEBoot.prepare_instance') def prepare_instance(self, task): """Prepares the boot of instance. @@ -343,16 +290,6 @@ class PXEBoot(base.BootInterface): else: pxe_utils.clean_up_pxe_env(task, images_info) - @METRICS.timer('PXEBoot.validate_rescue') - def validate_rescue(self, task): - """Validate that the node has required properties for rescue. - - :param task: a TaskManager instance with the node being checked - :raises: MissingParameterValue if node is missing one or more required - parameters - """ - pxe_utils.parse_driver_info(task.node, mode='rescue') - class PXERamdiskDeploy(agent.AgentDeploy): diff --git a/ironic/drivers/modules/pxe_base.py b/ironic/drivers/modules/pxe_base.py new file mode 100644 index 0000000000..5c61d806a9 --- /dev/null +++ b/ironic/drivers/modules/pxe_base.py @@ -0,0 +1,95 @@ +# 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 +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +""" +Base PXE Interface Methods +""" + +from ironic_lib import metrics_utils +from oslo_log import log as logging + +from ironic.common import exception +from ironic.common.i18n import _ +from ironic.common import pxe_utils as pxe_utils +from ironic.drivers.modules import deploy_utils +LOG = logging.getLogger(__name__) + +METRICS = metrics_utils.get_metrics_logger(__name__) + +REQUIRED_PROPERTIES = { + 'deploy_kernel': _("UUID (from Glance) of the deployment kernel. " + "Required."), + 'deploy_ramdisk': _("UUID (from Glance) of the ramdisk that is " + "mounted at boot time. Required."), +} +OPTIONAL_PROPERTIES = { + 'force_persistent_boot_device': _("True to enable persistent behavior " + "when the boot device is set during " + "deploy and cleaning operations. " + "Defaults to False. Optional."), +} +RESCUE_PROPERTIES = { + 'rescue_kernel': _('UUID (from Glance) of the rescue kernel. This value ' + 'is required for rescue mode.'), + 'rescue_ramdisk': _('UUID (from Glance) of the rescue ramdisk with agent ' + 'that is used at node rescue time. This value is ' + 'required for rescue mode.'), +} +COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy() +COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES) +COMMON_PROPERTIES.update(RESCUE_PROPERTIES) + + +class PXEBaseMixin(object): + + def get_properties(self): + """Return the properties of the interface. + + :returns: dictionary of : entries. + """ + return COMMON_PROPERTIES + + @METRICS.timer('PXEBaseMixin.clean_up_ramdisk') + def clean_up_ramdisk(self, task): + """Cleans up the boot of ironic ramdisk. + + This method cleans up the PXE environment that was setup for booting + the deploy or rescue ramdisk. It unlinks the deploy/rescue + kernel/ramdisk in the node's directory in tftproot and removes it's PXE + config. + + :param task: a task from TaskManager. + :param mode: Label indicating a deploy or rescue operation + was carried out on the node. Supported values are 'deploy' and + 'rescue'. Defaults to 'deploy', indicating deploy operation was + carried out. + :returns: None + """ + node = task.node + mode = deploy_utils.rescue_or_deploy_mode(node) + try: + images_info = pxe_utils.get_image_info(node, mode=mode) + except exception.MissingParameterValue as e: + LOG.warning('Could not get %(mode)s image info ' + 'to clean up images for node %(node)s: %(err)s', + {'mode': mode, 'node': node.uuid, 'err': e}) + else: + pxe_utils.clean_up_pxe_env(task, images_info) + + @METRICS.timer('PXEBaseMixin.validate_rescue') + def validate_rescue(self, task): + """Validate that the node has required properties for rescue. + + :param task: a TaskManager instance with the node being checked + :raises: MissingParameterValue if node is missing one or more required + parameters + """ + pxe_utils.parse_driver_info(task.node, mode='rescue') diff --git a/ironic/tests/unit/conductor/test_manager.py b/ironic/tests/unit/conductor/test_manager.py index 5c20a7584b..0a517b6765 100644 --- a/ironic/tests/unit/conductor/test_manager.py +++ b/ironic/tests/unit/conductor/test_manager.py @@ -6816,7 +6816,8 @@ class ManagerTestProperties(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase): 'ipmi_target_address', 'ipmi_local_address', 'deploy_kernel', 'deploy_ramdisk', 'force_persistent_boot_device', 'ipmi_protocol_version', - 'ipmi_force_boot_device', 'deploy_forces_oob_reboot'] + 'ipmi_force_boot_device', 'deploy_forces_oob_reboot', + 'rescue_kernel', 'rescue_ramdisk'] self._check_driver_properties("ipmi", expected) def test_driver_properties_snmp(self): @@ -6824,6 +6825,7 @@ class ManagerTestProperties(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase): enabled_power_interfaces=['snmp']) expected = ['deploy_kernel', 'deploy_ramdisk', 'force_persistent_boot_device', + 'rescue_kernel', 'rescue_ramdisk', 'snmp_driver', 'snmp_address', 'snmp_port', 'snmp_version', 'snmp_community', 'snmp_community_read', 'snmp_community_write', @@ -6873,7 +6875,8 @@ class ManagerTestHardwareTypeProperties(mgr_utils.ServiceSetUpMixin, def test_hardware_type_properties_manual_management(self): expected = ['deploy_kernel', 'deploy_ramdisk', - 'force_persistent_boot_device', 'deploy_forces_oob_reboot'] + 'force_persistent_boot_device', 'deploy_forces_oob_reboot', + 'rescue_kernel', 'rescue_ramdisk'] self._check_hardware_type_properties('manual-management', expected) diff --git a/ironic/tests/unit/drivers/test_generic.py b/ironic/tests/unit/drivers/test_generic.py index e1f4a90936..0453eaa680 100644 --- a/ironic/tests/unit/drivers/test_generic.py +++ b/ironic/tests/unit/drivers/test_generic.py @@ -67,7 +67,7 @@ class ManualManagementHardwareTestCase(db_base.DbTestCase): # These properties are from vendor (agent) and boot (pxe) interfaces expected_prop_keys = [ 'deploy_forces_oob_reboot', 'deploy_kernel', 'deploy_ramdisk', - 'force_persistent_boot_device'] + 'force_persistent_boot_device', 'rescue_kernel', 'rescue_ramdisk'] hardware_type = driver_factory.get_hardware_type("manual-management") properties = hardware_type.get_properties() self.assertEqual(sorted(expected_prop_keys), sorted(properties))