[openstack-nova/el6] improve performance and stability of file injection

Pádraig Brady pbrady at fedoraproject.org
Fri Jun 22 14:52:44 UTC 2012


commit 98948a9db54be83a0f31a087c2e09c0c4970a881
Author: Pádraig Brady <P at draigBrady.com>
Date:   Fri Jun 22 15:21:42 2012 +0100

    improve performance and stability of file injection
    
    There is no need to mount a guest image twice
    to inject specific files.  That's especially
    inefficient with libguestfs and was also seen
    to trigger an issue where changes in the first
    guestfs session were lost as the second was initiated.

 ...unt-guest-image-once-when-injecting-files.patch |  177 ++++++++++++++++++++
 openstack-nova.spec                                |    5 +-
 2 files changed, 181 insertions(+), 1 deletions(-)
---
diff --git a/0006-only-mount-guest-image-once-when-injecting-files.patch b/0006-only-mount-guest-image-once-when-injecting-files.patch
new file mode 100644
index 0000000..65efa59
--- /dev/null
+++ b/0006-only-mount-guest-image-once-when-injecting-files.patch
@@ -0,0 +1,177 @@
+From fa16491fc55358dc1db7177fa3350a9621265c1d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?P=C3=A1draig=20Brady?= <pbrady at redhat.com>
+Date: Thu, 21 Jun 2012 15:28:05 +0100
+Subject: [PATCH] only mount guest image once when injecting files
+
+Previously we could incur the costly guest mount operation twice,
+if injecting files with any of net, ssh keys, password, metadata.
+Instead now inject files in the same operation.
+
+Change-Id: I250532af14262962777e354324e9aa89d5ecbea1
+---
+ nova/virt/disk/api.py           |   39 ++++++++++++++-------------------------
+ nova/virt/libvirt/connection.py |   23 +++++++----------------
+ 2 files changed, 21 insertions(+), 41 deletions(-)
+
+diff --git a/nova/virt/disk/api.py b/nova/virt/disk/api.py
+index 6cb19f2..6756ac2 100644
+--- a/nova/virt/disk/api.py
++++ b/nova/virt/disk/api.py
+@@ -224,7 +224,7 @@ class _DiskImage(object):
+ 
+ def inject_data(image,
+                 key=None, net=None, metadata=None, admin_password=None,
+-                partition=None, use_cow=False):
++                files=None, partition=None, use_cow=False):
+     """Injects a ssh key and optionally net data into a disk image.
+ 
+     it will mount the image as a fully partitioned disk and attempt to inject
+@@ -237,21 +237,7 @@ def inject_data(image,
+     if img.mount():
+         try:
+             inject_data_into_fs(img.mount_dir,
+-                                key, net, metadata, admin_password,
+-                                utils.execute)
+-        finally:
+-            img.umount()
+-    else:
+-        raise exception.Error(img.errors)
+-
+-
+-def inject_files(image, files, partition=None, use_cow=False):
+-    """Injects arbitrary files into a disk image"""
+-    img = _DiskImage(image=image, partition=partition, use_cow=use_cow)
+-    if img.mount():
+-        try:
+-            for (path, contents) in files:
+-                _inject_file_into_fs(img.mount_dir, path, contents)
++                                key, net, metadata, admin_password, files)
+         finally:
+             img.umount()
+     else:
+@@ -291,19 +277,22 @@ def destroy_container(img):
+         LOG.exception(_('Failed to remove container: %s'), exn)
+ 
+ 
+-def inject_data_into_fs(fs, key, net, metadata, admin_password, execute):
++def inject_data_into_fs(fs, key, net, metadata, admin_password, files):
+     """Injects data into a filesystem already mounted by the caller.
+     Virt connections can call this directly if they mount their fs
+     in a different way to inject_data
+     """
+     if key:
+-        _inject_key_into_fs(key, fs, execute=execute)
++        _inject_key_into_fs(key, fs)
+     if net:
+-        _inject_net_into_fs(net, fs, execute=execute)
++        _inject_net_into_fs(net, fs)
+     if metadata:
+-        _inject_metadata_into_fs(metadata, fs, execute=execute)
++        _inject_metadata_into_fs(metadata, fs)
+     if admin_password:
+-        _inject_admin_password_into_fs(admin_password, fs, execute=execute)
++        _inject_admin_password_into_fs(admin_password, fs)
++    if files:
++        for (path, contents) in files:
++            _inject_file_into_fs(fs, path, contents)
+ 
+ 
+ def _inject_file_into_fs(fs, path, contents):
+@@ -314,7 +303,7 @@ def _inject_file_into_fs(fs, path, contents):
+           run_as_root=True)
+ 
+ 
+-def _inject_metadata_into_fs(metadata, fs, execute=None):
++def _inject_metadata_into_fs(metadata, fs):
+     metadata_path = os.path.join(fs, "meta.js")
+     metadata = dict([(m.key, m.value) for m in metadata])
+ 
+@@ -322,7 +311,7 @@ def _inject_metadata_into_fs(metadata, fs, execute=None):
+                   process_input=json.dumps(metadata), run_as_root=True)
+ 
+ 
+-def _inject_key_into_fs(key, fs, execute=None):
++def _inject_key_into_fs(key, fs):
+     """Add the given public ssh key to root's authorized_keys.
+ 
+     key is an ssh key string.
+@@ -344,7 +333,7 @@ def _inject_key_into_fs(key, fs, execute=None):
+                   process_input=''.join(key_data), run_as_root=True)
+ 
+ 
+-def _inject_net_into_fs(net, fs, execute=None):
++def _inject_net_into_fs(net, fs):
+     """Inject /etc/network/interfaces into the filesystem rooted at fs.
+ 
+     net is the contents of /etc/network/interfaces.
+@@ -357,7 +346,7 @@ def _inject_net_into_fs(net, fs, execute=None):
+     utils.execute('tee', netfile, process_input=net, run_as_root=True)
+ 
+ 
+-def _inject_admin_password_into_fs(admin_passwd, fs, execute=None):
++def _inject_admin_password_into_fs(admin_passwd, fs):
+     """Set the root password to admin_passwd
+ 
+     admin_password is a root password
+diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
+index 20d96b5..8235a84 100644
+--- a/nova/virt/libvirt/connection.py
++++ b/nova/virt/libvirt/connection.py
+@@ -970,12 +970,6 @@ class LibvirtConnection(driver.ComputeDriver):
+         fp.write(data)
+         return fpath
+ 
+-    def _inject_files(self, instance, files, partition):
+-        disk_path = os.path.join(FLAGS.instances_path,
+-                                 instance['name'], 'disk')
+-        disk.inject_files(disk_path, files, partition=partition,
+-                          use_cow=FLAGS.use_cow_images)
+-
+     @exception.wrap_exception()
+     def get_console_output(self, instance):
+         virt_dom = self._lookup_by_name(instance['name'])
+@@ -1368,11 +1362,13 @@ class LibvirtConnection(driver.ComputeDriver):
+         metadata = instance.get('metadata')
+ 
+         if FLAGS.libvirt_inject_password:
+-            admin_password = instance.get('admin_pass')
++            admin_pass = instance.get('admin_pass')
+         else:
+-            admin_password = None
++            admin_pass = None
++
++        files = instance.get('injected_files')
+ 
+-        if any((key, net, metadata, admin_password)):
++        if any((key, net, metadata, admin_pass, files)):
+             if config_drive:  # Should be True or None by now.
+                 injection_path = basepath('disk.config')
+                 img_id = 'config-drive'
+@@ -1380,13 +1376,13 @@ class LibvirtConnection(driver.ComputeDriver):
+                 injection_path = basepath('disk')
+                 img_id = instance.image_ref
+ 
+-            for injection in ('metadata', 'key', 'net', 'admin_password'):
++            for injection in ('metadata', 'key', 'net', 'admin_pass', 'files'):
+                 if locals()[injection]:
+                     LOG.info(_('Injecting %(injection)s into image %(img_id)s')
+                              % locals(), instance=instance)
+             try:
+                 disk.inject_data(injection_path,
+-                                 key, net, metadata, admin_password,
++                                 key, net, metadata, admin_pass, files,
+                                  partition=target_partition,
+                                  use_cow=FLAGS.use_cow_images)
+ 
+@@ -1404,11 +1400,6 @@ class LibvirtConnection(driver.ComputeDriver):
+         if FLAGS.libvirt_type == 'uml':
+             libvirt_utils.chown(basepath('disk'), 'root')
+ 
+-        files_to_inject = instance.get('injected_files')
+-        if files_to_inject:
+-            self._inject_files(instance, files_to_inject,
+-                               partition=target_partition)
+-
+     @staticmethod
+     def _volume_in_mapping(mount_device, block_device_info):
+         block_device_list = [block_device.strip_dev(vol['mount_device'])
diff --git a/openstack-nova.spec b/openstack-nova.spec
index 0692816..0fde61d 100644
--- a/openstack-nova.spec
+++ b/openstack-nova.spec
@@ -37,6 +37,7 @@ Patch0002: 0002-Ensure-we-don-t-access-the-net-when-building-docs.patch
 Patch0003: 0003-fix-useexisting-deprecation-warnings.patch
 Patch0004: 0004-support-a-configurable-libvirt-injection-partition.patch
 Patch0005: 0005-repeat-fusermount-to-avoid-business.patch
+Patch0006: 0006-only-mount-guest-image-once-when-injecting-files.patch
 
 # This is EPEL specific and not upstream
 Patch100:         openstack-nova-newdeps.patch
@@ -167,6 +168,7 @@ This package contains documentation files for nova.
 %patch0003 -p1
 %patch0004 -p1
 %patch0005 -p1
+%patch0006 -p1
 
 # Apply EPEL patch
 %patch100 -p1
@@ -365,7 +367,8 @@ fi
 
 %changelog
 * Fri Jun 22 2012 Pádraig Brady <P at draigBrady.com> - 2012.1.1-1
-- update to essex stable release 2012.1.1
+- Update to essex stable release 2012.1.1
+- Improve performance and stability of file injection
 
 * Fri Jun 15 2012 Pádraig Brady <P at draigBrady.com> - 2012.1-12
 - update performance and stability fixes from essex stable


More information about the scm-commits mailing list