Merge commit 'origin/next' into branch-2.1
authorIustin Pop <iustin@google.com>
Thu, 13 Aug 2009 11:15:33 +0000 (13:15 +0200)
committerIustin Pop <iustin@google.com>
Thu, 13 Aug 2009 11:41:42 +0000 (13:41 +0200)
* commit 'origin/next': (28 commits)
  Fix a typo in InitCluster
  Ignore results from drained nodes in iallocator
  Ship the ethers hook
  Ethers hook, compatibility with old lockfile
  Remove a few unused imports from noded/masterd
  Move HVM's device_model to a hypervisor parameter
  Implement the KERNEL_PATH parameter for xen-hvm
  Upgrade be/hv params with default values
  Add cluster-init --no-etc-hosts parameter
  objects: add configuration upgrade system
  Update NEWS and version for 2.0.3 release
  example ethers hook: use lockfile-progs
  ethers hook lock: use logger not echo
  ethers hook: reduce the probability of data loss
  devel/upload: revert rsync -p
  export: add meaningful exit code
  Fix detecting of errors in export
  Implement gnt-cluster check-disk-sizes
  rpc: add rpc call for getting disk size
  bdev: Add function for reading actual disk size
  ...

Conflicts:
daemons/ganeti-masterd   - trivial, kept 2.1 version
lib/bootstrap.py         - trivial, kept 2.1 version
lib/cmdlib.py            - integrated the 2.0.3 changes
lib/constants.py         - trivial
lib/hypervisor/hv_xen.py - trivial, kept 2.1 version
lib/objects.py           - trivial, kept 2.1 version
lib/opcodes.py           - integrated the 2.0.3 changes

Signed-off-by: Iustin Pop <iustin@google.com>

19 files changed:
1  2 
Makefile.am
configure.ac
daemons/ganeti-masterd
daemons/ganeti-noded
doc/iallocator.rst
lib/backend.py
lib/bdev.py
lib/cmdlib.py
lib/constants.py
lib/mcpu.py
lib/objects.py
lib/opcodes.py
lib/rpc.py
man/gnt-backup.sgml
man/gnt-cluster.sgml
man/gnt-instance.sgml
scripts/gnt-backup
scripts/gnt-cluster
scripts/gnt-instance

diff --cc Makefile.am
Simple merge
diff --cc configure.ac
Simple merge
Simple merge
Simple merge
@@@ -223,11 -223,15 +223,15 @@@ node
  
    No allocations should be made on nodes having either the ``drained``
    or ``offline`` flags set. More details about these of node status
 -  flags is available in the manpage *ganeti(7)*.
 +  flags is available in the manpage :manpage:`ganeti(7)`.
  
+ .. [*] Note that no run-time data is present for offline or drained nodes;
+    this means the tags total_memory, reserved_memory, free_memory, total_disk,
+    free_disk, total_cpus, i_pri_memory and i_pri_up memory will be absent
  
- Respone message
- ~~~~~~~~~~~~~~~
+ Response message
+ ~~~~~~~~~~~~~~~~
  
  The response message is much more simple than the input one. It is
  also a dict having three keys:
diff --cc lib/backend.py
@@@ -1425,14 -1458,38 +1425,40 @@@ def BlockdevFind(disk)
    try:
      rbd = _RecursiveFindBD(disk)
    except errors.BlockDeviceError, err:
 -    return (False, str(err))
 +    _Fail("Failed to find device: %s", err, exc=True)
 +
    if rbd is None:
 -    return (True, None)
 -  return (True, (rbd.dev_path, rbd.major, rbd.minor) + rbd.GetSyncStatus())
 +    return None
 +
 +  return rbd.GetSyncStatus()
  
  
+ def BlockdevGetsize(disks):
+   """Computes the size of the given disks.
+   If a disk is not found, returns None instead.
+   @type disks: list of L{objects.Disk}
+   @param disks: the list of disk to compute the size for
+   @rtype: list
+   @return: list with elements None if the disk cannot be found,
+       otherwise the size
+   """
+   result = []
+   for cf in disks:
+     try:
+       rbd = _RecursiveFindBD(cf)
+     except errors.BlockDeviceError, err:
+       result.append(None)
+       continue
+     if rbd is None:
+       result.append(None)
+     else:
+       result.append(rbd.GetActualSize())
+   return result
  def UploadFile(file_name, data, mode, uid, gid, atime, mtime):
    """Write a file to the filesystem.
  
@@@ -1834,11 -1867,14 +1860,11 @@@ def ExportSnapshot(disk, dest_node, ins
    # all commands have been checked, so we're safe to combine them
    command = '|'.join([expcmd, comprcmd, utils.ShellQuoteArgs(remotecmd)])
  
-   result = utils.RunCmd(command, env=export_env)
+   result = utils.RunCmd(["bash", "-c", command], env=export_env)
  
    if result.failed:
 -    logging.error("os snapshot export command '%s' returned error: %s"
 -                  " output: %s", command, result.fail_reason, result.output)
 -    return False
 -
 -  return True
 +    _Fail("OS snapshot export command '%s' returned error: %s"
 +          " output: %s", command, result.fail_reason, result.output)
  
  
  def FinalizeExport(instance, snap_disks):
diff --cc lib/bdev.py
Simple merge
diff --cc lib/cmdlib.py
@@@ -3044,9 -2743,12 +3147,12 @@@ def _AssembleInstanceDisks(lu, instance
    # 1st pass, assemble on all nodes in secondary mode
    for inst_disk in instance.disks:
      for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
+       if ignore_size:
+         node_disk = node_disk.Copy()
+         node_disk.UnsetSize()
        lu.cfg.SetDiskID(node_disk, node)
        result = lu.rpc.call_blockdev_assemble(node, node_disk, iname, False)
 -      msg = result.RemoteFailMsg()
 +      msg = result.fail_msg
        if msg:
          lu.proc.LogWarning("Could not prepare block device %s on node %s"
                             " (is_primary=False, pass=1): %s",
      for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
        if node != instance.primary_node:
          continue
+       if ignore_size:
+         node_disk = node_disk.Copy()
+         node_disk.UnsetSize()
        lu.cfg.SetDiskID(node_disk, node)
        result = lu.rpc.call_blockdev_assemble(node, node_disk, iname, True)
 -      msg = result.RemoteFailMsg()
 +      msg = result.fail_msg
        if msg:
          lu.proc.LogWarning("Could not prepare block device %s on node %s"
                             " (is_primary=True, pass=2): %s",
@@@ -7122,19 -6475,20 +7231,21 @@@ class LUExportInstance(LogicalUnit)
      for disk in instance.disks:
        self.cfg.SetDiskID(disk, src_node)
  
+     # per-disk results
+     dresults = []
      try:
        for idx, disk in enumerate(instance.disks):
 -        # new_dev_name will be a snapshot of an lvm leaf of the one we passed
 -        new_dev_name = self.rpc.call_blockdev_snapshot(src_node, disk)
 -        if new_dev_name.failed or not new_dev_name.data:
 -          self.LogWarning("Could not snapshot disk/%d on node %s",
 -                          idx, src_node)
 +        # result.payload will be a snapshot of an lvm leaf of the one we passed
 +        result = self.rpc.call_blockdev_snapshot(src_node, disk)
 +        msg = result.fail_msg
 +        if msg:
 +          self.LogWarning("Could not snapshot disk/%s on node %s: %s",
 +                          idx, src_node, msg)
            snap_disks.append(False)
          else:
 +          disk_id = (vgname, result.payload)
            new_dev = objects.Disk(dev_type=constants.LD_LV, size=disk.size,
 -                                 logical_id=(vgname, new_dev_name.data),
 -                                 physical_id=(vgname, new_dev_name.data),
 +                                 logical_id=disk_id, physical_id=disk_id,
                                   iv_name=disk.iv_name)
            snap_disks.append(new_dev)
  
        if dev:
          result = self.rpc.call_snapshot_export(src_node, dev, dst_node.name,
                                                 instance, cluster_name, idx)
 -        if result.failed or not result.data:
 -          self.LogWarning("Could not export disk/%d from node %s to"
 -                          " node %s", idx, src_node, dst_node.name)
 +        msg = result.fail_msg
 +        if msg:
 +          self.LogWarning("Could not export disk/%s from node %s to"
 +                          " node %s: %s", idx, src_node, dst_node.name, msg)
+           dresults.append(False)
+         else:
+           dresults.append(True)
 -        msg = self.rpc.call_blockdev_remove(src_node, dev).RemoteFailMsg()
 +        msg = self.rpc.call_blockdev_remove(src_node, dev).fail_msg
          if msg:
            self.LogWarning("Could not remove snapshot for disk/%d from node"
                            " %s: %s", idx, src_node, msg)
+       else:
+         dresults.append(False)
  
      result = self.rpc.call_finalize_export(dst_node.name, instance, snap_disks)
+     fin_resu = True
 -    if result.failed or not result.data:
 -      self.LogWarning("Could not finalize export for instance %s on node %s",
 -                      instance.name, dst_node.name)
 +    msg = result.fail_msg
 +    if msg:
 +      self.LogWarning("Could not finalize export for instance %s"
 +                      " on node %s: %s", instance.name, dst_node.name, msg)
+       fin_resu = False
  
      nodelist = self.cfg.GetNodeList()
      nodelist.remove(dst_node.name)
      if nodelist:
        exportlist = self.rpc.call_export_list(nodelist)
        for node in exportlist:
 -        if exportlist[node].failed:
 +        if exportlist[node].fail_msg:
            continue
 -        if instance.name in exportlist[node].data:
 -          if not self.rpc.call_export_remove(node, instance.name):
 +        if iname in exportlist[node].payload:
 +          msg = self.rpc.call_export_remove(node, iname).fail_msg
 +          if msg:
              self.LogWarning("Could not remove older export for instance %s"
 -                            " on node %s", instance.name, node)
 +                            " on node %s: %s", iname, node, msg)
+     return fin_resu, dresults
  
  
  class LURemoveExport(NoHooksLU):
@@@ -7548,11 -6907,11 +7667,12 @@@ class IAllocator(object)
          "master_candidate": ninfo.master_candidate,
          }
  
-       if not ninfo.offline:
+       if not (ninfo.offline or ninfo.drained):
 -        nresult.Raise()
 -        if not isinstance(nresult.data, dict):
 -          raise errors.OpExecError("Can't get data for node %s" % nname)
 -        remote_info = nresult.data
 +        nresult.Raise("Can't get data for node %s" % nname)
 +        node_iinfo[nname].Raise("Can't get node instance info from node %s" %
 +                                nname)
 +        remote_info = nresult.payload
++
          for attr in ['memory_total', 'memory_free', 'memory_dom0',
                       'vg_size', 'vg_free', 'cpu_total']:
            if attr not in remote_info:
@@@ -617,48 -542,4 +617,47 @@@ BEC_DEFAULTS = 
    BE_AUTO_BALANCE: True,
    }
  
 +NICC_DEFAULTS = {
 +  NIC_MODE: NIC_MODE_BRIDGED,
 +  NIC_LINK: DEFAULT_BRIDGE,
 +  }
 +
  MASTER_POOL_SIZE_DEFAULT = 10
 +
 +CONFD_PROTOCOL_VERSION = 1
 +
 +CONFD_REQ_PING = 0
 +CONFD_REQ_NODE_ROLE_BYNAME = 1
 +CONFD_REQ_NODE_PIP_BY_INSTANCE_IP = 2
 +
 +CONFD_REQS = frozenset([
 +  CONFD_REQ_PING,
 +  CONFD_REQ_NODE_ROLE_BYNAME,
 +  CONFD_REQ_NODE_PIP_BY_INSTANCE_IP,
 +  ])
 +
 +CONFD_REPL_STATUS_OK = 0
 +CONFD_REPL_STATUS_ERROR = 1
 +CONFD_REPL_STATUS_NOTIMPLEMENTED = 2
 +
 +CONFD_REPL_STATUSES = frozenset([
 +  CONFD_REPL_STATUS_OK,
 +  CONFD_REPL_STATUS_ERROR,
 +  CONFD_REPL_STATUS_NOTIMPLEMENTED,
 +  ])
 +
 +(CONFD_NODE_ROLE_MASTER,
 + CONFD_NODE_ROLE_CANDIDATE,
 + CONFD_NODE_ROLE_OFFLINE,
 + CONFD_NODE_ROLE_DRAINED,
 + CONFD_NODE_ROLE_REGULAR,
 + ) = range(5)
 +
 +# A few common errors for confd
 +CONFD_ERROR_UNKNOWN_ENTRY = 1
 +CONFD_ERROR_INTERNAL = 2
 +
 +# Each request is "salted" by the current timestamp.
 +# This constants decides how many seconds of skew to accept.
 +# TODO: make this a default and allow the value to be more configurable
 +CONFD_MAX_CLOCK_SKEW = 300
diff --cc lib/mcpu.py
Simple merge
diff --cc lib/objects.py
Simple merge
diff --cc lib/opcodes.py
@@@ -234,9 -221,29 +234,29 @@@ class OpVerifyDisks(OpCode)
  
    """
    OP_ID = "OP_CLUSTER_VERIFY_DISKS"
 -  __slots__ = []
 +  __slots__ = OpCode.__slots__ + []
  
  
+ class OpRepairDiskSizes(OpCode):
+   """Verify the disk sizes of the instances and fixes configuration
+   mimatches.
+   Parameters: optional instances list, in case we want to restrict the
+   checks to only a subset of the instances.
+   Result: a list of tuples, (instance, disk, new-size) for changed
+   configurations.
+   In normal operation, the list should be empty.
+   @type instances: list
+   @ivar instances: the list of instances to check, or empty for all instances
+   """
+   OP_ID = "OP_CLUSTER_REPAIR_DISK_SIZES"
+   __slots__ = ["instances"]
  class OpQueryConfigValues(OpCode):
    """Query cluster configuration values."""
    OP_ID = "OP_CLUSTER_CONFIG_QUERY"
@@@ -510,7 -453,7 +530,7 @@@ class OpActivateInstanceDisks(OpCode)
    """Activate an instance's disks."""
    OP_ID = "OP_INSTANCE_ACTIVATE_DISKS"
    OP_DSC_FIELD = "instance_name"
-   __slots__ = OpCode.__slots__ + ["instance_name"]
 -  __slots__ = ["instance_name", "ignore_size"]
++  __slots__ = OpCode.__slots__ + ["instance_name", "ignore_size"]
  
  
  class OpDeactivateInstanceDisks(OpCode):
diff --cc lib/rpc.py
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -102,11 -121,8 +121,11 @@@ def ImportInstance(opts, args)
      except ValueError, err:
        raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err))
      nics = [{}] * nic_max
-     for nidx, ndict in opts.nics.items():
+     for nidx, ndict in opts.nics:
        nidx = int(nidx)
 +      if not isinstance(ndict, dict):
 +        msg = "Invalid nic/%d value: expected dict, got %s" % (nidx, ndict)
 +        raise errors.OpPrereqError(msg)
        nics[nidx] = ndict
    elif opts.no_nics:
      # no nics
Simple merge
Simple merge