[Pkg-ganeti-devel] [ganeti] 71/165: Add a separate function for running helper VMs

Apollon Oikonomopoulos apoikos at moszumanska.debian.org
Tue Aug 11 13:53:14 UTC 2015


This is an automated email from the git hooks/post-receive script.

apoikos pushed a commit to branch master
in repository ganeti.

commit e8c47afa161a0df3ddd57b291462b99a1bfe27d2
Author: Petr Pudlak <pudlak at google.com>
Date:   Tue Nov 11 10:48:26 2014 +0100

    Add a separate function for running helper VMs
    
    The code for creating an instance and running a zeroing VM was almost
    the same. The new generic function will be also used for other untrusted
    operations such as export and import.
    
    Signed-off-by: Petr Pudlak <pudlak at google.com>
    Reviewed-by: Hrvoje Ribicic <riba at google.com>
---
 Makefile.am                     |   1 +
 lib/cmdlib/backup.py            |  57 +++----------
 lib/cmdlib/instance_create.py   |  51 +++---------
 lib/cmdlib/instance_helpervm.py | 172 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 191 insertions(+), 90 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 7c2d1a9..2be3981 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -489,6 +489,7 @@ cmdlib_PYTHON = \
 	lib/cmdlib/group.py \
 	lib/cmdlib/instance.py \
 	lib/cmdlib/instance_create.py \
+	lib/cmdlib/instance_helpervm.py \
 	lib/cmdlib/instance_migration.py \
 	lib/cmdlib/instance_operation.py \
 	lib/cmdlib/instance_query.py \
diff --git a/lib/cmdlib/backup.py b/lib/cmdlib/backup.py
index 3486291..84ceecf 100644
--- a/lib/cmdlib/backup.py
+++ b/lib/cmdlib/backup.py
@@ -39,13 +39,12 @@ from ganeti import errors
 from ganeti import locking
 from ganeti import masterd
 from ganeti import utils
-from ganeti.utils import retry
 
 from ganeti.cmdlib.base import NoHooksLU, LogicalUnit
-from ganeti.cmdlib.common import CheckNodeOnline, ExpandNodeUuidAndName, \
-  IsInstanceRunning, DetermineImageSize
+from ganeti.cmdlib.common import CheckNodeOnline, ExpandNodeUuidAndName
+from ganeti.cmdlib.instance_helpervm import RunWithHelperVM
 from ganeti.cmdlib.instance_storage import StartInstanceDisks, \
-  ShutdownInstanceDisks, TemporaryDisk, ImageDisks
+  ShutdownInstanceDisks
 from ganeti.cmdlib.instance_utils import GetClusterDomainSecret, \
   BuildInstanceHookEnvByObject, CheckNodeNotDrained, RemoveInstance, \
   CheckCompressionTool
@@ -374,54 +373,16 @@ class LUBackupExport(LogicalUnit):
     assert self.op.zeroing_timeout_per_mib is not None
 
     zeroing_image = self.cfg.GetZeroingImage()
-    src_node_uuid = self.instance.primary_node
-
-    try:
-      disk_size = DetermineImageSize(self, zeroing_image, src_node_uuid)
-    except errors.OpExecError, err:
-      raise errors.OpExecError("Could not create temporary disk for zeroing:"
-                               " %s", err)
 
     # Calculate the sum prior to adding the temporary disk
     instance_disks_size_sum = self._InstanceDiskSizeSum()
+    timeout = self.op.zeroing_timeout_fixed + \
+              self.op.zeroing_timeout_per_mib * instance_disks_size_sum
 
-    with TemporaryDisk(self,
-                       self.instance,
-                       [(constants.DT_PLAIN, constants.DISK_RDWR, disk_size)],
-                       feedback_fn):
-      feedback_fn("Activating instance disks")
-      StartInstanceDisks(self, self.instance, False)
-
-      feedback_fn("Imaging disk with zeroing image")
-      ImageDisks(self, self.instance, zeroing_image)
-
-      feedback_fn("Starting instance with zeroing image")
-      result = self.rpc.call_instance_start(src_node_uuid,
-                                            (self.instance, [], []),
-                                            False, self.op.reason)
-      result.Raise("Could not start instance %s when using the zeroing image "
-                   "%s" % (self.instance.name, zeroing_image))
-
-      # First wait for the instance to start up
-      running_check = lambda: IsInstanceRunning(self, self.instance,
-                                                prereq=False)
-      instance_up = retry.SimpleRetry(True, running_check, 5.0,
-                                      self.op.shutdown_timeout)
-      if not instance_up:
-        raise errors.OpExecError("Could not boot instance when using the "
-                                 "zeroing image %s" % zeroing_image)
-
-      feedback_fn("Instance is up, now awaiting shutdown")
-
-      # Then for it to be finished, detected by its shutdown
-      timeout = self.op.zeroing_timeout_fixed + \
-                self.op.zeroing_timeout_per_mib * instance_disks_size_sum
-      instance_up = retry.SimpleRetry(False, running_check, 20.0, timeout)
-      if instance_up:
-        self.LogWarning("Zeroing not completed prior to timeout; instance will"
-                        "be shut down forcibly")
-
-    feedback_fn("Zeroing completed!")
+    RunWithHelperVM(self, self.instance, zeroing_image,
+                    self.op.shutdown_timeout, timeout,
+                    log_prefix="Zeroing free disk space",
+                    feedback_fn=feedback_fn)
 
   def StartInstance(self, feedback_fn, src_node_uuid):
     """Send the node instructions to start the instance.
diff --git a/lib/cmdlib/instance_create.py b/lib/cmdlib/instance_create.py
index 2178b4a..e13b06d 100644
--- a/lib/cmdlib/instance_create.py
+++ b/lib/cmdlib/instance_create.py
@@ -45,7 +45,6 @@ from ganeti import netutils
 from ganeti import objects
 from ganeti import pathutils
 from ganeti import utils
-from ganeti.utils import retry
 from ganeti import serializer
 
 from ganeti.cmdlib.base import LogicalUnit
@@ -56,14 +55,14 @@ from ganeti.cmdlib.common import \
   IsExclusiveStorageEnabledNode, CheckHVParams, CheckOSParams, \
   ExpandNodeUuidAndName, \
   IsValidDiskAccessModeCombination, \
-  CheckDiskTemplateEnabled, CheckIAllocatorOrNode, CheckOSImage, \
-  IsInstanceRunning, DetermineImageSize
+  CheckDiskTemplateEnabled, CheckIAllocatorOrNode, CheckOSImage
+from ganeti.cmdlib.instance_helpervm import RunWithHelperVM
 from ganeti.cmdlib.instance_storage import CalculateFileStorageDir, \
   CheckNodesFreeDiskPerVG, CheckRADOSFreeSpace, CheckSpindlesExclusiveStorage, \
   ComputeDiskSizePerVG, CreateDisks, \
-  GenerateDiskTemplate, CommitDisks, StartInstanceDisks, \
+  GenerateDiskTemplate, CommitDisks, \
   WaitForSync, ComputeDisks, \
-  TemporaryDisk, ImageDisks, WipeDisks
+  ImageDisks, WipeDisks
 from ganeti.cmdlib.instance_utils import \
   CheckNodeNotDrained, CopyLockList, \
   ReleaseLocks, CheckNodeVmCapable, \
@@ -1395,8 +1394,6 @@ class LUInstanceCreate(LogicalUnit):
       raise errors.OpExecError("Cannot create install instance because an"
                                " install image has not been specified")
 
-    disk_size = DetermineImageSize(self, install_image, instance.primary_node)
-
     env = self.GetOsInstallPackageEnvironment(
       instance,
       constants.OS_SCRIPT_CREATE_UNTRUSTED)
@@ -1405,41 +1402,11 @@ class LUInstanceCreate(LogicalUnit):
                    osparams_private=self.op.osparams_private,
                    osparams_secret=self.op.osparams_secret)
 
-    with TemporaryDisk(self,
-                       instance,
-                       [(constants.DT_PLAIN, constants.DISK_RDWR, disk_size)],
-                       feedback_fn):
-      feedback_fn("Activating instance disks")
-      StartInstanceDisks(self, instance, False)
-
-      feedback_fn("Imaging disk with install image")
-      ImageDisks(self, instance, install_image)
-
-      feedback_fn("Starting instance with install image")
-      result = self.rpc.call_instance_start(instance.primary_node,
-                                            (instance, [], []),
-                                            False, self.op.reason)
-      result.Raise("Could not start instance '%s' with the install image '%s'"
-                   % (instance.name, install_image))
-
-      # First wait for the instance to start up
-      running_check = lambda: IsInstanceRunning(self, instance, prereq=False)
-      instance_up = retry.SimpleRetry(True, running_check, 5.0,
-                                      self.op.helper_startup_timeout)
-      if not instance_up:
-        raise errors.OpExecError("Could not boot instance using install image"
-                                 " '%s'" % install_image)
-
-      feedback_fn("Instance is up, now awaiting shutdown")
-
-      # Then for it to be finished, detected by its shutdown
-      instance_up = retry.SimpleRetry(False, running_check, 20.0,
-                                      self.op.helper_shutdown_timeout)
-      if instance_up:
-        self.LogWarning("Installation not completed prior to timeout, shutting"
-                        " down instance forcibly")
-
-    feedback_fn("Installation complete")
+    RunWithHelperVM(self, instance, install_image,
+                    self.op.helper_startup_timeout,
+                    self.op.helper_shutdown_timeout,
+                    log_prefix="Running OS create script",
+                    feedback_fn=feedback_fn)
 
   def Exec(self, feedback_fn):
     """Create and add the instance to the cluster.
diff --git a/lib/cmdlib/instance_helpervm.py b/lib/cmdlib/instance_helpervm.py
new file mode 100644
index 0000000..5fba97b
--- /dev/null
+++ b/lib/cmdlib/instance_helpervm.py
@@ -0,0 +1,172 @@
+#
+#
+
+# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+"""Functions for running helper virtual machines to perform tasks on instances.
+
+"""
+
+import contextlib
+
+from ganeti import constants
+from ganeti import errors
+from ganeti.utils import retry
+
+from ganeti.cmdlib.common import IsInstanceRunning, DetermineImageSize
+from ganeti.cmdlib.instance_storage import StartInstanceDisks, \
+  TemporaryDisk, ImageDisks
+
+
+ at contextlib.contextmanager
+def HelperVM(lu, instance, vm_image, startup_timeout, vm_timeout,
+             log_prefix=None, feedback_fn=None):
+  """Runs a given helper VM for a given instance.
+
+  @type lu: L{LogicalUnit}
+  @param lu: the lu on whose behalf we execute
+  @type instance: L{objects.Instance}
+  @param instance: the instance definition
+  @type vm_image: string
+  @param vm_image: the name of the helper VM image to dump on a temporary disk
+  @type startup_timeout: int
+  @param startup_timeout: how long to wait for the helper VM to start up
+  @type vm_timeout: int
+  @param vm_timeout: how long to wait for the helper VM to finish its work
+  @type log_prefix: string
+  @param log_prefix: a prefix for all log messages
+  @type feedback_fn: function
+  @param feedback_fn: Function used to log progress
+
+  """
+  if log_prefix:
+    add_prefix = lambda msg: "%s: %s" % (log_prefix, msg)
+  else:
+    add_prefix = lambda msg: msg
+
+  if feedback_fn is not None:
+    log_feedback = lambda msg: feedback_fn(add_prefix(msg))
+  else:
+    log_feedback = lambda _: None
+
+  try:
+    disk_size = DetermineImageSize(lu, vm_image, instance.primary_node)
+  except errors.OpExecError, err:
+    raise errors.OpExecError("Could not create temporary disk: %s", err)
+
+  with TemporaryDisk(lu,
+                     instance,
+                     [(constants.DT_PLAIN, constants.DISK_RDWR, disk_size)],
+                     log_feedback):
+    log_feedback("Activating helper VM's temporary disks")
+    StartInstanceDisks(lu, instance, False)
+
+    log_feedback("Imaging temporary disks with image %s" % (vm_image, ))
+    ImageDisks(lu, instance, vm_image)
+
+    log_feedback("Starting helper VM")
+    result = lu.rpc.call_instance_start(instance.primary_node,
+                                        (instance, [], []),
+                                        False, lu.op.reason)
+    result.Raise(add_prefix("Could not start helper VM with image %s" %
+                            (vm_image, )))
+
+    # First wait for the instance to start up
+    running_check = lambda: IsInstanceRunning(lu, instance, prereq=False)
+    instance_up = retry.SimpleRetry(True, running_check, 5.0,
+                                    startup_timeout)
+    if not instance_up:
+      raise errors.OpExecError(add_prefix("Could not boot instance using"
+                                          " image %s" % (vm_image, )))
+
+    log_feedback("Helper VM is up")
+
+    def cleanup():
+      log_feedback("Waiting for helper VM to finish")
+
+      # Then for it to be finished, detected by its shutdown
+      instance_up = retry.SimpleRetry(False, running_check, 20.0, vm_timeout)
+      if instance_up:
+        lu.LogWarning(add_prefix("Helper VM has not finished within the"
+                                 " timeout; shutting it down forcibly"))
+        return \
+          lu.rpc.call_instance_shutdown(instance.primary_node,
+                                        instance,
+                                        constants.DEFAULT_SHUTDOWN_TIMEOUT,
+                                        lu.op.reason)
+      else:
+        return None
+
+    # Run the inner block and handle possible errors
+    try:
+      yield
+    except Exception:
+      # if the cleanup failed for some reason, log it and just re-raise
+      result = cleanup()
+      if result:
+        result.Warn(add_prefix("Could not shut down helper VM with image"
+                               " %s within timeout" % (vm_image, )))
+        log_feedback("Error running helper VM with image %s" %
+                     (vm_image, ))
+      raise
+    else:
+      result = cleanup()
+      # if the cleanup failed for some reason, throw an exception
+      if result:
+        result.Raise(add_prefix("Could not shut down helper VM with image %s"
+                                " within timeout" % (vm_image, )))
+        raise errors.OpExecError("Error running helper VM with image %s" %
+                                 (vm_image, ))
+
+  log_feedback("Helper VM execution completed")
+
+
+def RunWithHelperVM(lu, instance, vm_image, startup_timeout, vm_timeout,
+                    log_prefix=None, feedback_fn=None):
+  """Runs a given helper VM for a given instance.
+
+  @type lu: L{LogicalUnit}
+  @param lu: the lu on whose behalf we execute
+  @type instance: L{objects.Instance}
+  @param instance: the instance definition
+  @type vm_image: string
+  @param vm_image: the name of the helper VM image to dump on a temporary disk
+  @type startup_timeout: int
+  @param startup_timeout: how long to wait for the helper VM to start up
+  @type vm_timeout: int
+  @param vm_timeout: how long to wait for the helper VM to finish its work
+  @type log_prefix: string
+  @param log_prefix: a prefix for all log messages
+  @type feedback_fn: function
+  @param feedback_fn: Function used to log progress
+
+
+  """
+  with HelperVM(lu, instance, vm_image, startup_timeout, vm_timeout,
+                log_prefix=log_prefix, feedback_fn=feedback_fn):
+    pass

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ganeti/ganeti.git



More information about the Pkg-ganeti-devel mailing list