return jsonutils.dumps(disk_info.values())
+def get_injection_info(network_info=None, admin_pass=None, files=None):
+ return libvirt_driver.InjectionInfo(
+ network_info=network_info, admin_pass=admin_pass, files=files)
+
+
def _concurrency(signal, wait, done, target, is_block_dev=False):
signal.send()
wait.wait()
fake_imagebackend.ImageBackendFixture(exists=lambda path: False))
mock_build_device_metadata.return_value = None
-
+ injection_info = get_injection_info(
+ network_info=mock.sentinel.network_info,
+ admin_pass=mock.sentinel.admin_pass,
+ files=mock.sentinel.files
+ )
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
- drvr._create_configdrive(self.context, instance,
- admin_pass=mock.sentinel.admin_pass,
- files=mock.sentinel.files,
- network_info=mock.sentinel.network_info)
+ drvr._create_configdrive(self.context, instance, injection_info)
expected_config_drive_path = os.path.join(
CONF.instances_path, instance.uuid, 'disk.config')
disk_images = {'image_id': None}
drvr._create_and_inject_local_root(self.context, instance_ref, False,
- '', disk_images, [], None, [], True, None)
+ '', disk_images, get_injection_info(),
+ None)
self.assertFalse(mock_inject.called)
@mock.patch('nova.virt.netutils.get_injected_network_template')
@mock.patch('nova.virt.disk.api.inject_data')
@mock.patch.object(libvirt_driver.LibvirtDriver, "_conn")
- def _test_inject_data(self, driver_params, path, disk_params,
+ def _test_inject_data(self, instance, injection_info, path, disk_params,
mock_conn, disk_inject_data, inj_network,
called=True):
class ImageBackend(object):
return_value=image_backend):
self.flags(inject_partition=0, group='libvirt')
- self.drvr._inject_data(image_backend, **driver_params)
+ self.drvr._inject_data(image_backend, instance, injection_info)
if called:
disk_inject_data.assert_called_once_with(
self.assertEqual(disk_inject_data.called, called)
- def _test_inject_data_default_driver_params(self, **params):
- return {
- 'instance': self._create_instance(params=params),
- 'network_info': None,
- 'admin_pass': None,
- 'files': None
- }
-
def test_inject_data_adminpass(self):
self.flags(inject_password=True, group='libvirt')
- driver_params = self._test_inject_data_default_driver_params()
- driver_params['admin_pass'] = 'foobar'
+ instance = self._create_instance()
+ injection_info = get_injection_info(admin_pass='foobar')
disk_params = [
None, # key
None, # net
'foobar', # admin_pass
None, # files
]
- self._test_inject_data(driver_params, "/path", disk_params)
+ self._test_inject_data(instance, injection_info, "/path", disk_params)
# Test with the configuration setted to false.
self.flags(inject_password=False, group='libvirt')
- self._test_inject_data(driver_params, "/path",
- disk_params, called=False)
+ self._test_inject_data(instance, injection_info, "/path", disk_params,
+ called=False)
def test_inject_data_key(self):
- driver_params = self._test_inject_data_default_driver_params()
- driver_params['instance']['key_data'] = 'key-content'
+ instance = self._create_instance(params={'key_data': 'key-content'})
+ injection_info = get_injection_info()
self.flags(inject_key=True, group='libvirt')
disk_params = [
None, # admin_pass
None, # files
]
- self._test_inject_data(driver_params, "/path", disk_params)
+ self._test_inject_data(instance, injection_info, "/path",
+ disk_params)
# Test with the configuration setted to false.
self.flags(inject_key=False, group='libvirt')
- self._test_inject_data(driver_params, "/path",
- disk_params, called=False)
+ self._test_inject_data(instance, injection_info, "/path", disk_params,
+ called=False)
def test_inject_data_metadata(self):
- instance_metadata = {'metadata': {'data': 'foo'}}
- driver_params = self._test_inject_data_default_driver_params(
- **instance_metadata
- )
+ instance = self._create_instance(params={'metadata': {'data': 'foo'}})
+ injection_info = get_injection_info()
disk_params = [
None, # key
None, # net
None, # admin_pass
None, # files
]
- self._test_inject_data(driver_params, "/path", disk_params)
+ self._test_inject_data(instance, injection_info, "/path", disk_params)
def test_inject_data_files(self):
- driver_params = self._test_inject_data_default_driver_params()
- driver_params['files'] = ['file1', 'file2']
+ instance = self._create_instance()
+ injection_info = get_injection_info(files=['file1', 'file2'])
disk_params = [
None, # key
None, # net
None, # admin_pass
['file1', 'file2'], # files
]
- self._test_inject_data(driver_params, "/path", disk_params)
+ self._test_inject_data(instance, injection_info, "/path", disk_params)
def test_inject_data_net(self):
- driver_params = self._test_inject_data_default_driver_params()
- driver_params['network_info'] = {'net': 'eno1'}
+ instance = self._create_instance()
+ injection_info = get_injection_info(network_info={'net': 'eno1'})
disk_params = [
None, # key
{'net': 'eno1'}, # net
None, # admin_pass
None, # files
]
- self._test_inject_data(driver_params, "/path", disk_params)
+ self._test_inject_data(instance, injection_info, "/path", disk_params)
def test_inject_not_exist_image(self):
- driver_params = self._test_inject_data_default_driver_params()
+ instance = self._create_instance()
+ injection_info = get_injection_info()
disk_params = [
'key-content', # key
None, # net
None, # admin_pass
None, # files
]
- self._test_inject_data(driver_params, "/fail/path",
+ self._test_inject_data(instance, injection_info, "/fail/path",
disk_params, called=False)
def _test_attach_detach_interface(self, method, power_state,
GuestNumaConfig = collections.namedtuple(
'GuestNumaConfig', ['cpuset', 'cputune', 'numaconfig', 'numatune'])
+InjectionInfo = collections.namedtuple(
+ 'InjectionInfo', ['network_info', 'files', 'admin_pass'])
+
libvirt_volume_drivers = [
'iscsi=nova.virt.libvirt.volume.iscsi.LibvirtISCSIVolumeDriver',
'iser=nova.virt.libvirt.volume.iser.LibvirtISERVolumeDriver',
instance,
image_meta,
rescue=True)
+ injection_info = InjectionInfo(network_info=network_info,
+ admin_pass=rescue_password,
+ files=None)
gen_confdrive = functools.partial(self._create_configdrive,
- context, instance,
- admin_pass=rescue_password,
- network_info=network_info,
- suffix='.rescue')
+ context, instance, injection_info,
+ rescue=True)
self._create_image(context, instance, disk_info['mapping'],
- suffix='.rescue', disk_images=rescue_images,
- network_info=network_info,
- admin_pass=rescue_password)
+ injection_info=injection_info, suffix='.rescue',
+ disk_images=rescue_images)
xml = self._get_guest_xml(context, instance, network_info, disk_info,
image_meta, rescue=rescue_images)
self._destroy(instance)
instance,
image_meta,
block_device_info)
+ injection_info = InjectionInfo(network_info=network_info,
+ files=injected_files,
+ admin_pass=admin_password)
gen_confdrive = functools.partial(self._create_configdrive,
context, instance,
- admin_pass=admin_password,
- files=injected_files,
- network_info=network_info)
- self._create_image(context, instance,
- disk_info['mapping'],
- network_info=network_info,
- block_device_info=block_device_info,
- files=injected_files,
- admin_pass=admin_password)
+ injection_info)
+ self._create_image(context, instance, disk_info['mapping'],
+ injection_info=injection_info,
+ block_device_info=block_device_info)
# Required by Quobyte CI
self._ensure_console_log_for_instance(instance)
instance=instance)
libvirt_utils.file_open(console_file, 'a').close()
- @staticmethod
- def _get_disk_config_path(instance, suffix=''):
- return os.path.join(libvirt_utils.get_instance_path(instance),
- 'disk.config' + suffix)
-
@staticmethod
def _get_disk_config_image_type():
# TODO(mikal): there is a bug here if images_type has
return ((not bool(instance.get('image_ref')))
or 'disk' not in disk_mapping)
- def _inject_data(self, injection_image, instance, network_info,
- admin_pass, files):
+ def _inject_data(self, disk, instance, injection_info):
"""Injects data in a disk image
Helper used for injecting data in a disk image file system.
- Keyword arguments:
- injection_image -- An Image object we're injecting into
- instance -- a dict that refers instance specifications
- network_info -- a dict that refers network speficications
- admin_pass -- a string used to set an admin password
- files -- a list of files needs to be injected
+ :param disk: The disk we're injecting into (an Image object)
+ :param instance: The instance we're injecting into
+ :param injection_info: Injection info
"""
# Handles the partition need to be used.
+ LOG.debug('Checking root disk injection %(info)s',
+ info=str(injection_info), instance=instance)
target_partition = None
if not instance.kernel_id:
target_partition = CONF.libvirt.inject_partition
# Handles the admin password injection.
if not CONF.libvirt.inject_password:
admin_pass = None
+ else:
+ admin_pass = injection_info.admin_pass
# Handles the network injection.
net = netutils.get_injected_network_template(
- network_info, libvirt_virt_type=CONF.libvirt.virt_type)
+ injection_info.network_info,
+ libvirt_virt_type=CONF.libvirt.virt_type)
# Handles the metadata injection
metadata = instance.get('metadata')
- if any((key, net, metadata, admin_pass, files)):
+ if any((key, net, metadata, admin_pass, injection_info.files)):
+ LOG.debug('Injecting %(info)s', info=str(injection_info),
+ instance=instance)
img_id = instance.image_ref
try:
- disk_api.inject_data(injection_image.get_model(self._conn),
- key, net, metadata, admin_pass, files,
+ disk_api.inject_data(disk.get_model(self._conn),
+ key, net, metadata, admin_pass,
+ injection_info.files,
partition=target_partition,
mandatory=('files',))
except Exception as e:
# method doesn't fail if an image already exists but instead
# think that it will be reused (ie: (live)-migration/resize)
def _create_image(self, context, instance,
- disk_mapping, suffix='',
- disk_images=None, network_info=None,
- block_device_info=None, files=None,
- admin_pass=None, inject_files=True,
+ disk_mapping, injection_info=None, suffix='',
+ disk_images=None, block_device_info=None,
fallback_from_host=None,
ignore_bdi_for_swap=False):
booted_from_volume = self._is_booted_from_volume(
libvirt_utils.chown(image('disk').path, 'root')
self._create_and_inject_local_root(context, instance,
- booted_from_volume, suffix, disk_images,
- network_info, admin_pass, files, inject_files,
- fallback_from_host)
+ booted_from_volume, suffix,
+ disk_images, injection_info,
+ fallback_from_host)
# Lookup the filesystem type if required
os_type_with_default = disk_api.get_fs_type_for_os_type(
swap_mb=swap_mb)
def _create_and_inject_local_root(self, context, instance,
- booted_from_volume, suffix, disk_images,
- network_info, admin_pass, files, inject_files,
- fallback_from_host):
+ booted_from_volume, suffix, disk_images,
+ injection_info, fallback_from_host):
# File injection only if needed
need_inject = (not configdrive.required_by(instance) and
- inject_files and CONF.libvirt.inject_partition != -2)
+ injection_info is not None and
+ CONF.libvirt.inject_partition != -2)
# NOTE(ndipanov): Even if disk_mapping was passed in, which
# currently happens only on rescue - we still don't want to
instance, size, fallback_from_host)
if need_inject:
- self._inject_data(backend, instance, network_info, admin_pass,
- files)
+ self._inject_data(backend, instance, injection_info)
elif need_inject:
LOG.warning(_LW('File injection into a boot from volume '
'instance is not supported'), instance=instance)
- def _create_configdrive(self, context, instance, admin_pass=None,
- files=None, network_info=None, suffix=''):
+ def _create_configdrive(self, context, instance, injection_info,
+ rescue=False):
# As this method being called right after the definition of a
# domain, but before its actual launch, device metadata will be built
# and saved in the instance for it to be used by the config drive and
# the metadata service.
instance.device_metadata = self._build_device_metadata(context,
instance)
- config_drive_image = None
if configdrive.required_by(instance):
LOG.info(_LI('Using config drive'), instance=instance)
- config_drive_image = self.image_backend.by_name(
- instance, 'disk.config' + suffix,
- self._get_disk_config_image_type())
+ name = 'disk.config'
+ if rescue:
+ name += '.rescue'
+
+ config_disk = self.image_backend.by_name(
+ instance, name, self._get_disk_config_image_type())
# Don't overwrite an existing config drive
- if not config_drive_image.exists():
+ if not config_disk.exists():
extra_md = {}
- if admin_pass:
- extra_md['admin_pass'] = admin_pass
+ if injection_info.admin_pass:
+ extra_md['admin_pass'] = injection_info.admin_pass
inst_md = instance_metadata.InstanceMetadata(
- instance, content=files, extra_md=extra_md,
- network_info=network_info, request_context=context)
+ instance, content=injection_info.files, extra_md=extra_md,
+ network_info=injection_info.network_info,
+ request_context=context)
cdb = configdrive.ConfigDriveBuilder(instance_md=inst_md)
with cdb:
- config_drive_local_path = self._get_disk_config_path(
- instance, suffix)
+ # NOTE(mdbooth): We're hardcoding here the path of the
+ # config disk when using the flat backend. This isn't
+ # good, but it's required because we need a local path we
+ # know we can write to in case we're subsequently
+ # importing into rbd. This will be cleaned up when we
+ # replace this with a call to create_from_func, but that
+ # can't happen until we've updated the backends and we
+ # teach them not to cache config disks. This isn't
+ # possible while we're still using cache() under the hood.
+ config_disk_local_path = os.path.join(
+ libvirt_utils.get_instance_path(instance), name)
LOG.info(_LI('Creating config drive at %(path)s'),
- {'path': config_drive_local_path},
+ {'path': config_disk_local_path},
instance=instance)
try:
- cdb.make_drive(config_drive_local_path)
+ cdb.make_drive(config_disk_local_path)
except processutils.ProcessExecutionError as e:
with excutils.save_and_reraise_exception():
LOG.error(_LE('Creating config drive failed '
e, instance=instance)
try:
- config_drive_image.import_file(
- instance, config_drive_local_path,
- 'disk.config' + suffix)
+ config_disk.import_file(
+ instance, config_disk_local_path, name)
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(config_drive_local_path)
+ os.unlink(config_disk_local_path)
def _prepare_pci_devices_for_use(self, pci_devices):
# kvm , qemu support managed mode
# NOTE: This has the intended side-effect of fetching a missing
# backing file.
self._create_image(context, instance, block_disk_info['mapping'],
- network_info=network_info,
block_device_info=block_device_info,
- inject_files=False, ignore_bdi_for_swap=True,
+ ignore_bdi_for_swap=True,
fallback_from_host=migration.source_compute)
# Required by Quobyte CI
self._ensure_console_log_for_instance(instance)
- gen_confdrive = functools.partial(self._create_configdrive,
- context, instance,
- network_info=network_info)
+ gen_confdrive = functools.partial(
+ self._create_configdrive, context, instance,
+ InjectionInfo(admin_pass=None, network_info=network_info,
+ files=None))
# Convert raw disks to qcow2 if migrating to host which uses
# qcow2 from host which uses raw.