]> xenbits.xensource.com Git - osstest/openstack-nova.git/commitdiff
libvirt: Combine injection info in InjectionInfo
authorMatthew Booth <mbooth@redhat.com>
Tue, 5 Jul 2016 13:36:47 +0000 (14:36 +0100)
committerMatthew Booth <mbooth@redhat.com>
Wed, 7 Dec 2016 10:56:04 +0000 (10:56 +0000)
Simplify method signatures by combining network_info, admin_pass, and
files into a single data structure.

Implements: bp/libvirt-imagebackend-refactor
Change-Id: I11ae6a0709d4d85f85c3e8e3f3cf8ca9e26a4798

nova/tests/unit/virt/libvirt/test_driver.py
nova/virt/libvirt/driver.py

index ccfcd13c20ace7edcc4914e42a521e3e94b1d2f1..81a1d39d78b60719c31b37f499d43c6e010db302 100644 (file)
@@ -364,6 +364,11 @@ def fake_disk_info_json(instance, type='qcow2'):
     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()
@@ -10529,12 +10534,13 @@ class LibvirtConnTestCase(test.NoDBTestCase):
             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')
@@ -16180,13 +16186,14 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
         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):
@@ -16207,7 +16214,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
                                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(
@@ -16217,18 +16224,10 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
 
             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
@@ -16236,16 +16235,16 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
             '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 = [
@@ -16255,18 +16254,17 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
             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
@@ -16274,11 +16272,11 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
             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
@@ -16286,11 +16284,11 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
             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
@@ -16298,10 +16296,11 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
             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
@@ -16309,7 +16308,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
             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,
index 1055dc241405ae58d780d13cca74d727f1b0c519..353bfb3aef4ae77847064b257de7f67553412694 100644 (file)
@@ -141,6 +141,9 @@ CONSOLE = "console=tty0 console=ttyS0"
 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',
@@ -2595,15 +2598,15 @@ class LibvirtDriver(driver.ComputeDriver):
                                             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)
@@ -2649,17 +2652,15 @@ class LibvirtDriver(driver.ComputeDriver):
                                             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)
@@ -2926,11 +2927,6 @@ class LibvirtDriver(driver.ComputeDriver):
                   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
@@ -2948,20 +2944,18 @@ class LibvirtDriver(driver.ComputeDriver):
         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
@@ -2979,19 +2973,25 @@ class LibvirtDriver(driver.ComputeDriver):
         # 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:
@@ -3005,10 +3005,8 @@ class LibvirtDriver(driver.ComputeDriver):
     # 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(
@@ -3049,9 +3047,9 @@ class LibvirtDriver(driver.ComputeDriver):
             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(
@@ -3132,12 +3130,12 @@ class LibvirtDriver(driver.ComputeDriver):
                                          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
@@ -3167,49 +3165,60 @@ class LibvirtDriver(driver.ComputeDriver):
                                         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 '
@@ -3217,14 +3226,13 @@ class LibvirtDriver(driver.ComputeDriver):
                                       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
@@ -7308,17 +7316,17 @@ class LibvirtDriver(driver.ComputeDriver):
         # 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.