burnin: move decorators out of classes
[ganeti-local] / tools / burnin
index 817aad6..3d70161 100755 (executable)
@@ -101,7 +101,8 @@ class SimpleOpener(urllib.FancyURLopener):
 OPTIONS = [
   cli.cli_option("-o", "--os", dest="os", default=None,
                  help="OS to use during burnin",
-                 metavar="<OS>"),
+                 metavar="<OS>",
+                 completion_suggest=cli.OPT_COMPL_ONE_OS),
   cli.cli_option("--disk-size", dest="disk_size",
                  help="Disk size (determines disk count)",
                  default="128m", type="string", metavar="<size,size,...>",
@@ -113,9 +114,9 @@ OPTIONS = [
                  default=128, type="unit", metavar="<size>",
                  completion_suggest=("128M 256M 512M 1G 4G 8G"
                                      " 12G 16G").split()),
-  cli.cli_option("-v", "--verbose",
-                 action="store_true", dest="verbose", default=False,
-                 help="print command execution messages to stdout"),
+  cli.VERBOSE_OPT,
+  cli.NOIPCHECK_OPT,
+  cli.NONAMECHECK_OPT,
   cli.cli_option("--no-replace1", dest="do_replace1",
                  help="Skip disk replacement with the same secondary",
                  action="store_false", default=True),
@@ -165,13 +166,15 @@ OPTIONS = [
                  help="Disk template (diskless, file, plain or drbd) [drbd]"),
   cli.cli_option("-n", "--nodes", dest="nodes", default="",
                  help=("Comma separated list of nodes to perform"
-                       " the burnin on (defaults to all nodes)")),
+                       " the burnin on (defaults to all nodes)"),
+                 completion_suggest=cli.OPT_COMPL_MANY_NODES),
   cli.cli_option("-I", "--iallocator", dest="iallocator",
                  default=None, type="string",
                  help=("Perform the allocation using an iallocator"
                        " instead of fixed node spread (node restrictions no"
                        " longer apply, therefore -n/--nodes must not be"
-                       " used")),
+                       " used"),
+                 completion_suggest=cli.OPT_COMPL_ONE_IALLOCATOR),
   cli.cli_option("-p", "--parallel", default=False, action="store_true",
                  dest="parallel",
                  help=("Enable parallelization of some operations in"
@@ -198,6 +201,39 @@ OPTIONS = [
 ARGUMENTS = [cli.ArgInstance(min=1)]
 
 
+def _DoCheckInstances(fn):
+  """Decorator for checking instances.
+
+  """
+  def wrapper(self, *args, **kwargs):
+    val = fn(self, *args, **kwargs)
+    for instance in self.instances:
+      self._CheckInstanceAlive(instance)
+    return val
+
+  return wrapper
+
+
+def _DoBatch(retry):
+  """Decorator for possible batch operations.
+
+  Must come after the _DoCheckInstances decorator (if any).
+
+  @param retry: whether this is a retryable batch, will be
+      passed to StartBatch
+
+  """
+  def wrap(fn):
+    def batched(self, *args, **kwargs):
+      self.StartBatch(retry)
+      val = fn(self, *args, **kwargs)
+      self.CommitQueue()
+      return val
+    return batched
+
+  return wrap
+
+
 class Burner(object):
   """Burner class."""
 
@@ -228,10 +264,10 @@ class Burner(object):
 
   def Feedback(self, msg):
     """Acumulate feedback in our buffer."""
-    self._feed_buf.write("%s %s\n" % (time.ctime(utils.MergeTime(msg[0])),
-                                      msg[2]))
+    formatted_msg = "%s %s" % (time.ctime(utils.MergeTime(msg[0])), msg[2])
+    self._feed_buf.write(formatted_msg + "\n")
     if self.opts.verbose:
-      Log(msg, indent=3)
+      Log(formatted_msg, indent=3)
 
   def MaybeRetry(self, retry_count, msg, fn, *args):
     """Possibly retry a given function execution.
@@ -335,7 +371,7 @@ class Burner(object):
     """
     self.ClearFeedbackBuf()
     job_ids = [cli.SendJob(row[0], cl=self.cl) for row in jobs]
-    Log("Submitted job ID(s) %s" % ", ".join(job_ids), indent=1)
+    Log("Submitted job ID(s) %s" % utils.CommaJoin(job_ids), indent=1)
     results = []
     for jid, (_, iname) in zip(job_ids, jobs):
       Log("waiting for job %s for %s" % (jid, iname), indent=2)
@@ -347,37 +383,6 @@ class Burner(object):
       raise BurninFailure()
     return results
 
-  def _DoCheckInstances(fn):
-    """Decorator for checking instances.
-
-    """
-    def wrapper(self, *args, **kwargs):
-      val = fn(self, *args, **kwargs)
-      for instance in self.instances:
-        self._CheckInstanceAlive(instance)
-      return val
-
-    return wrapper
-
-  def _DoBatch(retry):
-    """Decorator for possible batch operations.
-
-    Must come after the _DoCheckInstances decorator (if any).
-
-    @param retry: whether this is a retryable batch, will be
-        passed to StartBatch
-
-    """
-    def wrap(fn):
-      def batched(self, *args, **kwargs):
-        self.StartBatch(retry)
-        val = fn(self, *args, **kwargs)
-        self.CommitQueue()
-        return val
-      return batched
-
-    return wrap
-
   def ParseOptions(self):
     """Parses the command line options.
 
@@ -421,6 +426,9 @@ class Burner(object):
     if options.nodes and options.iallocator:
       Err("Give either the nodes option or the iallocator option, not both")
 
+    if options.http_check and not options.name_check:
+      Err("Can't enable HTTP checks without name checks")
+
     self.opts = options
     self.instances = args
     self.bep = {
@@ -446,16 +454,20 @@ class Burner(object):
       Err(msg, exit_code=err_code)
     self.nodes = [data[0] for data in result if not (data[1] or data[2])]
 
-    op_diagos = opcodes.OpDiagnoseOS(output_fields=["name", "valid"], names=[])
-    result = self.ExecOp(True, op_diagos)
+    op_diagnose = opcodes.OpDiagnoseOS(output_fields=["name", "valid",
+                                                      "variants"], names=[])
+    result = self.ExecOp(True, op_diagnose)
 
     if not result:
       Err("Can't get the OS list")
 
-    # filter non-valid OS-es
-    os_set = [val[0] for val in result if val[1]]
+    found = False
+    for (name, valid, variants) in result:
+      if valid and self.opts.os in cli.CalculateOSNames(name, variants):
+        found = True
+        break
 
-    if self.opts.os not in os_set:
+    if not found:
       Err("OS '%s' not found" % self.opts.os)
 
   @_DoCheckInstances
@@ -493,7 +505,8 @@ class Burner(object):
                                     pnode=pnode,
                                     snode=snode,
                                     start=True,
-                                    ip_check=True,
+                                    ip_check=self.opts.ip_check,
+                                    name_check=self.opts.name_check,
                                     wait_for_sync=True,
                                     file_driver="loop",
                                     file_storage_dir=None,
@@ -643,7 +656,8 @@ class Burner(object):
                                         pnode=pnode,
                                         snode=snode,
                                         start=True,
-                                        ip_check=True,
+                                        ip_check=self.opts.ip_check,
+                                        name_check=self.opts.name_check,
                                         wait_for_sync=True,
                                         file_storage_dir=None,
                                         file_driver="loop",
@@ -860,8 +874,8 @@ class Burner(object):
       if opts.do_migrate and opts.disk_template == constants.DT_DRBD8:
         self.BurnMigrate()
 
-      if opts.do_move and opts.disk_template in [constants.DT_PLAIN,
-                                                 constants.DT_FILE]:
+      if (opts.do_move and len(self.nodes) > 1 and
+          opts.disk_template in [constants.DT_PLAIN, constants.DT_FILE]):
         self.BurnMove()
 
       if (opts.do_importexport and