Merge branch 'devel-2.4'
authorMichael Hanselmann <hansmi@google.com>
Thu, 7 Apr 2011 10:03:51 +0000 (12:03 +0200)
committerMichael Hanselmann <hansmi@google.com>
Thu, 7 Apr 2011 10:24:48 +0000 (12:24 +0200)
* devel-2.4:
  LUInstanceQueryData: Don't acquire locks unless requested
  Increase the lock timeouts before we block-acquire
  daemon.py: move startup log message before prep_fn
  Display the actual memory values in N+1 failures
  ssh.VerifyNodeHostname: remove the quiet flag
  Add error checking and merging for cluster params
  RAPI: Document need for Content-type header in requests
  Fix output for “gnt-job info”
  watcher: Fix misleading usage output
  Clarify --force-join parameter message
  locking: Fix race condition in lock monitor
  utils: Export NiceSortKey function
  Revert "Only merge nodes that are known to not be offline"
  cluster-merge: only operate on online nodes
  Only merge nodes that are known to not be offline
  Treat empty oob_program param as default
  Fix bug in instance listing with orphan instances
  Fix bug related to log opening failures
  Bump version for 2.4.1 release
  cfgupgrade: Fix critical bug overwriting RAPI users file

Conflicts:
NEWS: Trivial
lib/opcodes.py: Added parameter descriptions, used variable for
  "use_locking"

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: René Nussbaumer <rn@google.com>

1  2 
NEWS
configure.ac
doc/rapi.rst
lib/cli.py
lib/cmdlib.py
lib/constants.py
lib/mcpu.py
lib/opcodes.py
lib/utils/log.py
lib/watcher/__init__.py
tools/cfgupgrade

diff --cc NEWS
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,23 -1,17 +1,34 @@@
  News
  ====
  
 +Version 2.5.0 beta1
 +-------------------
 +
 +*(unreleased)*
 +
 +- The default of the ``/2/instances/[instance_name]/rename`` RAPI
 +  resource's ``ip_check`` parameter changed from ``True`` to ``False``
 +  to match the underlying LUXI interface
 +- When creating file-based instances via RAPI, the ``file_driver``
 +  parameter no longer defaults to ``loop`` and must be specified
 +- The deprecated "bridge" nic parameter is no longer supported. Use
 +  "link" instead.
 +- Support for the undocumented and deprecated RAPI instance creation
 +  request format version 0 has been dropped. Use version 1, supported
 +  since Ganeti 2.1.3 and :doc:`documented <rapi>`, instead.
 +
 +
+ Version 2.4.1
+ -------------
+ *(Released Wed, 09 Mar 2011)*
+ Emergency bug-fix release. ``tools/cfgupgrade`` was broken and overwrote
+ the RAPI users file if run twice (even with ``-dry-run``).
+ The release fixes that bug (nothing else changed).
  Version 2.4.0
  -------------
  
diff --cc configure.ac
Simple merge
diff --cc doc/rapi.rst
Simple merge
diff --cc lib/cli.py
Simple merge
diff --cc lib/cmdlib.py
@@@ -1695,93 -1641,52 +1695,94 @@@ class LUClusterVerify(LogicalUnit)
          test = n_img.mfree < needed_mem
          self._ErrorIf(test, self.ENODEN1, node,
                        "not enough memory to accomodate instance failovers"
-                       " should node %s fail", prinode)
+                       " should node %s fail (%dMiB needed, %dMiB available)",
+                       prinode, needed_mem, n_img.mfree)
  
 -  def _VerifyNodeFiles(self, ninfo, nresult, file_list, local_cksum,
 -                       master_files):
 -    """Verifies and computes the node required file checksums.
 +  @classmethod
 +  def _VerifyFiles(cls, errorif, nodeinfo, master_node, all_nvinfo,
 +                   (files_all, files_all_opt, files_mc, files_vm)):
 +    """Verifies file checksums collected from all nodes.
  
 -    @type ninfo: L{objects.Node}
 -    @param ninfo: the node to check
 -    @param nresult: the remote results for the node
 -    @param file_list: required list of files
 -    @param local_cksum: dictionary of local files and their checksums
 -    @param master_files: list of files that only masters should have
 +    @param errorif: Callback for reporting errors
 +    @param nodeinfo: List of L{objects.Node} objects
 +    @param master_node: Name of master node
 +    @param all_nvinfo: RPC results
  
      """
 -    node = ninfo.name
 -    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
 +    node_names = frozenset(node.name for node in nodeinfo)
  
 -    remote_cksum = nresult.get(constants.NV_FILELIST, None)
 -    test = not isinstance(remote_cksum, dict)
 -    _ErrorIf(test, self.ENODEFILECHECK, node,
 -             "node hasn't returned file checksum data")
 -    if test:
 -      return
 +    assert master_node in node_names
 +    assert (len(files_all | files_all_opt | files_mc | files_vm) ==
 +            sum(map(len, [files_all, files_all_opt, files_mc, files_vm]))), \
 +           "Found file listed in more than one file list"
 +
 +    # Define functions determining which nodes to consider for a file
 +    file2nodefn = dict([(filename, fn)
 +      for (files, fn) in [(files_all, None),
 +                          (files_all_opt, None),
 +                          (files_mc, lambda node: (node.master_candidate or
 +                                                   node.name == master_node)),
 +                          (files_vm, lambda node: node.vm_capable)]
 +      for filename in files])
 +
 +    fileinfo = dict((filename, {}) for filename in file2nodefn.keys())
 +
 +    for node in nodeinfo:
 +      nresult = all_nvinfo[node.name]
 +
 +      if nresult.fail_msg or not nresult.payload:
 +        node_files = None
 +      else:
 +        node_files = nresult.payload.get(constants.NV_FILELIST, None)
 +
 +      test = not (node_files and isinstance(node_files, dict))
 +      errorif(test, cls.ENODEFILECHECK, node.name,
 +              "Node did not return file checksum data")
 +      if test:
 +        continue
 +
 +      for (filename, checksum) in node_files.items():
 +        # Check if the file should be considered for a node
 +        fn = file2nodefn[filename]
 +        if fn is None or fn(node):
 +          fileinfo[filename].setdefault(checksum, set()).add(node.name)
 +
 +    for (filename, checksums) in fileinfo.items():
 +      assert compat.all(len(i) > 10 for i in checksums), "Invalid checksum"
 +
 +      # Nodes having the file
 +      with_file = frozenset(node_name
 +                            for nodes in fileinfo[filename].values()
 +                            for node_name in nodes)
 +
 +      # Nodes missing file
 +      missing_file = node_names - with_file
 +
 +      if filename in files_all_opt:
 +        # All or no nodes
 +        errorif(missing_file and missing_file != node_names,
 +                cls.ECLUSTERFILECHECK, None,
 +                "File %s is optional, but it must exist on all or no nodes (not"
 +                " found on %s)",
 +                filename, utils.CommaJoin(utils.NiceSort(missing_file)))
 +      else:
 +        errorif(missing_file, cls.ECLUSTERFILECHECK, None,
 +                "File %s is missing from node(s) %s", filename,
 +                utils.CommaJoin(utils.NiceSort(missing_file)))
  
 -    for file_name in file_list:
 -      node_is_mc = ninfo.master_candidate
 -      must_have = (file_name not in master_files) or node_is_mc
 -      # missing
 -      test1 = file_name not in remote_cksum
 -      # invalid checksum
 -      test2 = not test1 and remote_cksum[file_name] != local_cksum[file_name]
 -      # existing and good
 -      test3 = not test1 and remote_cksum[file_name] == local_cksum[file_name]
 -      _ErrorIf(test1 and must_have, self.ENODEFILECHECK, node,
 -               "file '%s' missing", file_name)
 -      _ErrorIf(test2 and must_have, self.ENODEFILECHECK, node,
 -               "file '%s' has wrong checksum", file_name)
 -      # not candidate and this is not a must-have file
 -      _ErrorIf(test2 and not must_have, self.ENODEFILECHECK, node,
 -               "file '%s' should not exist on non master"
 -               " candidates (and the file is outdated)", file_name)
 -      # all good, except non-master/non-must have combination
 -      _ErrorIf(test3 and not must_have, self.ENODEFILECHECK, node,
 -               "file '%s' should not exist"
 -               " on non master candidates", file_name)
 +      # See if there are multiple versions of the file
 +      test = len(checksums) > 1
 +      if test:
 +        variants = ["variant %s on %s" %
 +                    (idx + 1, utils.CommaJoin(utils.NiceSort(nodes)))
 +                    for (idx, (checksum, nodes)) in
 +                      enumerate(sorted(checksums.items()))]
 +      else:
 +        variants = []
 +
 +      errorif(test, cls.ECLUSTERFILECHECK, None,
 +              "File %s found with %s different checksums (%s)",
 +              filename, len(checksums), "; ".join(variants))
  
    def _VerifyNodeDrbd(self, ninfo, nresult, instanceinfo, drbd_helper,
                        drbd_map):
Simple merge
diff --cc lib/mcpu.py
Simple merge
diff --cc lib/opcodes.py
@@@ -1119,8 -967,9 +1119,12 @@@ class OpInstanceQuery(OpCode)
  class OpInstanceQueryData(OpCode):
    """Compute the run-time status of instances."""
    OP_PARAMS = [
-     ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None),
-     ("static", False, ht.TBool, None),
 -    ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
 -    ("static", False, ht.TBool),
 -    ("use_locking", False, ht.TBool),
++    _PUseLocking,
++    ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
++     "Instance names"),
++    ("static", False, ht.TBool,
++     "Whether to only return configuration data without querying"
++     " nodes"),
      ]
  
  
Simple merge
Simple merge
Simple merge