Improve cli.SubmitOpCode
[ganeti-local] / tools / burnin
index 0a3a640..cfa848a 100755 (executable)
@@ -26,6 +26,7 @@
 import os
 import sys
 import optparse
+import time
 from itertools import izip, islice, cycle
 from cStringIO import StringIO
 
@@ -62,9 +63,8 @@ class Burner(object):
 
   def __init__(self):
     """Constructor."""
-    logger.SetupLogging(debug=False, program="ganeti/burnin")
+    logger.SetupLogging(program="ganeti/burnin", debug=False)
     self._feed_buf = StringIO()
-    self.proc = mcpu.Processor(feedback=self.Feedback)
     self.nodes = []
     self.instances = []
     self.to_rem = []
@@ -82,15 +82,14 @@ class Burner(object):
 
   def Feedback(self, msg):
     """Acumulate feedback in our buffer."""
-    self._feed_buf.write(msg)
-    self._feed_buf.write("\n")
+    self._feed_buf.write("%s %s\n" % (time.ctime(msg[0]), msg[2]))
     if self.opts.verbose:
       Log(msg)
 
   def ExecOp(self, op):
     """Execute an opcode and manage the exec buffer."""
     self.ClearFeedbackBuf()
-    return self.proc.ExecOpCode(op)
+    return cli.SubmitOpCode(op, feedback_fn=self.Feedback)
 
   def ParseOptions(self):
     """Parses the command line options.
@@ -112,6 +111,8 @@ class Burner(object):
                       default=4 * 1024, type="unit", metavar="<size>")
     parser.add_option("--swap-size", dest="swap_size", help="Swap size",
                       default=4 * 1024, type="unit", metavar="<size>")
+    parser.add_option("--mem-size", dest="mem_size", help="Memory size",
+                      default=128, type="unit", metavar="<size>")
     parser.add_option("-v", "--verbose",
                       action="store_true", dest="verbose", default=False,
                       help="print command execution messages to stdout")
@@ -130,6 +131,10 @@ class Burner(object):
     parser.add_option("--no-startstop", dest="do_startstop",
                       help="Skip instance stop/start", action="store_false",
                       default=True)
+    parser.add_option("--rename", dest="rename", default=None,
+                      help="Give one unused instance name which is taken"
+                           " to start the renaming sequence",
+                      metavar="<instance_name>")
     parser.add_option("-t", "--disk-template", dest="disk_template",
                       choices=("diskless", "file", "plain", "drbd"),
                       default="drbd",
@@ -138,6 +143,11 @@ class Burner(object):
     parser.add_option("-n", "--nodes", dest="nodes", default="",
                       help="Comma separated list of nodes to perform"
                       " the burnin on (defaults to all nodes)")
+    parser.add_option("--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")
 
     options, args = parser.parse_args()
     if len(args) < 1 or options.os is None:
@@ -151,6 +161,10 @@ class Burner(object):
       Log("Unknown disk template '%s'" % options.disk_template)
       sys.exit(1)
 
+    if options.nodes and options.iallocator:
+      Log("Give either the nodes option or the iallocator option, not both")
+      sys.exit(1)
+
     self.opts = options
     self.instances = args
 
@@ -192,8 +206,18 @@ class Burner(object):
                  islice(cycle(self.nodes), 1, None),
                  self.instances)
     for pnode, snode, instance in mytor:
+      if self.opts.iallocator:
+        pnode = snode = None
+        Log("- Add instance %s (iallocator: %s)" %
+              (instance, self.opts.iallocator))
+      elif self.opts.disk_template not in constants.DTS_NET_MIRROR:
+        snode = None
+        Log("- Add instance %s on node %s" % (instance, pnode))
+      else:
+        Log("- Add instance %s on nodes %s/%s" % (instance, pnode, snode))
+
       op = opcodes.OpCreateInstance(instance_name=instance,
-                                    mem_size=128,
+                                    mem_size=self.opts.mem_size,
                                     disk_size=self.opts.os_size,
                                     swap_size=self.opts.swap_size,
                                     disk_template=self.opts.disk_template,
@@ -210,8 +234,8 @@ class Burner(object):
                                     initrd_path=None,
                                     hvm_boot_order=None,
                                     file_driver="loop",
-                                    file_storage_dir=None)
-      Log("- Add instance %s on nodes %s/%s" % (instance, pnode, snode))
+                                    file_storage_dir=None,
+                                    iallocator=self.opts.iallocator)
       self.ExecOp(op)
       self.to_rem.append(instance)
 
@@ -232,9 +256,12 @@ class Burner(object):
     mytor = izip(islice(cycle(self.nodes), 2, None),
                  self.instances)
     for tnode, instance in mytor:
+      if self.opts.iallocator:
+        tnode = None
       op = opcodes.OpReplaceDisks(instance_name=instance,
                                   mode=mode,
                                   remote_node=tnode,
+                                  iallocator=self.opts.iallocator,
                                   disks=["sda", "sdb"])
       Log("- Replace secondary (%s) for instance %s" % (mode, instance))
       self.ExecOp(op)
@@ -260,10 +287,24 @@ class Burner(object):
                  self.instances)
 
     for pnode, snode, enode, instance in mytor:
+
+      if self.opts.iallocator:
+        pnode = snode = None
+        import_log_msg = ("- Import instance %s from node %s (iallocator: %s)" %
+                          (instance, enode, self.opts.iallocator))
+      elif self.opts.disk_template not in constants.DTS_NET_MIRROR:
+        snode = None
+        import_log_msg = ("- Import instance %s from node %s to node %s" %
+                          (instance, enode, pnode))
+      else:
+        import_log_msg = ("- Import instance %s from node %s to nodes %s/%s" %
+                          (instance, enode, pnode, snode))
+
       exp_op = opcodes.OpExportInstance(instance_name=instance,
                                            target_node=enode,
                                            shutdown=True)
-      rem_op = opcodes.OpRemoveInstance(instance_name=instance)
+      rem_op = opcodes.OpRemoveInstance(instance_name=instance,
+                                        ignore_failures=True)
       nam_op = opcodes.OpQueryInstances(output_fields=["name"],
                                            names=[instance])
       full_name = self.ExecOp(nam_op)[0][0]
@@ -282,35 +323,69 @@ class Burner(object):
                                         start=True,
                                         ip_check=True,
                                         wait_for_sync=True,
-                                        mac="auto")
+                                        mac="auto",
+                                        file_storage_dir=None,
+                                        file_driver=None,
+                                        iallocator=self.opts.iallocator)
+      erem_op = opcodes.OpRemoveExport(instance_name=instance)
 
       Log("- Export instance %s to node %s" % (instance, enode))
       self.ExecOp(exp_op)
       Log("- Remove instance %s" % (instance))
       self.ExecOp(rem_op)
       self.to_rem.remove(instance)
-      Log("- Import instance %s from node %s to node %s" %
-          (instance, enode, pnode))
+      Log(import_log_msg)
       self.ExecOp(imp_op)
+      Log("- Remove export of instance %s" % (instance))
+      self.ExecOp(erem_op)
+
       self.to_rem.append(instance)
 
+  def StopInstance(self, instance):
+    """Stop given instance."""
+    op = opcodes.OpShutdownInstance(instance_name=instance)
+    Log("- Shutdown instance %s" % instance)
+    self.ExecOp(op)
+
+  def StartInstance(self, instance):
+    """Start given instance."""
+    op = opcodes.OpStartupInstance(instance_name=instance, force=False)
+    Log("- Start instance %s" % instance)
+    self.ExecOp(op)
+
+  def RenameInstance(self, instance, instance_new):
+    """Rename instance."""
+    op = opcodes.OpRenameInstance(instance_name=instance,
+                                  new_name=instance_new)
+    Log("- Rename instance %s to %s" % (instance, instance_new))
+    self.ExecOp(op)
+
   def StopStart(self):
     """Stop/start the instances."""
     for instance in self.instances:
-      op = opcodes.OpShutdownInstance(instance_name=instance)
-      Log("- Shutdown instance %s" % instance)
-      self.ExecOp(op)
-      op = opcodes.OpStartupInstance(instance_name=instance, force=False)
-      Log("- Start instance %s" % instance)
-      self.ExecOp(op)
+      self.StopInstance(instance)
+      self.StartInstance(instance)
 
   def Remove(self):
     """Remove the instances."""
     for instance in self.to_rem:
-      op = opcodes.OpRemoveInstance(instance_name=instance)
+      op = opcodes.OpRemoveInstance(instance_name=instance,
+                                    ignore_failures=True)
       Log("- Remove instance %s" % instance)
       self.ExecOp(op)
 
+
+  def Rename(self):
+    """Rename the instances."""
+    rename = self.opts.rename
+    for instance in self.instances:
+      self.StopInstance(instance)
+      self.RenameInstance(instance, rename)
+      self.StartInstance(rename)
+      self.StopInstance(rename)
+      self.RenameInstance(rename, instance)
+      self.StartInstance(instance)
+
   def BurninCluster(self):
     """Test a cluster intensively.
 
@@ -348,6 +423,9 @@ class Burner(object):
       if opts.do_startstop:
         self.StopStart()
 
+      if opts.rename:
+        self.Rename()
+
       has_err = False
     finally:
       if has_err:
@@ -363,17 +441,7 @@ def main():
   """Main function"""
 
   burner = Burner()
-  try:
-    utils.Lock('cmd', max_retries=15, debug=True)
-  except errors.LockError, err:
-    logger.ToStderr(str(err))
-    return 1
-  try:
-    retval = burner.BurninCluster()
-  finally:
-    utils.Unlock('cmd')
-    utils.LockCleanup()
-  return retval
+  return burner.BurninCluster()
 
 
 if __name__ == "__main__":