Merge "Fix rebuilds using anaconda deploy interface"
This commit is contained in:
commit
01dd06a176
@ -668,16 +668,22 @@ def get_instance_image_info(task, ipxe_enabled=False):
|
|||||||
|
|
||||||
return image_info
|
return image_info
|
||||||
|
|
||||||
labels = ('kernel', 'ramdisk')
|
|
||||||
image_properties = None
|
image_properties = None
|
||||||
d_info = deploy_utils.get_image_instance_info(node)
|
d_info = deploy_utils.get_image_instance_info(node)
|
||||||
|
|
||||||
|
def _get_image_properties():
|
||||||
|
nonlocal image_properties
|
||||||
|
if not image_properties:
|
||||||
|
glance_service = service.GlanceImageService(context=ctx)
|
||||||
|
image_properties = glance_service.show(
|
||||||
|
d_info['image_source'])['properties']
|
||||||
|
|
||||||
|
labels = ('kernel', 'ramdisk')
|
||||||
if not (i_info.get('kernel') and i_info.get('ramdisk')):
|
if not (i_info.get('kernel') and i_info.get('ramdisk')):
|
||||||
# NOTE(rloo): If both are not specified in instance_info
|
# NOTE(rloo): If both are not specified in instance_info
|
||||||
# we won't use any of them. We'll use the values specified
|
# we won't use any of them. We'll use the values specified
|
||||||
# with the image, which we assume have been set.
|
# with the image, which we assume have been set.
|
||||||
glance_service = service.GlanceImageService(context=ctx)
|
_get_image_properties()
|
||||||
image_properties = glance_service.show(
|
|
||||||
d_info['image_source'])['properties']
|
|
||||||
for label in labels:
|
for label in labels:
|
||||||
i_info[label] = str(image_properties[label + '_id'])
|
i_info[label] = str(image_properties[label + '_id'])
|
||||||
node.instance_info = i_info
|
node.instance_info = i_info
|
||||||
@ -689,36 +695,41 @@ def get_instance_image_info(task, ipxe_enabled=False):
|
|||||||
# ks_template: anaconda kickstart template
|
# ks_template: anaconda kickstart template
|
||||||
# ks_cfg - rendered ks_template
|
# ks_cfg - rendered ks_template
|
||||||
anaconda_labels = ('stage2', 'ks_template', 'ks_cfg')
|
anaconda_labels = ('stage2', 'ks_template', 'ks_cfg')
|
||||||
if not i_info.get('stage2') or not i_info.get('ks_template'):
|
# NOTE(rloo): We save stage2 & ks_template values in case they
|
||||||
if not image_properties:
|
# are changed by the user after we start using them and to
|
||||||
glance_service = service.GlanceImageService(context=ctx)
|
# prevent re-computing them again.
|
||||||
image_properties = glance_service.show(
|
if not node.driver_internal_info.get('stage2'):
|
||||||
d_info['image_source'])['properties']
|
if i_info.get('stage2'):
|
||||||
if not i_info.get('ks_template'):
|
node.set_driver_internal_info('stage2', i_info['stage2'])
|
||||||
# ks_template is an optional property on the image
|
else:
|
||||||
if 'ks_template' not in image_properties:
|
_get_image_properties()
|
||||||
i_info['ks_template'] = CONF.anaconda.default_ks_template
|
|
||||||
else:
|
|
||||||
i_info['ks_template'] = str(
|
|
||||||
image_properties['ks_template'])
|
|
||||||
if not i_info.get('stage2'):
|
|
||||||
if 'stage2_id' not in image_properties:
|
if 'stage2_id' not in image_properties:
|
||||||
msg = ("'stage2_id' property is missing from the OS image "
|
msg = (_("'stage2_id' is missing from the properties of "
|
||||||
"%s. The anaconda deploy interface requires this "
|
"the OS image %s. The anaconda deploy interface "
|
||||||
"to be set with the OS image or in instance_info. "
|
"requires this to be set with the OS image or "
|
||||||
% d_info['image_source'])
|
"in instance_info['stage2']. ") %
|
||||||
|
d_info['image_source'])
|
||||||
raise exception.ImageUnacceptable(msg)
|
raise exception.ImageUnacceptable(msg)
|
||||||
else:
|
else:
|
||||||
i_info['stage2'] = str(image_properties['stage2_id'])
|
node.set_driver_internal_info(
|
||||||
# NOTE(rloo): This is internally generated; cannot be specified.
|
'stage2', str(image_properties['stage2_id']))
|
||||||
i_info['ks_cfg'] = ''
|
if i_info.get('ks_template'):
|
||||||
|
node.set_driver_internal_info('ks_template',
|
||||||
node.instance_info = i_info
|
i_info['ks_template'])
|
||||||
node.save()
|
else:
|
||||||
|
_get_image_properties()
|
||||||
|
# ks_template is an optional property on the image
|
||||||
|
if 'ks_template' not in image_properties:
|
||||||
|
node.set_driver_internal_info(
|
||||||
|
'ks_template', CONF.anaconda.default_ks_template)
|
||||||
|
else:
|
||||||
|
node.set_driver_internal_info(
|
||||||
|
'ks_template', str(image_properties['ks_template']))
|
||||||
|
node.save()
|
||||||
|
|
||||||
for label in labels + anaconda_labels:
|
for label in labels + anaconda_labels:
|
||||||
image_info[label] = (
|
image_info[label] = (
|
||||||
i_info[label],
|
i_info.get(label) or node.driver_internal_info.get(label, ''),
|
||||||
get_file_path_from_label(node.uuid, root_dir, label)
|
get_file_path_from_label(node.uuid, root_dir, label)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1116,9 +1127,9 @@ def validate_kickstart_file(ks_cfg):
|
|||||||
'ksvalidator', ks_file.name, check_on_exit=[0], attempts=1
|
'ksvalidator', ks_file.name, check_on_exit=[0], attempts=1
|
||||||
)
|
)
|
||||||
except processutils.ProcessExecutionError as e:
|
except processutils.ProcessExecutionError as e:
|
||||||
msg = _(("The kickstart file generated does not pass validation. "
|
msg = (_("The kickstart file generated does not pass validation. "
|
||||||
"The ksvalidator tool returned the following error: %s") %
|
"The ksvalidator tool returned the following error: %s") %
|
||||||
(e))
|
e)
|
||||||
raise exception.InvalidKickstartFile(msg)
|
raise exception.InvalidKickstartFile(msg)
|
||||||
|
|
||||||
|
|
||||||
@ -1214,7 +1225,7 @@ def cache_ramdisk_kernel(task, pxe_info, ipxe_enabled=False):
|
|||||||
path = os.path.join(CONF.pxe.tftp_root, node.uuid)
|
path = os.path.join(CONF.pxe.tftp_root, node.uuid)
|
||||||
ensure_tree(path)
|
ensure_tree(path)
|
||||||
# anaconda deploy will have 'stage2' as one of the labels in pxe_info dict
|
# anaconda deploy will have 'stage2' as one of the labels in pxe_info dict
|
||||||
if 'stage2' in pxe_info.keys():
|
if 'stage2' in pxe_info:
|
||||||
# stage2 will be stored in ipxe http directory so make sure the
|
# stage2 will be stored in ipxe http directory so make sure the
|
||||||
# directory exists.
|
# directory exists.
|
||||||
file_path = get_file_path_from_label(node.uuid,
|
file_path = get_file_path_from_label(node.uuid,
|
||||||
|
@ -134,8 +134,8 @@ class PXEAnacondaDeploy(agent_base.AgentBaseMixin, agent_base.HeartbeatMixin,
|
|||||||
manager_utils.node_power_action(task, states.POWER_ON)
|
manager_utils.node_power_action(task, states.POWER_ON)
|
||||||
task.process_event('done')
|
task.process_event('done')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = (_('Error rebooting node %(node)s after deploy. '
|
msg = (_('An error occurred after deployment, while preparing to '
|
||||||
'Error: %(error)s') %
|
'reboot the node %(node)s: %(error)s') %
|
||||||
{'node': node.uuid, 'error': e})
|
{'node': node.uuid, 'error': e})
|
||||||
agent_base.log_and_raise_deployment_error(task, msg)
|
agent_base.log_and_raise_deployment_error(task, msg)
|
||||||
|
|
||||||
@ -164,3 +164,14 @@ class PXEAnacondaDeploy(agent_base.AgentBaseMixin, agent_base.HeartbeatMixin,
|
|||||||
'%(agent_status_message)s', msg)
|
'%(agent_status_message)s', msg)
|
||||||
deploy_utils.set_failed_state(task, agent_status_message,
|
deploy_utils.set_failed_state(task, agent_status_message,
|
||||||
collect_logs=False)
|
collect_logs=False)
|
||||||
|
|
||||||
|
@METRICS.timer('AnacondaDeploy.clean_up')
|
||||||
|
@task_manager.require_exclusive_lock
|
||||||
|
def clean_up(self, task):
|
||||||
|
super(PXEAnacondaDeploy, self).clean_up(task)
|
||||||
|
node = task.node
|
||||||
|
# NOTE(rloo): These were added during deployment, as a side-effect of
|
||||||
|
# pxe_utils.get_instance_image_info().
|
||||||
|
node.del_driver_internal_info('stage2')
|
||||||
|
node.del_driver_internal_info('ks_template')
|
||||||
|
node.save()
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
The anaconda deploy interface was saving internal information in
|
||||||
|
the node's instance_info, in the user-facing 'stage2' and
|
||||||
|
'ks_template' fields. This broke rebuilds using a different image
|
||||||
|
with different stage2 or template specified in the image properties.
|
||||||
|
This has been fixed by saving the information in the node's
|
||||||
|
driver_internal_info instead.
|
Loading…
x
Reference in New Issue
Block a user