Merge branch 'master' into next
authorGuido Trotter <ultrotter@google.com>
Fri, 17 Jul 2009 11:40:17 +0000 (13:40 +0200)
committerGuido Trotter <ultrotter@google.com>
Fri, 17 Jul 2009 11:40:17 +0000 (13:40 +0200)
* master:
  Update NEWS and version for 2.0.2 release
  Improve the description of node flags in man page
  Change default stripe count to 1
  Use full-stripe size in LVM growth
  RAPI: implement instance reinstall

NEWS
configure.ac
lib/bdev.py
lib/rapi/baserlib.py
lib/rapi/connector.py
lib/rapi/rlib2.py
man/gnt-node.sgml

diff --git a/NEWS b/NEWS
index 6709d3f..cbbf76a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,33 @@
+Version 2.0.2
+  - Added experimental support for stripped logical volumes; this should
+    enhance performance but comes with a higher complexity in the block
+    device handling; stripping is only enabled when passing
+    --with-lvm-stripecount=N to configure, but codepaths are affected
+    even in the non-stripped mode
+  - Improved resiliency against transient failures at the end of DRBD
+    resyncs, and in general of DRBD resync checks
+  - Fixed a couple of issues with exports and snapshot errors
+  - Fixed a couple of issues in instance listing
+  - Added display of the disk size in “gnt-instance info”
+  - Fixed checking for valid OSes in instance creation
+  - Fixed handling of the ‘vcpus’ parameter in instance listing and in
+    general of invalid parameters
+  - Fixed http server library, and thus RAPI, to handle invalid
+    username/password combinations correctly; this means that now they
+    report unauthorized for queries too, not only for modifications,
+    allowing earlier detect of configuration problems
+  - Added a new ‘role’ node list field, equivalent to the master/master
+    candidate/drained/offline flags combinations
+  - Fixed cluster modify and changes of candidate pool size
+  - Fixed cluster verify error messages for wrong files on regular nodes
+  - Fixed a couple of issues with node demotion from master candidate
+    role
+  - Fixed node readd issues
+  - Added non-interactive mode for “ganeti-masterd --no-voting” startup
+  - Added a new ‘--no-voting’ option for masterfailover to fix failover
+    on two-nodes clusters when the former master node is unreachable
+  - Added instance reinstall over RAPI
+
 Version 2.0.1
   - added -H/-B startup parameters to gnt-instance, which will allow
     re-adding the start in single-user option (regression from 1.2)
index 76eeb36..12ba06d 100644 (file)
@@ -1,7 +1,7 @@
 # Configure script for Ganeti
 m4_define([gnt_version_major], [2])
 m4_define([gnt_version_minor], [0])
-m4_define([gnt_version_revision], [1])
+m4_define([gnt_version_revision], [2])
 m4_define([gnt_version_suffix], [])
 m4_define([gnt_version_full],
           m4_format([%d.%d.%d%s],
@@ -123,10 +123,10 @@ AC_SUBST(SOCAT_PATH, $socat_path)
 AC_ARG_WITH([lvm-stripecount],
   [AS_HELP_STRING([--with-lvm-stripecount=NUM],
     [the number of stripes to use for LVM volumes]
-    [ (default is 3)]
+    [ (default is 1)]
   )],
   [lvm_stripecount="$withval"],
-  [lvm_stripecount="3"])
+  [lvm_stripecount="1"])
 AC_SUBST(LVM_STRIPECOUNT, $lvm_stripecount)
 
 # Check common programs
index 4971b53..9ac41e5 100644 (file)
@@ -299,7 +299,7 @@ class LogicalVolume(BlockDev):
     self._vg_name, self._lv_name = unique_id
     self.dev_path = "/dev/%s/%s" % (self._vg_name, self._lv_name)
     self._degraded = True
-    self.major = self.minor = None
+    self.major = self.minor = self.pe_size = self.stripe_count = None
     self.Attach()
 
   @classmethod
@@ -411,19 +411,30 @@ class LogicalVolume(BlockDev):
     """
     self.attached = False
     result = utils.RunCmd(["lvs", "--noheadings", "--separator=,",
-                           "-olv_attr,lv_kernel_major,lv_kernel_minor",
-                           self.dev_path])
+                           "--units=m", "--nosuffix",
+                           "-olv_attr,lv_kernel_major,lv_kernel_minor,"
+                           "vg_extent_size,stripes", self.dev_path])
     if result.failed:
       logging.error("Can't find LV %s: %s, %s",
                     self.dev_path, result.fail_reason, result.output)
       return False
-    out = result.stdout.strip().rstrip(',')
+    # the output can (and will) have multiple lines for multi-segment
+    # LVs, as the 'stripes' parameter is a segment one, so we take
+    # only the last entry, which is the one we're interested in; note
+    # that with LVM2 anyway the 'stripes' value must be constant
+    # across segments, so this is a no-op actually
+    out = result.stdout.splitlines()
+    if not out: # totally empty result? splitlines() returns at least
+                # one line for any non-empty string
+      logging.error("Can't parse LVS output, no lines? Got '%s'", str(out))
+      return False
+    out = out[-1].strip().rstrip(',')
     out = out.split(",")
-    if len(out) != 3:
-      logging.error("Can't parse LVS output, len(%s) != 3", str(out))
+    if len(out) != 5:
+      logging.error("Can't parse LVS output, len(%s) != 5", str(out))
       return False
 
-    status, major, minor = out[:3]
+    status, major, minor, pe_size, stripes = out
     if len(status) != 6:
       logging.error("lvs lv_attr is not 6 characters (%s)", status)
       return False
@@ -434,8 +445,22 @@ class LogicalVolume(BlockDev):
     except ValueError, err:
       logging.error("lvs major/minor cannot be parsed: %s", str(err))
 
+    try:
+      pe_size = int(float(pe_size))
+    except (TypeError, ValueError), err:
+      logging.error("Can't parse vg extent size: %s", err)
+      return False
+
+    try:
+      stripes = int(stripes)
+    except (TypeError, ValueError), err:
+      logging.error("Can't parse the number of stripes: %s", err)
+      return False
+
     self.major = major
     self.minor = minor
+    self.pe_size = pe_size
+    self.stripe_count = stripes
     self._degraded = status[0] == 'v' # virtual volume, i.e. doesn't backing
                                       # storage
     self.attached = True
@@ -554,6 +579,13 @@ class LogicalVolume(BlockDev):
     """Grow the logical volume.
 
     """
+    if self.pe_size is None or self.stripe_count is None:
+      if not self.Attach():
+        _ThrowError("Can't attach to LV during Grow()")
+    full_stripe_size = self.pe_size * self.stripe_count
+    rest = amount % full_stripe_size
+    if rest != 0:
+      amount += full_stripe_size - rest
     # we try multiple algorithms since the 'best' ones might not have
     # space available in the right place, but later ones might (since
     # they have less constraints); also note that only recent LVM
@@ -1609,7 +1641,8 @@ class DRBD8(BaseDRBD):
     if len(self._children) != 2 or None in self._children:
       _ThrowError("drbd%d: cannot grow diskless device", self.minor)
     self._children[0].Grow(amount)
-    result = utils.RunCmd(["drbdsetup", self.dev_path, "resize"])
+    result = utils.RunCmd(["drbdsetup", self.dev_path, "resize", "-s",
+                           "%dm" % (self.size + amount)])
     if result.failed:
       _ThrowError("drbd%d: resize failed: %s", self.minor, result.output)
 
index 270d61a..77a7e62 100644 (file)
@@ -250,6 +250,18 @@ class R_Generic(object):
                                 " '%s' parameter" % (name,))
     return val
 
+  def _checkStringVariable(self, name, default=None):
+    """Return the parsed value of an int argument.
+
+    """
+    val = self.queryargs.get(name, default)
+    if isinstance(val, list):
+      if val:
+        val = val[0]
+      else:
+        val = default
+    return val
+
   def getBodyParameter(self, name, *args):
     """Check and return the value for a given parameter.
 
index fcc4f2d..c6270ab 100644 (file)
@@ -163,6 +163,8 @@ CONNECTOR.update({
   re.compile(r'^/2/instances/([\w\._-]+)/tags$'): rlib2.R_2_instances_name_tags,
   re.compile(r'^/2/instances/([\w\._-]+)/reboot$'):
       rlib2.R_2_instances_name_reboot,
+  re.compile(r'^/2/instances/([\w\._-]+)/reinstall$'):
+      rlib2.R_2_instances_name_reinstall,
   re.compile(r'^/2/instances/([\w\._-]+)/shutdown$'):
       rlib2.R_2_instances_name_shutdown,
   re.compile(r'^/2/instances/([\w\._-]+)/startup$'):
index 738f86f..45f649b 100644 (file)
@@ -493,6 +493,36 @@ class R_2_instances_name_shutdown(baserlib.R_Generic):
     return baserlib.SubmitJob([op])
 
 
+class R_2_instances_name_reinstall(baserlib.R_Generic):
+  """/2/instances/[instance_name]/reinstall resource.
+
+  Implements an instance reinstall.
+
+  """
+
+  DOC_URI = "/2/instances/[instance_name]/reinstall"
+
+  def POST(self):
+    """Reinstall an instance.
+
+    The URI takes os=name and nostartup=[0|1] optional
+    parameters. By default, the instance will be started
+    automatically.
+
+    """
+    instance_name = self.items[0]
+    ostype = self._checkStringVariable('os')
+    nostartup = self._checkIntVariable('nostartup')
+    ops = [
+      opcodes.OpShutdownInstance(instance_name=instance_name),
+      opcodes.OpReinstallInstance(instance_name=instance_name, os_type=ostype),
+      ]
+    if not nostartup:
+      ops.append(opcodes.OpStartupInstance(instance_name=instance_name,
+                                           force=False))
+    return baserlib.SubmitJob(ops)
+
+
 class _R_Tags(baserlib.R_Generic):
   """ Quasiclass for tagging resources
 
index 5071e5a..278a633 100644 (file)
           <varlistentry>
             <term>drained</term>
             <listitem>
-              <simpara>whether the node is drained or not</simpara>
+              <simpara>whether the node is drained or not; the cluster
+              still communicates with drained nodes but excludes them
+              from allocation operations</simpara>
             </listitem>
           </varlistentry>
           <varlistentry>
             <term>offline</term>
             <listitem>
-              <simpara>whether the node is offline or not</simpara>
+              <simpara>whether the node is offline or not; if offline,
+              the cluster does not communicate with offline nodes;
+              useful for nodes that are not reachable in order to
+              avoid delays</simpara>
             </listitem>
           </varlistentry>
           <varlistentry>