Merge branch 'devel-2.5'
authorMichael Hanselmann <hansmi@google.com>
Thu, 12 Apr 2012 19:17:24 +0000 (21:17 +0200)
committerMichael Hanselmann <hansmi@google.com>
Fri, 13 Apr 2012 13:19:34 +0000 (15:19 +0200)
* devel-2.5: (29 commits)
  gnt-* {add,list,remove}-tags: Unify options
  Bump version for 2.5.0 final release
  configure.ac: Fix “too many arguments” error
  Fix extra whitespace
  Further fixes concerning drbd port release
  Fix a bug concerning TCP port release
  Fix extra whitespace
  Fix a bug concerning TCP port release
  ganeti.initd: Add “status” action
  Add whitelist for opcodes using BGL
  LUOobCommand: acquire BGL in shared mode
  Fix docstring bug
  LUNodeAdd: Verify version in Prereq
  LUNodeAdd: Verify version in Prereq
  Fix LV status parsing to accept newer LVM
  gnt-instance info: Show node group information
  cmdlib: Factorize checking acquired node group locks
  Bump version for 2.5.0~rc6 release
  cmdlib: Stop forking in LUClusterQuery
  locking: Notify only once on release
  ...

Conflicts:
NEWS: Trivial
daemons/daemon-util.in: Copyright line
lib/client/gnt_group.py: Tag operations
lib/cmdlib.py: Not so trivial, hopefully correct

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>

18 files changed:
1  2 
NEWS
configure.ac
daemons/daemon-util.in
lib/bdev.py
lib/cli.py
lib/client/gnt_cluster.py
lib/client/gnt_group.py
lib/client/gnt_instance.py
lib/client/gnt_node.py
lib/cmdlib.py
lib/config.py
lib/hypervisor/hv_kvm.py
lib/locking.py
lib/runtime.py
lib/server/masterd.py
qa/qa_cluster.py
test/ganeti.locking_unittest.py
test/ganeti.mcpu_unittest.py

diff --cc NEWS
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -2,28 -2,10 +2,28 @@@ New
  ====
  
  
 +Version 2.6.0 beta1
 +-------------------
 +
 +*(unreleased)*
 +
 +- Deprecated ``admin_up`` field. Instead, ``admin_state`` is introduced,
 +  with 3 possible values -- ``up``, ``down`` and ``offline``.
 +- Replaced ``--disks`` option of ``gnt-instance replace-disks`` with a
 +  more flexible ``--disk`` option. Now disk size and mode can be changed
 +  upon recreation.
 +- Removed deprecated ``QueryLocks`` LUXI request. Use
 +  ``Query(what=QR_LOCK, ...)`` instead.
 +- The LUXI requests :pyeval:`luxi.REQ_QUERY_JOBS`,
 +  :pyeval:`luxi.REQ_QUERY_INSTANCES`, :pyeval:`luxi.REQ_QUERY_NODES` and
 +  :pyeval:`luxi.REQ_QUERY_GROUPS` are deprecated and will be removed in
 +  a future version. :pyeval:`luxi.REQ_QUERY` should be used instead.
 +
 +
- Version 2.5.0 rc5
- -----------------
+ Version 2.5.0
+ -------------
  
- *(Released Mon, 9 Jan 2012)*
+ *(Released Thu, 12 Apr 2012)*
  
  Incompatible/important changes and bugfixes
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --cc configure.ac
Simple merge
@@@ -1,7 -1,7 +1,7 @@@
  #!/bin/bash
  #
  
- # Copyright (C) 2009, 2011 Google Inc.
 -# Copyright (C) 2009, 2012 Google Inc.
++# Copyright (C) 2009, 2011, 2012 Google Inc.
  #
  # This program is free software; you can redistribute it and/or modify
  # it under the terms of the GNU General Public License as published by
diff --cc lib/bdev.py
Simple merge
diff --cc lib/cli.py
Simple merge
Simple merge
@@@ -310,16 -243,16 +310,16 @@@ commands = 
      "[-I <iallocator>] [--to <group>]",
      "Evacuate all instances within a group"),
    "list-tags": (
-     ListTags, ARGS_ONE_GROUP, [PRIORITY_OPT],
+     ListTags, ARGS_ONE_GROUP, [],
 -    "<instance_name>", "List the tags of the given instance"),
 +    "<group_name>", "List the tags of the given group"),
    "add-tags": (
      AddTags, [ArgGroup(min=1, max=1), ArgUnknown()],
-     [TAG_SRC_OPT, PRIORITY_OPT],
+     [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
 -    "<instance_name> tag...", "Add tags to the given instance"),
 +    "<group_name> tag...", "Add tags to the given group"),
    "remove-tags": (
      RemoveTags, [ArgGroup(min=1, max=1), ArgUnknown()],
-     [TAG_SRC_OPT, PRIORITY_OPT],
+     [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
 -    "<instance_name> tag...", "Remove tags from given instance"),
 +    "<group_name> tag...", "Remove tags from the given group"),
    }
  
  
Simple merge
Simple merge
diff --cc lib/cmdlib.py
@@@ -59,7 -58,7 +58,8 @@@ from ganeti import quer
  from ganeti import qlang
  from ganeti import opcodes
  from ganeti import ht
 +from ganeti import rpc
+ from ganeti import runtime
  
  import ganeti.masterd.instance # pylint: disable=W0611
  
@@@ -582,20 -557,32 +582,46 @@@ def _ShareAll()
    return dict.fromkeys(locking.LEVELS, 1)
  
  
 +def _MakeLegacyNodeInfo(data):
 +  """Formats the data returned by L{rpc.RpcRunner.call_node_info}.
 +
 +  Converts the data into a single dictionary. This is fine for most use cases,
 +  but some require information from more than one volume group or hypervisor.
 +
 +  """
 +  (bootid, (vg_info, ), (hv_info, )) = data
 +
 +  return utils.JoinDisjointDicts(utils.JoinDisjointDicts(vg_info, hv_info), {
 +    "bootid": bootid,
 +    })
 +
 +
+ def _CheckInstancesNodeGroups(cfg, instances, owned_groups, owned_nodes,
+                               cur_group_uuid):
+   """Checks if node groups for locked instances are still correct.
+   @type cfg: L{config.ConfigWriter}
+   @param cfg: Cluster configuration
+   @type instances: dict; string as key, L{objects.Instance} as value
+   @param instances: Dictionary, instance name as key, instance object as value
+   @type owned_groups: iterable of string
+   @param owned_groups: List of owned groups
+   @type owned_nodes: iterable of string
+   @param owned_nodes: List of owned nodes
+   @type cur_group_uuid: string or None
+   @param cur_group_uuid: Optional group UUID to check against instance's groups
+   """
+   for (name, inst) in instances.items():
+     assert owned_nodes.issuperset(inst.all_nodes), \
+       "Instance %s's nodes changed while we kept the lock" % name
+     inst_groups = _CheckInstanceNodeGroups(cfg, name, owned_groups)
+     assert cur_group_uuid is None or cur_group_uuid in inst_groups, \
+       "Instance %s has no node in group %s" % (name, cur_group_uuid)
  def _CheckInstanceNodeGroups(cfg, instance_name, owned_groups):
    """Checks if the owned node groups are still correct for an instance.
  
@@@ -1899,12 -1595,17 +1925,17 @@@ class LUClusterVerifyConfig(NoHooksLU, 
          utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
          hv_class.CheckParameterSyntax(hv_params)
        except errors.GenericError, err:
 -        self._ErrorIf(True, self.ECLUSTERCFG, None, msg % str(err))
 +        self._ErrorIf(True, constants.CV_ECLUSTERCFG, None, msg % str(err))
  
    def ExpandNames(self):
-     # Information can be safely retrieved as the BGL is acquired in exclusive
-     # mode
-     assert locking.BGL in self.owned_locks(locking.LEVEL_CLUSTER)
+     self.needed_locks = dict.fromkeys(locking.LEVELS, locking.ALL_SET)
+     self.share_locks = _ShareAll()
+   def CheckPrereq(self):
+     """Check prerequisites.
+     """
+     # Retrieve all information
      self.all_group_info = self.cfg.GetAllNodeGroupsInfo()
      self.all_node_info = self.cfg.GetAllNodesInfo()
      self.all_inst_info = self.cfg.GetAllInstancesInfo()
@@@ -6096,10 -5544,10 +6119,10 @@@ class LUClusterQuery(NoHooksLU)
        "config_version": constants.CONFIG_VERSION,
        "os_api_version": max(constants.OS_API_VERSIONS),
        "export_version": constants.EXPORT_VERSION,
-       "architecture": (platform.architecture()[0], platform.machine()),
+       "architecture": runtime.GetArchInfo(),
        "name": cluster.cluster_name,
        "master": cluster.master_node,
 -      "default_hypervisor": cluster.enabled_hypervisors[0],
 +      "default_hypervisor": cluster.primary_hypervisor,
        "enabled_hypervisors": cluster.enabled_hypervisors,
        "hvparams": dict([(hypervisor_name, cluster.hvparams[hypervisor_name])
                          for hypervisor_name in cluster.enabled_hypervisors]),
@@@ -8955,7 -8021,8 +8978,8 @@@ def _RemoveDisks(lu, instance, target_n
    logging.info("Removing block devices for instance %s", instance.name)
  
    all_result = True
+   ports_to_release = set()
 -  for device in instance.disks:
 +  for (idx, device) in enumerate(instance.disks):
      if target_node:
        edata = [(target_node, device)]
      else:
@@@ -11765,12 -10711,19 +11824,19 @@@ class LUInstanceQueryData(NoHooksLU)
        disks = map(compat.partial(self._ComputeDiskStatus, instance, None),
                    instance.disks)
  
+       snodes_group_uuids = [nodes[snode_name].group
+                             for snode_name in instance.secondary_nodes]
        result[instance.name] = {
          "name": instance.name,
 -        "config_state": config_state,
 +        "config_state": instance.admin_state,
          "run_state": remote_state,
          "pnode": instance.primary_node,
+         "pnode_group_uuid": pnode.group,
+         "pnode_group_name": group2name_fn(pnode.group),
          "snodes": instance.secondary_nodes,
+         "snodes_group_uuids": snodes_group_uuids,
+         "snodes_group_names": map(group2name_fn, snodes_group_uuids),
          "os": instance.os,
          # this happens to be the same format used for hooks
          "nics": _NICListToTuple(self, instance.nics),
@@@ -12589,112 -11284,6 +12661,105 @@@ class LUInstanceSetParams(LogicalUnit)
          self.LogWarning("Could not remove metadata for disk %d on node %s,"
                          " continuing anyway: %s", idx, pnode, msg)
  
-     # this is a DRBD disk, return its port to the pool
-     for disk in old_disks:
-       tcp_port = disk.logical_id[2]
-       self.cfg.AddTcpUdpPort(tcp_port)
-     # Node resource locks will be released by caller
 +  def _CreateNewDisk(self, idx, params, _):
 +    """Creates a new disk.
 +
 +    """
 +    instance = self.instance
 +
 +    # add a new disk
 +    if instance.disk_template in constants.DTS_FILEBASED:
 +      (file_driver, file_path) = instance.disks[0].logical_id
 +      file_path = os.path.dirname(file_path)
 +    else:
 +      file_driver = file_path = None
 +
 +    disk = \
 +      _GenerateDiskTemplate(self, instance.disk_template, instance.name,
 +                            instance.primary_node, instance.secondary_nodes,
 +                            [params], file_path, file_driver, idx,
 +                            self.Log, self.diskparams)[0]
 +
 +    info = _GetInstanceInfoText(instance)
 +
 +    logging.info("Creating volume %s for instance %s",
 +                 disk.iv_name, instance.name)
 +    # Note: this needs to be kept in sync with _CreateDisks
 +    #HARDCODE
 +    for node in instance.all_nodes:
 +      f_create = (node == instance.primary_node)
 +      try:
 +        _CreateBlockDev(self, node, instance, disk, f_create, info, f_create)
 +      except errors.OpExecError, err:
 +        self.LogWarning("Failed to create volume %s (%s) on node '%s': %s",
 +                        disk.iv_name, disk, node, err)
 +
 +    return (disk, [
 +      ("disk/%d" % idx, "add:size=%s,mode=%s" % (disk.size, disk.mode)),
 +      ])
 +
 +  @staticmethod
 +  def _ModifyDisk(idx, disk, params, _):
 +    """Modifies a disk.
 +
 +    """
 +    disk.mode = params[constants.IDISK_MODE]
 +
 +    return [
 +      ("disk.mode/%d" % idx, disk.mode),
 +      ]
 +
 +  def _RemoveDisk(self, idx, root, _):
 +    """Removes a disk.
 +
 +    """
 +    for node, disk in root.ComputeNodeTree(self.instance.primary_node):
 +      self.cfg.SetDiskID(disk, node)
 +      msg = self.rpc.call_blockdev_remove(node, disk).fail_msg
 +      if msg:
 +        self.LogWarning("Could not remove disk/%d on node '%s': %s,"
 +                        " continuing anyway", idx, node, msg)
 +
 +    # if this is a DRBD disk, return its port to the pool
 +    if root.dev_type in constants.LDS_DRBD:
 +      self.cfg.AddTcpUdpPort(root.logical_id[2])
 +
 +  @staticmethod
 +  def _CreateNewNic(idx, params, private):
 +    """Creates data structure for a new network interface.
 +
 +    """
 +    mac = params[constants.INIC_MAC]
 +    ip = params.get(constants.INIC_IP, None)
 +    nicparams = private.params
 +
 +    return (objects.NIC(mac=mac, ip=ip, nicparams=nicparams), [
 +      ("nic.%d" % idx,
 +       "add:mac=%s,ip=%s,mode=%s,link=%s" %
 +       (mac, ip, private.filled[constants.NIC_MODE],
 +       private.filled[constants.NIC_LINK])),
 +      ])
 +
 +  @staticmethod
 +  def _ApplyNicMods(idx, nic, params, private):
 +    """Modifies a network interface.
 +
 +    """
 +    changes = []
 +
 +    for key in [constants.INIC_MAC, constants.INIC_IP]:
 +      if key in params:
 +        changes.append(("nic.%s/%d" % (key, idx), params[key]))
 +        setattr(nic, key, params[key])
 +
 +    if private.params:
 +      nic.nicparams = private.params
 +
 +      for (key, val) in params.items():
 +        changes.append(("nic.%s/%d" % (key, idx), val))
 +
 +    return changes
 +
    def Exec(self, feedback_fn):
      """Modifies an instance.
  
diff --cc lib/config.py
Simple merge
Simple merge
diff --cc lib/locking.py
Simple merge
diff --cc lib/runtime.py
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge