Untie the ramdisk deploy from AgentDeploy
Currently PXERamdiskDeploy inherits AgentDeploy, which is unnecessary (it does not use in-band deploy steps or rely on heartbeats) and only happens to work because AgentDeploy has only one deploy step, which is not going to be the case soon. This change extracts common code for tear down and cleaning from ISCSIDeploy and AgentDeploy into the new AgentBaseMixin and makes PXERamdiskDeploy inherit it instead. Also removes the confusion AgentDeployMixin from iscsi_deploy. Change-Id: Ia6c2e3d98d74fc9c64268db04bc2fb7f5a6f0c1c Story: #2006963 Task: #40153
This commit is contained in:
parent
743d79ef99
commit
2b412df429
|
@ -19,7 +19,6 @@ from oslo_log import log
|
|||
from oslo_utils import excutils
|
||||
from oslo_utils import units
|
||||
|
||||
from ironic.common import dhcp_factory
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service import service_utils
|
||||
from ironic.common.i18n import _
|
||||
|
@ -380,7 +379,8 @@ class AgentDeployMixin(agent_base.AgentDeployMixin):
|
|||
self.reboot_and_finish_deploy(task)
|
||||
|
||||
|
||||
class AgentDeploy(AgentDeployMixin, base.DeployInterface):
|
||||
class AgentDeploy(AgentDeployMixin, agent_base.AgentBaseMixin,
|
||||
base.DeployInterface):
|
||||
"""Interface for deploy-related actions."""
|
||||
|
||||
def get_properties(self):
|
||||
|
@ -390,6 +390,10 @@ class AgentDeploy(AgentDeployMixin, base.DeployInterface):
|
|||
"""
|
||||
return COMMON_PROPERTIES
|
||||
|
||||
def should_manage_boot(self, task):
|
||||
"""Whether agent boot is managed by ironic."""
|
||||
return CONF.agent.manage_agent_boot
|
||||
|
||||
@METRICS.timer('AgentDeploy.validate')
|
||||
def validate(self, task):
|
||||
"""Validate the driver-specific Node deployment info.
|
||||
|
@ -508,31 +512,6 @@ class AgentDeploy(AgentDeployMixin, base.DeployInterface):
|
|||
LOG.info('Deployment to node %s done', task.node.uuid)
|
||||
return None
|
||||
|
||||
@METRICS.timer('AgentDeploy.tear_down')
|
||||
@task_manager.require_exclusive_lock
|
||||
def tear_down(self, task):
|
||||
"""Tear down a previous deployment on the task's node.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:returns: status of the deploy. One of ironic.common.states.
|
||||
:raises: NetworkError if the cleaning ports cannot be removed.
|
||||
:raises: InvalidParameterValue when the wrong power state is specified
|
||||
or the wrong driver info is specified for power management.
|
||||
:raises: StorageError when the storage interface attached volumes fail
|
||||
to detach.
|
||||
:raises: other exceptions by the node's power driver if something
|
||||
wrong occurred during the power action.
|
||||
"""
|
||||
manager_utils.node_power_action(task, states.POWER_OFF)
|
||||
task.driver.storage.detach_volumes(task)
|
||||
deploy_utils.tear_down_storage_configuration(task)
|
||||
with manager_utils.power_state_for_network_configuration(task):
|
||||
task.driver.network.unconfigure_tenant_networks(task)
|
||||
# NOTE(mgoddard): If the deployment was unsuccessful the node may
|
||||
# have ports on the provisioning network which were not deleted.
|
||||
task.driver.network.remove_provisioning_network(task)
|
||||
return states.DELETED
|
||||
|
||||
@METRICS.timer('AgentDeploy.prepare')
|
||||
@task_manager.require_exclusive_lock
|
||||
def prepare(self, task):
|
||||
|
@ -658,46 +637,10 @@ class AgentDeploy(AgentDeployMixin, base.DeployInterface):
|
|||
|
||||
:param task: a TaskManager instance.
|
||||
"""
|
||||
if CONF.agent.manage_agent_boot:
|
||||
task.driver.boot.clean_up_ramdisk(task)
|
||||
task.driver.boot.clean_up_instance(task)
|
||||
provider = dhcp_factory.DHCPFactory()
|
||||
provider.clean_dhcp(task)
|
||||
super(AgentDeploy, self).clean_up(task)
|
||||
if CONF.agent.image_download_source == 'http':
|
||||
deploy_utils.destroy_http_instance_images(task.node)
|
||||
|
||||
def take_over(self, task):
|
||||
"""Take over management of this node from a dead conductor.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
"""
|
||||
pass
|
||||
|
||||
@METRICS.timer('AgentDeploy.prepare_cleaning')
|
||||
def prepare_cleaning(self, task):
|
||||
"""Boot into the agent to prepare for cleaning.
|
||||
|
||||
:param task: a TaskManager object containing the node
|
||||
:raises: NodeCleaningFailure, NetworkError if the previous cleaning
|
||||
ports cannot be removed or if new cleaning ports cannot be created.
|
||||
:raises: InvalidParameterValue if cleaning network UUID config option
|
||||
has an invalid value.
|
||||
:returns: states.CLEANWAIT to signify an asynchronous prepare
|
||||
"""
|
||||
return deploy_utils.prepare_inband_cleaning(
|
||||
task, manage_boot=CONF.agent.manage_agent_boot)
|
||||
|
||||
@METRICS.timer('AgentDeploy.tear_down_cleaning')
|
||||
def tear_down_cleaning(self, task):
|
||||
"""Clean up the PXE and DHCP files after cleaning.
|
||||
|
||||
:param task: a TaskManager object containing the node
|
||||
:raises: NodeCleaningFailure, NetworkError if the cleaning ports cannot
|
||||
be removed
|
||||
"""
|
||||
deploy_utils.tear_down_inband_cleaning(
|
||||
task, manage_boot=CONF.agent.manage_agent_boot)
|
||||
|
||||
|
||||
class AgentRAID(base.RAIDInterface):
|
||||
"""Implementation of RAIDInterface which uses agent ramdisk."""
|
||||
|
|
|
@ -25,12 +25,14 @@ from oslo_utils import timeutils
|
|||
import retrying
|
||||
|
||||
from ironic.common import boot_devices
|
||||
from ironic.common import dhcp_factory
|
||||
from ironic.common import exception
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import image_service
|
||||
from ironic.common import states
|
||||
from ironic.common import utils
|
||||
from ironic.conductor import steps as conductor_steps
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.conductor import utils as manager_utils
|
||||
from ironic.conf import CONF
|
||||
from ironic.drivers.modules import agent_client
|
||||
|
@ -657,6 +659,88 @@ class HeartbeatMixin(object):
|
|||
task.process_event('done')
|
||||
|
||||
|
||||
class AgentBaseMixin(object):
|
||||
"""Mixin with base methods not relying on any deploy steps."""
|
||||
|
||||
def should_manage_boot(self, task):
|
||||
"""Whether agent boot is managed by ironic."""
|
||||
return True
|
||||
|
||||
@METRICS.timer('AgentBaseMixin.tear_down')
|
||||
@task_manager.require_exclusive_lock
|
||||
def tear_down(self, task):
|
||||
"""Tear down a previous deployment on the task's node.
|
||||
|
||||
Power off the node. All actual clean-up is done in the clean_up()
|
||||
method which should be called separately.
|
||||
|
||||
:param task: a TaskManager instance containing the node to act on.
|
||||
:returns: deploy state DELETED.
|
||||
:raises: NetworkError if the cleaning ports cannot be removed.
|
||||
:raises: InvalidParameterValue when the wrong state is specified
|
||||
or the wrong driver info is specified.
|
||||
:raises: StorageError when volume detachment fails.
|
||||
:raises: other exceptions by the node's power driver if something
|
||||
wrong occurred during the power action.
|
||||
"""
|
||||
manager_utils.node_power_action(task, states.POWER_OFF)
|
||||
task.driver.storage.detach_volumes(task)
|
||||
deploy_utils.tear_down_storage_configuration(task)
|
||||
with manager_utils.power_state_for_network_configuration(task):
|
||||
task.driver.network.unconfigure_tenant_networks(task)
|
||||
# NOTE(mgoddard): If the deployment was unsuccessful the node may
|
||||
# have ports on the provisioning network which were not deleted.
|
||||
task.driver.network.remove_provisioning_network(task)
|
||||
return states.DELETED
|
||||
|
||||
@METRICS.timer('AgentBaseMixin.clean_up')
|
||||
def clean_up(self, task):
|
||||
"""Clean up the deployment environment for the task's node.
|
||||
|
||||
Unlinks TFTP and instance images and triggers image cache cleanup.
|
||||
Removes the TFTP configuration files for this node.
|
||||
|
||||
:param task: a TaskManager instance containing the node to act on.
|
||||
"""
|
||||
if self.should_manage_boot(task):
|
||||
task.driver.boot.clean_up_ramdisk(task)
|
||||
task.driver.boot.clean_up_instance(task)
|
||||
provider = dhcp_factory.DHCPFactory()
|
||||
provider.clean_dhcp(task)
|
||||
|
||||
def take_over(self, task):
|
||||
"""Take over management of this node from a dead conductor.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
"""
|
||||
pass
|
||||
|
||||
@METRICS.timer('AgentDeployMixin.prepare_cleaning')
|
||||
def prepare_cleaning(self, task):
|
||||
"""Boot into the agent to prepare for cleaning.
|
||||
|
||||
:param task: a TaskManager object containing the node
|
||||
:raises: NodeCleaningFailure, NetworkError if the previous cleaning
|
||||
ports cannot be removed or if new cleaning ports cannot be created.
|
||||
:raises: InvalidParameterValue if cleaning network UUID config option
|
||||
has an invalid value.
|
||||
:returns: states.CLEANWAIT to signify an asynchronous prepare
|
||||
"""
|
||||
return deploy_utils.prepare_inband_cleaning(
|
||||
task, manage_boot=self.should_manage_boot(task))
|
||||
|
||||
@METRICS.timer('AgentDeployMixin.tear_down_cleaning')
|
||||
def tear_down_cleaning(self, task):
|
||||
"""Clean up the PXE and DHCP files after cleaning.
|
||||
|
||||
:param task: a TaskManager object containing the node
|
||||
:raises: NodeCleaningFailure, NetworkError if the cleaning ports cannot
|
||||
be removed
|
||||
"""
|
||||
deploy_utils.tear_down_inband_cleaning(
|
||||
task, manage_boot=self.should_manage_boot(task))
|
||||
|
||||
|
||||
class AgentDeployMixin(HeartbeatMixin):
|
||||
"""Mixin with deploy methods."""
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ from oslo_concurrency import processutils
|
|||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from ironic.common import dhcp_factory
|
||||
from ironic.common import exception
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import states
|
||||
|
@ -599,38 +598,8 @@ def validate(task):
|
|||
deploy_utils.parse_instance_info(task.node)
|
||||
|
||||
|
||||
class AgentDeployMixin(agent_base.AgentDeployMixin):
|
||||
|
||||
@METRICS.timer('AgentDeployMixin.continue_deploy')
|
||||
@task_manager.require_exclusive_lock
|
||||
def continue_deploy(self, task):
|
||||
"""Method invoked when deployed using iSCSI.
|
||||
|
||||
This method is invoked during a heartbeat from an agent when
|
||||
the node is in wait-call-back state. This deploys the image on
|
||||
the node and then configures the node to boot according to the
|
||||
desired boot option (netboot or localboot).
|
||||
|
||||
:param task: a TaskManager object containing the node.
|
||||
:param kwargs: the kwargs passed from the heartbeat method.
|
||||
:raises: InstanceDeployFailure, if it encounters some error during
|
||||
the deploy.
|
||||
"""
|
||||
task.process_event('resume')
|
||||
node = task.node
|
||||
LOG.debug('Continuing the deployment on node %s', node.uuid)
|
||||
|
||||
uuid_dict_returned = do_agent_iscsi_deploy(task, self._client)
|
||||
root_uuid = uuid_dict_returned.get('root uuid')
|
||||
efi_sys_uuid = uuid_dict_returned.get('efi system partition uuid')
|
||||
prep_boot_part_uuid = uuid_dict_returned.get(
|
||||
'PrEP Boot partition uuid')
|
||||
self.prepare_instance_to_boot(task, root_uuid, efi_sys_uuid,
|
||||
prep_boot_part_uuid=prep_boot_part_uuid)
|
||||
self.reboot_and_finish_deploy(task)
|
||||
|
||||
|
||||
class ISCSIDeploy(AgentDeployMixin, base.DeployInterface):
|
||||
class ISCSIDeploy(agent_base.AgentDeployMixin, agent_base.AgentBaseMixin,
|
||||
base.DeployInterface):
|
||||
"""iSCSI Deploy Interface for deploy-related actions."""
|
||||
|
||||
def get_properties(self):
|
||||
|
@ -717,32 +686,33 @@ class ISCSIDeploy(AgentDeployMixin, base.DeployInterface):
|
|||
|
||||
return None
|
||||
|
||||
@METRICS.timer('ISCSIDeploy.tear_down')
|
||||
@METRICS.timer('AgentDeployMixin.continue_deploy')
|
||||
@task_manager.require_exclusive_lock
|
||||
def tear_down(self, task):
|
||||
"""Tear down a previous deployment on the task's node.
|
||||
def continue_deploy(self, task):
|
||||
"""Method invoked when deployed using iSCSI.
|
||||
|
||||
Power off the node. All actual clean-up is done in the clean_up()
|
||||
method which should be called separately.
|
||||
This method is invoked during a heartbeat from an agent when
|
||||
the node is in wait-call-back state. This deploys the image on
|
||||
the node and then configures the node to boot according to the
|
||||
desired boot option (netboot or localboot).
|
||||
|
||||
:param task: a TaskManager instance containing the node to act on.
|
||||
:returns: deploy state DELETED.
|
||||
:raises: NetworkError if the cleaning ports cannot be removed.
|
||||
:raises: InvalidParameterValue when the wrong state is specified
|
||||
or the wrong driver info is specified.
|
||||
:raises: StorageError when volume detachment fails.
|
||||
:raises: other exceptions by the node's power driver if something
|
||||
wrong occurred during the power action.
|
||||
:param task: a TaskManager object containing the node.
|
||||
:param kwargs: the kwargs passed from the heartbeat method.
|
||||
:raises: InstanceDeployFailure, if it encounters some error during
|
||||
the deploy.
|
||||
"""
|
||||
manager_utils.node_power_action(task, states.POWER_OFF)
|
||||
task.driver.storage.detach_volumes(task)
|
||||
deploy_utils.tear_down_storage_configuration(task)
|
||||
with manager_utils.power_state_for_network_configuration(task):
|
||||
task.driver.network.unconfigure_tenant_networks(task)
|
||||
# NOTE(mgoddard): If the deployment was unsuccessful the node may
|
||||
# have ports on the provisioning network which were not deleted.
|
||||
task.driver.network.remove_provisioning_network(task)
|
||||
return states.DELETED
|
||||
task.process_event('resume')
|
||||
node = task.node
|
||||
LOG.debug('Continuing the deployment on node %s', node.uuid)
|
||||
|
||||
uuid_dict_returned = do_agent_iscsi_deploy(task, self._client)
|
||||
root_uuid = uuid_dict_returned.get('root uuid')
|
||||
efi_sys_uuid = uuid_dict_returned.get('efi system partition uuid')
|
||||
prep_boot_part_uuid = uuid_dict_returned.get(
|
||||
'PrEP Boot partition uuid')
|
||||
self.prepare_instance_to_boot(task, root_uuid, efi_sys_uuid,
|
||||
prep_boot_part_uuid=prep_boot_part_uuid)
|
||||
self.reboot_and_finish_deploy(task)
|
||||
|
||||
@METRICS.timer('ISCSIDeploy.prepare')
|
||||
@task_manager.require_exclusive_lock
|
||||
|
@ -817,33 +787,4 @@ class ISCSIDeploy(AgentDeployMixin, base.DeployInterface):
|
|||
:param task: a TaskManager instance containing the node to act on.
|
||||
"""
|
||||
deploy_utils.destroy_images(task.node.uuid)
|
||||
task.driver.boot.clean_up_ramdisk(task)
|
||||
task.driver.boot.clean_up_instance(task)
|
||||
provider = dhcp_factory.DHCPFactory()
|
||||
provider.clean_dhcp(task)
|
||||
|
||||
def take_over(self, task):
|
||||
pass
|
||||
|
||||
@METRICS.timer('ISCSIDeploy.prepare_cleaning')
|
||||
def prepare_cleaning(self, task):
|
||||
"""Boot into the agent to prepare for cleaning.
|
||||
|
||||
:param task: a TaskManager object containing the node
|
||||
:raises NodeCleaningFailure: if the previous cleaning ports cannot
|
||||
be removed or if new cleaning ports cannot be created
|
||||
:returns: states.CLEANWAIT to signify an asynchronous prepare.
|
||||
"""
|
||||
return deploy_utils.prepare_inband_cleaning(
|
||||
task, manage_boot=True)
|
||||
|
||||
@METRICS.timer('ISCSIDeploy.tear_down_cleaning')
|
||||
def tear_down_cleaning(self, task):
|
||||
"""Clean up the PXE and DHCP files after cleaning.
|
||||
|
||||
:param task: a TaskManager object containing the node
|
||||
:raises NodeCleaningFailure: if the cleaning ports cannot be
|
||||
removed
|
||||
"""
|
||||
deploy_utils.tear_down_inband_cleaning(
|
||||
task, manage_boot=True)
|
||||
super(ISCSIDeploy, self).clean_up(task)
|
||||
|
|
|
@ -24,7 +24,7 @@ from ironic.common import states
|
|||
from ironic.conductor import task_manager
|
||||
from ironic.conductor import utils as manager_utils
|
||||
from ironic.drivers import base
|
||||
from ironic.drivers.modules import agent
|
||||
from ironic.drivers.modules import agent_base
|
||||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules import pxe_base
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -37,7 +37,10 @@ class PXEBoot(pxe_base.PXEBaseMixin, base.BootInterface):
|
|||
capabilities = ['ramdisk_boot', 'pxe_boot']
|
||||
|
||||
|
||||
class PXERamdiskDeploy(agent.AgentDeploy):
|
||||
class PXERamdiskDeploy(agent_base.AgentBaseMixin, base.DeployInterface):
|
||||
|
||||
def get_properties(self, task):
|
||||
return {}
|
||||
|
||||
def validate(self, task):
|
||||
if 'ramdisk_boot' not in task.driver.boot.capabilities:
|
||||
|
|
Loading…
Reference in New Issue