From def7d00ded863b0647ef18d611c2832b1336d06a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <pbrady@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 ad084b2..9f85419 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'])
