Only attempt to inject files if the injection disk exists

_inject_data was checking for the existence of the image to inject
into. However, the only caller of _inject_data has just created that
image. We move the _inject_data call up to where the image is created,
and pass the existing image object in directly. We modify _inject_data
to remove the existence check as, bar a delete race which was present
anyway, we know it exists.

Change-Id: Icb926e64151048c6ce8353de604417d5d79858e4
This commit is contained in:
Matthew Booth 2015-11-27 15:52:13 +00:00
parent 547dc45044
commit eb4229506c
2 changed files with 55 additions and 67 deletions

View File

@ -14949,11 +14949,6 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
class ImageBackend(object): class ImageBackend(object):
path = '/path' path = '/path'
def check_image_exists(self):
if self.path == '/fail/path':
return False
return True
def get_model(self, connection): def get_model(self, connection):
return imgmodel.LocalFileImage(self.path, return imgmodel.LocalFileImage(self.path,
imgmodel.FORMAT_RAW) imgmodel.FORMAT_RAW)
@ -14971,7 +14966,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
return_value=image_backend): return_value=image_backend):
self.flags(inject_partition=0, group='libvirt') self.flags(inject_partition=0, group='libvirt')
self.drvr._inject_data(**driver_params) self.drvr._inject_data(image_backend, **driver_params)
if called: if called:
disk_inject_data.assert_called_once_with( disk_inject_data.assert_called_once_with(
@ -14986,8 +14981,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
'instance': self._create_instance(params=params), 'instance': self._create_instance(params=params),
'network_info': None, 'network_info': None,
'admin_pass': None, 'admin_pass': None,
'files': None, 'files': None
'suffix': ''
} }
def test_inject_data_adminpass(self): def test_inject_data_adminpass(self):
@ -15326,10 +15320,10 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
).AndReturn(mock_backend.kernel) ).AndReturn(mock_backend.kernel)
imagebackend.Backend.image(instance, 'ramdisk.rescue', 'raw' imagebackend.Backend.image(instance, 'ramdisk.rescue', 'raw'
).AndReturn(mock_backend.ramdisk) ).AndReturn(mock_backend.ramdisk)
imagebackend.Backend.image(instance, 'disk.config.rescue', 'raw'
).AndReturn(mock_backend.config)
imagebackend.Backend.image(instance, 'disk.rescue', 'default' imagebackend.Backend.image(instance, 'disk.rescue', 'default'
).AndReturn(mock_backend.root) ).AndReturn(mock_backend.root)
imagebackend.Backend.image(instance, 'disk.config.rescue', 'raw'
).AndReturn(mock_backend.config)
instance_metadata.InstanceMetadata.__init__(mox.IgnoreArg(), instance_metadata.InstanceMetadata.__init__(mox.IgnoreArg(),
content=mox.IgnoreArg(), content=mox.IgnoreArg(),

View File

@ -2836,17 +2836,18 @@ class LibvirtDriver(driver.ComputeDriver):
return True return True
return False return False
def _inject_data(self, instance, network_info, admin_pass, files, suffix): def _inject_data(self, injection_image, instance, network_info,
admin_pass, files):
"""Injects data in a disk image """Injects data in a disk image
Helper used for injecting data in a disk image file system. Helper used for injecting data in a disk image file system.
Keyword arguments: Keyword arguments:
injection_image -- An Image object we're injecting into
instance -- a dict that refers instance specifications instance -- a dict that refers instance specifications
network_info -- a dict that refers network speficications network_info -- a dict that refers network speficications
admin_pass -- a string used to set an admin password admin_pass -- a string used to set an admin password
files -- a list of files needs to be injected files -- a list of files needs to be injected
suffix -- a string used as an image name suffix
""" """
# Handles the partition need to be used. # Handles the partition need to be used.
target_partition = None target_partition = None
@ -2874,19 +2875,8 @@ class LibvirtDriver(driver.ComputeDriver):
# Handles the metadata injection # Handles the metadata injection
metadata = instance.get('metadata') metadata = instance.get('metadata')
image_type = CONF.libvirt.images_type
if any((key, net, metadata, admin_pass, files)): if any((key, net, metadata, admin_pass, files)):
injection_image = self.image_backend.image(
instance,
'disk' + suffix,
image_type)
img_id = instance.image_ref img_id = instance.image_ref
if not injection_image.check_image_exists():
LOG.warning(_LW('Image %s not found on disk storage. '
'Continue without injecting data'),
injection_image.path, instance=instance)
return
try: try:
disk.inject_data(injection_image.get_model(self._conn), disk.inject_data(injection_image.get_model(self._conn),
key, net, metadata, admin_pass, files, key, net, metadata, admin_pass, files,
@ -2954,6 +2944,46 @@ class LibvirtDriver(driver.ComputeDriver):
inst_type = instance.get_flavor() inst_type = instance.get_flavor()
# Config drive
config_drive_image = None
if configdrive.required_by(instance):
LOG.info(_LI('Using config drive'), instance=instance)
extra_md = {}
if admin_pass:
extra_md['admin_pass'] = admin_pass
inst_md = instance_metadata.InstanceMetadata(instance,
content=files, extra_md=extra_md, network_info=network_info)
with configdrive.ConfigDriveBuilder(instance_md=inst_md) as cdb:
configdrive_path = self._get_disk_config_path(instance, suffix)
LOG.info(_LI('Creating config drive at %(path)s'),
{'path': configdrive_path}, instance=instance)
try:
cdb.make_drive(configdrive_path)
except processutils.ProcessExecutionError as e:
with excutils.save_and_reraise_exception():
LOG.error(_LE('Creating config drive failed '
'with error: %s'),
e, instance=instance)
try:
# Tell the storage backend about the config drive
config_drive_image = self.image_backend.image(
instance, 'disk.config' + suffix,
self._get_disk_config_image_type())
config_drive_image.import_file(
instance, configdrive_path, 'disk.config' + suffix)
finally:
# NOTE(mikal): if the config drive was imported into RBD, then
# we no longer need the local copy
if CONF.libvirt.images_type == 'rbd':
os.unlink(configdrive_path)
need_inject = (config_drive_image is None and inject_files and
CONF.libvirt.inject_partition != -2)
# NOTE(ndipanov): Even if disk_mapping was passed in, which # NOTE(ndipanov): Even if disk_mapping was passed in, which
# currently happens only on rescue - we still don't want to # currently happens only on rescue - we still don't want to
# create a base image. # create a base image.
@ -2980,6 +3010,14 @@ class LibvirtDriver(driver.ComputeDriver):
root_fname, disk_images['image_id'], root_fname, disk_images['image_id'],
instance, size, fallback_from_host) instance, size, fallback_from_host)
if need_inject:
self._inject_data(backend, instance, network_info, admin_pass,
files)
elif need_inject:
LOG.warn(_LW('File injection into a boot from volume '
'instance is not supported'), instance=instance)
# Lookup the filesystem type if required # Lookup the filesystem type if required
os_type_with_default = disk.get_fs_type_for_os_type(instance.os_type) os_type_with_default = disk.get_fs_type_for_os_type(instance.os_type)
# Generate a file extension based on the file system # Generate a file extension based on the file system
@ -3044,50 +3082,6 @@ class LibvirtDriver(driver.ComputeDriver):
size=size, size=size,
swap_mb=swap_mb) swap_mb=swap_mb)
# Config drive
if configdrive.required_by(instance):
LOG.info(_LI('Using config drive'), instance=instance)
extra_md = {}
if admin_pass:
extra_md['admin_pass'] = admin_pass
inst_md = instance_metadata.InstanceMetadata(instance,
content=files, extra_md=extra_md, network_info=network_info)
with configdrive.ConfigDriveBuilder(instance_md=inst_md) as cdb:
configdrive_path = self._get_disk_config_path(instance, suffix)
LOG.info(_LI('Creating config drive at %(path)s'),
{'path': configdrive_path}, instance=instance)
try:
cdb.make_drive(configdrive_path)
except processutils.ProcessExecutionError as e:
with excutils.save_and_reraise_exception():
LOG.error(_LE('Creating config drive failed '
'with error: %s'),
e, instance=instance)
try:
# Tell the storage backend about the config drive
config_drive_image = self.image_backend.image(
instance, 'disk.config' + suffix,
self._get_disk_config_image_type())
config_drive_image.import_file(
instance, configdrive_path, 'disk.config' + suffix)
finally:
# NOTE(mikal): if the config drive was imported into RBD, then
# we no longer need the local copy
if CONF.libvirt.images_type == 'rbd':
os.unlink(configdrive_path)
# File injection only if needed
elif inject_files and CONF.libvirt.inject_partition != -2:
if booted_from_volume:
LOG.warning(_LW('File injection into a boot from volume '
'instance is not supported'), instance=instance)
self._inject_data(
instance, network_info, admin_pass, files, suffix)
if CONF.libvirt.virt_type == 'uml': if CONF.libvirt.virt_type == 'uml':
libvirt_utils.chown(image('disk').path, 'root') libvirt_utils.chown(image('disk').path, 'root')