Implement more options for “gnt-backup import”
[ganeti-local] / scripts / gnt-instance
index 8d930be..5502334 100755 (executable)
@@ -41,6 +41,11 @@ _SHUTDOWN_INSTANCES = "instances"
 
 _VALUE_TRUE = "true"
 
+_LIST_DEF_FIELDS = [
+  "name", "os", "pnode", "status", "oper_ram",
+  ]
+
+
 def _ExpandMultiNames(mode, names):
   """Expand the given names using the passed mode.
 
@@ -163,7 +168,9 @@ def ListInstances(opts, args):
 
   """
   if opts.output is None:
-    selected_fields = ["name", "os", "pnode", "status", "oper_ram"]
+    selected_fields = _LIST_DEF_FIELDS
+  elif opts.output.startswith("+"):
+    selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",")
   else:
     selected_fields = opts.output.split(",")
 
@@ -176,10 +183,21 @@ def ListInstances(opts, args):
       "snodes": "Secondary_Nodes", "admin_state": "Autostart",
       "oper_state": "Running", "admin_ram": "Configured_memory",
       "oper_ram": "Memory", "disk_template": "Disk_template",
-      "ip": "IP Address", "mac": "MAC Address",
+      "ip": "IP_address", "mac": "MAC_address",
       "bridge": "Bridge", "vcpus": "VCPUs",
       "sda_size": "Disk/0", "sdb_size": "Disk/1",
-      "status": "Status",
+      "status": "Status", "tags": "Tags",
+      "auto_balance": "Auto_balance",
+      "network_port": "Network_port",
+      "kernel_path": "Kernel_path",
+      "initrd_path": "Initrd_path",
+      "hvm_boot_order": "HVM_boot_order",
+      "hvm_acpi": "HVM_ACPI",
+      "hvm_pae": "HVM_PAE",
+      "hvm_cdrom_image_path": "HVM_CDROM_image_path",
+      "hvm_nic_type": "HVM_NIC_type",
+      "hvm_disk_type": "HVM_disk_type",
+      "vnc_bind_address": "VNC_bind_address",
       }
   else:
     headers = None
@@ -191,13 +209,14 @@ def ListInstances(opts, args):
 
   numfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size", "vcpus"]
 
+  list_type_fields = ("tags",)
   # change raw values to nicer strings
   for row in output:
     for idx, field in enumerate(selected_fields):
       val = row[idx]
       if field == "snodes":
         val = ",".join(val) or "-"
-      elif field == "admin_state":
+      elif field == "admin_state" or field == "auto_balance":
         if val:
           val = "yes"
         else:
@@ -215,6 +234,8 @@ def ListInstances(opts, args):
       elif field == "sda_size" or field == "sdb_size":
         if val is None:
           val = "N/A"
+      elif field in list_type_fields:
+        val = ",".join(val)
       row[idx] = str(val)
 
   data = GenerateTable(separator=opts.separator, headers=headers,
@@ -256,6 +277,8 @@ def AddInstance(opts, args):
   else:
     hvm_cdrom_image_path = opts.hvm_cdrom_image_path
 
+  auto_balance = opts.auto_balance == _VALUE_TRUE
+
   op = opcodes.OpCreateInstance(instance_name=instance, mem_size=opts.mem,
                                 disk_size=opts.size, swap_size=opts.swap,
                                 disk_template=opts.disk_template,
@@ -272,7 +295,10 @@ def AddInstance(opts, args):
                                 hvm_boot_order=opts.hvm_boot_order,
                                 hvm_acpi=hvm_acpi, hvm_pae=hvm_pae,
                                 hvm_cdrom_image_path=hvm_cdrom_image_path,
-                                vnc_bind_address=opts.vnc_bind_address)
+                                vnc_bind_address=opts.vnc_bind_address,
+                                hvm_nic_type=opts.hvm_nic_type,
+                                hvm_disk_type=opts.hvm_disk_type,
+                                auto_balance=auto_balance)
 
   SubmitOpCode(op)
   return 0
@@ -288,6 +314,34 @@ def ReinstallInstance(opts, args):
   """
   instance_name = args[0]
 
+  if opts.interactive is True:
+    op = opcodes.OpDiagnoseOS(output_fields=["name", "valid"], names=[])
+    result = SubmitOpCode(op)
+
+    if not result:
+      logger.ToStdout("Can't get the OS list")
+      return 1
+
+    logger.ToStdout("Available OS templates:")
+    number = 0
+    choices = []
+    for entry in result:
+      logger.ToStdout("%3s: %s" % (number, entry[0]))
+      choices.append(("%s" % number, entry[0], entry[0]))
+      number = number + 1
+
+    choices.append(('x', 'exit', 'Exit gnt-instance reinstall'))
+    selected = AskUser("Enter OS template name or number (or x to abort):",
+                       choices)
+
+    if selected == 'exit':
+      logger.ToStdout("User aborted reinstall, exiting")
+      return 1
+
+    os = selected
+  else:
+    os = opts.os
+
   if not opts.force:
     usertext = ("This will reinstall the instance %s and remove"
                 " all data. Continue?") % instance_name
@@ -295,7 +349,7 @@ def ReinstallInstance(opts, args):
       return 1
 
   op = opcodes.OpReinstallInstance(instance_name=instance_name,
-                                   os_type=opts.os)
+                                   os_type=os)
   SubmitOpCode(op)
 
   return 0
@@ -371,6 +425,22 @@ def DeactivateDisks(opts, args):
   return 0
 
 
+def GrowDisk(opts, args):
+  """Command-line interface for _ShutdownInstanceBlockDevices.
+
+  This function takes the instance name, looks for its primary node
+  and the tries to shutdown its block devices on that node.
+
+  """
+  instance = args[0]
+  disk = args[1]
+  amount = utils.ParseUnit(args[2])
+  op = opcodes.OpGrowDisk(instance_name=instance, disk=disk, amount=amount,
+                          wait_for_sync=opts.wait_for_sync)
+  SubmitOpCode(op)
+  return 0
+
+
 def StartupInstance(opts, args):
   """Startup an instance.
 
@@ -539,6 +609,41 @@ def FailoverInstance(opts, args):
   return 0
 
 
+def MigrateInstance(opts, args):
+  """Migrate an instance.
+
+  The migrate is done without shutdown.
+
+  Args:
+    opts - class with options as members
+    args - list with a single element, the instance name
+  Opts used:
+    force - whether to migrate without asking questions.
+
+  """
+  instance_name = args[0]
+  force = opts.force
+
+  if not force:
+    if opts.cleanup:
+      usertext = ("Instance %s will be recovered from a failed migration."
+                  " Note that the migration procedure (including cleanup)" %
+                  (instance_name,))
+    else:
+      usertext = ("Instance %s will be migrated. Note that migration" %
+                  (instance_name,))
+    usertext += (" is **experimental** in this version."
+                " This might impact the instance if anything goes wrong."
+                " Continue?")
+    if not AskUser(usertext):
+      return 1
+
+  op = opcodes.OpMigrateInstance(instance_name=instance_name, live=opts.live,
+                                 cleanup=opts.cleanup)
+  SubmitOpCode(op)
+  return 0
+
+
 def ConnectToInstanceConsole(opts, args):
   """Connect to the console of an instance.
 
@@ -631,7 +736,7 @@ def ShowInstanceConfig(opts, args):
   op = opcodes.OpQueryInstanceData(instances=args)
   result = SubmitOpCode(op)
   hvm_parameters = ("hvm_acpi", "hvm_pae", "hvm_cdrom_image_path",
-                    "hvm_boot_order")
+                    "hvm_boot_order", "hvm_nic_type", "hvm_disk_type")
 
   pvm_parameters = ("kernel_path", "initrd_path")
 
@@ -646,6 +751,8 @@ def ShowInstanceConfig(opts, args):
     buf.write("Instance name: %s\n" % instance["name"])
     buf.write("State: configured to be %s, actual state is %s\n" %
               (instance["config_state"], instance["run_state"]))
+    buf.write("Considered for memory checks in cluster verify: %s\n" %
+              instance["auto_balance"])
     buf.write("  Nodes:\n")
     buf.write("    - primary: %s\n" % instance["pnode"])
     buf.write("    - secondaries: %s\n" % ", ".join(instance["snodes"]))
@@ -671,8 +778,11 @@ def ShowInstanceConfig(opts, args):
       buf.write("    - ACPI support: %s\n" % instance["hvm_acpi"])
       buf.write("    - PAE support: %s\n" % instance["hvm_pae"])
       buf.write("    - virtual CDROM: %s\n" % instance["hvm_cdrom_image_path"])
+      buf.write("    - virtual NIC type: %s\n" %  instance["hvm_nic_type"])
+      buf.write("    - virtual disk type: %s\n" %  instance["hvm_disk_type"])
     if instance.has_key("vnc_bind_address"):
       buf.write("  VNC bind address: %s\n" % instance["vnc_bind_address"])
+      buf.write("  VNC console port: %s\n" % instance["vnc_console_port"])
     buf.write("  Hardware:\n")
     buf.write("    - VCPUs: %d\n" % instance["vcpus"])
     buf.write("    - memory: %dMiB\n" % instance["memory"])
@@ -705,8 +815,9 @@ def SetInstanceParms(opts, args):
   """
   if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or
           opts.kernel_path or opts.initrd_path or opts.hvm_boot_order or
-          opts.hvm_acpi or opts.hvm_acpi or opts.hvm_cdrom_image_path or
-          opts.vnc_bind_address):
+          opts.hvm_acpi or opts.hvm_pae or opts.hvm_cdrom_image_path or
+          opts.vnc_bind_address or opts.hvm_nic_type or opts.hvm_disk_type or
+          opts.auto_balance):
     logger.ToStdout("Please give at least one of the parameters.")
     return 1
 
@@ -717,14 +828,31 @@ def SetInstanceParms(opts, args):
   else:
     hvm_boot_order = opts.hvm_boot_order
 
-  hvm_acpi = opts.hvm_acpi == _VALUE_TRUE
-  hvm_pae = opts.hvm_pae == _VALUE_TRUE
+  if opts.hvm_acpi is None:
+    hvm_acpi = opts.hvm_acpi
+  else:
+    hvm_acpi = opts.hvm_acpi == _VALUE_TRUE
 
-  if ((opts.hvm_cdrom_image_path is not None) and
-      (opts.hvm_cdrom_image_path.lower() == constants.VALUE_NONE)):
-    hvm_cdrom_image_path = None
+  if opts.hvm_pae is None:
+    hvm_pae = opts.hvm_pae
   else:
-    hvm_cdrom_image_path = opts.hvm_cdrom_image_path
+    hvm_pae = opts.hvm_pae == _VALUE_TRUE
+
+  if opts.hvm_nic_type == constants.VALUE_NONE:
+    hvm_nic_type = None
+  else:
+    hvm_nic_type = opts.hvm_nic_type
+
+  if opts.hvm_disk_type == constants.VALUE_NONE:
+    hvm_disk_type = None
+  else:
+    hvm_disk_type = opts.hvm_disk_type
+
+  if opts.auto_balance is None:
+    auto_balance = opts.auto_balance
+  else:
+    auto_balance = opts.auto_balance == _VALUE_TRUE
+
 
   op = opcodes.OpSetInstanceParms(instance_name=args[0], mem=opts.mem,
                                   vcpus=opts.vcpus, ip=opts.ip,
@@ -733,8 +861,13 @@ def SetInstanceParms(opts, args):
                                   initrd_path=opts.initrd_path,
                                   hvm_boot_order=hvm_boot_order,
                                   hvm_acpi=hvm_acpi, hvm_pae=hvm_pae,
-                                  hvm_cdrom_image_path=hvm_cdrom_image_path,
-                                  vnc_bind_address=opts.vnc_bind_address)
+                                  hvm_cdrom_image_path=
+                                  opts.hvm_cdrom_image_path,
+                                  vnc_bind_address=opts.vnc_bind_address,
+                                  hvm_nic_type=hvm_nic_type,
+                                  hvm_disk_type=hvm_disk_type,
+                                  force=opts.force,
+                                  auto_balance=auto_balance)
 
   result = SubmitOpCode(op)
 
@@ -835,6 +968,19 @@ add_opts = [
   make_option("--hvm-acpi", dest="hvm_acpi",
               help="ACPI support for HVM (true|false)",
               metavar="<BOOL>", choices=["true", "false"]),
+  make_option("--hvm-nic-type", dest="hvm_nic_type",
+              help="Type of virtual NIC for HVM "
+              "(rtl8139,ne2k_pci,ne2k_isa,paravirtual)",
+              metavar="NICTYPE", choices=[constants.HT_HVM_NIC_RTL8139,
+                                          constants.HT_HVM_NIC_NE2K_PCI,
+                                          constants.HT_HVM_NIC_NE2K_ISA,
+                                          constants.HT_HVM_DEV_PARAVIRTUAL],
+              default=constants.HT_HVM_NIC_RTL8139),
+  make_option("--hvm-disk-type", dest="hvm_disk_type",
+              help="Type of virtual disks for HVM (ioemu,paravirtual)",
+              metavar="DISKTYPE", choices=[constants.HT_HVM_DEV_IOEMU,
+                                           constants.HT_HVM_DEV_PARAVIRTUAL],
+              default=constants.HT_HVM_DEV_IOEMU,),
   make_option("--hvm-pae", dest="hvm_pae",
               help="PAE support for HVM (true|false)",
               metavar="<BOOL>", choices=["true", "false"]),
@@ -844,11 +990,16 @@ add_opts = [
   make_option("--vnc-bind-address", dest="vnc_bind_address",
               help="bind address for VNC (IP address)",
               default=None, type="string", metavar="<VNCADDRESS>"),
+  make_option("--auto-balance", dest="auto_balance",
+              help="consider instance memory requirements for"
+              " failover in cluster verify (true|false)",
+              default=_VALUE_TRUE,
+              metavar="<BOOL>", choices=["true", "false"]),
   ]
 
 commands = {
   'add': (AddInstance, ARGS_ONE, add_opts,
-          "[opts...] <name>",
+          "[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
           "Creates and adds a new instance to the cluster"),
   'add-mirror': (AddMDDRBDComponent, ARGS_ONE,
                 [DEBUG_OPT, node_opt,
@@ -869,7 +1020,28 @@ commands = {
                 ],
                "[-f] <instance>",
                "Stops the instance and starts it on the backup node, using"
-               " the remote mirror (only for instances of type drbd or remote_raid1)"),
+               " the remote mirror (only for instances of type drbd or"
+               " remote_raid1)"),
+  'migrate': (MigrateInstance, ARGS_ONE,
+               [DEBUG_OPT, FORCE_OPT,
+                make_option("--non-live", dest="live",
+                            default=True, action="store_false",
+                            help="Do a non-live migration (this usually means"
+                            " freeze the instance, save the state,"
+                            " transfer and only then resume running on the"
+                            " secondary node)"),
+                make_option("--cleanup", dest="cleanup",
+                            default=False, action="store_true",
+                            help="Instead of performing the migration, try to"
+                            " recover from a failed cleanup. This is safe"
+                            " to run even if the instance is healthy, but it"
+                            " will create extra replication traffic and "
+                            " disrupt briefly the replication (like during the"
+                            " migration"),
+                ],
+               "[-f] <instance>",
+               "Migrate instance to its secondary node"
+               " (only for instances of type drbd)"),
   'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
            "Show information on the specified instance"),
   'list': (ListInstances, ARGS_NONE,
@@ -877,10 +1049,16 @@ commands = {
            "Lists the instances and their status. The available fields are"
            " (see the man page for details): status, oper_state, oper_ram,"
            " name, os, pnode, snodes, admin_state, admin_ram, disk_template,"
-           " ip, mac, bridge, sda_size, sdb_size, vcpus. The default field"
-           " list is (in order): name, os, pnode, status,"
-           " oper_ram."),
-  'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
+           " ip, mac, bridge, sda_size, sdb_size, vcpus, auto_balance."
+           " The default field"
+           " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS),
+           ),
+  'reinstall': (ReinstallInstance, ARGS_ONE,
+                [DEBUG_OPT, FORCE_OPT, os_opt,
+                 make_option("--interactive", dest="interactive",
+                             action="store_true", default=False,
+                             help="Interactive reinstall, lists available"
+                             " OS templates for selection")],
                 "[-f] <instance>", "Reinstall a stopped instance"),
   'remove': (RemoveInstance, ARGS_ONE,
              [DEBUG_OPT, FORCE_OPT,
@@ -977,9 +1155,30 @@ commands = {
                           help="CDROM image path for HVM"
                           "(absolute path or None)",
                           default=None, type="string", metavar="<CDROMIMAGE>"),
+              make_option("--hvm-nic-type", dest="hvm_nic_type",
+                          help="Type of virtual NIC for HVM "
+                          "(rtl8139,ne2k_pci,ne2k_isa,paravirtual)",
+                          metavar="NICTYPE",
+                          choices=[constants.HT_HVM_NIC_RTL8139,
+                                   constants.HT_HVM_NIC_NE2K_PCI,
+                                   constants.HT_HVM_NIC_NE2K_ISA,
+                                   constants.HT_HVM_DEV_PARAVIRTUAL],
+                          default=None),
+              make_option("--hvm-disk-type", dest="hvm_disk_type",
+                          help="Type of virtual disks for HVM "
+                          "(ioemu,paravirtual)",
+                          metavar="DISKTYPE",
+                          choices=[constants.HT_HVM_DEV_IOEMU,
+                                   constants.HT_HVM_DEV_PARAVIRTUAL],
+                          default=None),
               make_option("--vnc-bind-address", dest="vnc_bind_address",
                           help="bind address for VNC (IP address)",
                           default=None, type="string", metavar="<VNCADDRESS>"),
+              make_option("--auto-balance", dest="auto_balance",
+                          help="consider instance memory requirements for"
+                          " failover in cluster verify (true|false)",
+                          default=None,
+                          metavar="<BOOL>", choices=["true", "false"]),
               ],
              "<instance>", "Alters the parameters of an instance"),
   'shutdown': (ShutdownInstance, ARGS_ANY,
@@ -1018,6 +1217,14 @@ commands = {
   'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
                        "<instance>",
                        "Deactivate an instance's disks"),
+  'grow-disk': (GrowDisk, ARGS_FIXED(3),
+                [DEBUG_OPT,
+                 make_option("--no-wait-for-sync",
+                             dest="wait_for_sync", default=True,
+                             action="store_false",
+                             help="Don't wait for sync (DANGEROUS!)"),
+                 ],
+                "<instance> <disk> <size>", "Grow an instance's disk"),
   'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
                 "<node_name>", "List the tags of the given instance"),
   'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],