--select-instances hbal manpage update
[ganeti-local] / lib / config.py
index fe580ef..7d81b37 100644 (file)
@@ -125,6 +125,13 @@ class TemporaryReservationManager:
     return new_resource
 
 
+def _MatchNameComponentIgnoreCase(short_name, names):
+  """Wrapper around L{utils.text.MatchNameComponent}.
+
+  """
+  return utils.MatchNameComponent(short_name, names, case_sensitive=False)
+
+
 class ConfigWriter:
   """The interface to the cluster configuration.
 
@@ -212,7 +219,7 @@ class ConfigWriter:
     if mac in all_macs:
       raise errors.ReservationError("mac already in use")
     else:
-      self._temporary_macs.Reserve(mac, ec_id)
+      self._temporary_macs.Reserve(ec_id, mac)
 
   @locking.ssynchronized(_config_lock, shared=1)
   def ReserveLV(self, lv_name, ec_id):
@@ -226,7 +233,7 @@ class ConfigWriter:
     if lv_name in all_lvs:
       raise errors.ReservationError("LV already in use")
     else:
-      self._temporary_lvs.Reserve(lv_name, ec_id)
+      self._temporary_lvs.Reserve(ec_id, lv_name)
 
   @locking.ssynchronized(_config_lock, shared=1)
   def GenerateDRBDSecret(self, ec_id):
@@ -878,6 +885,13 @@ class ConfigWriter:
     return self._config_data.cluster.file_storage_dir
 
   @locking.ssynchronized(_config_lock, shared=1)
+  def GetSharedFileStorageDir(self):
+    """Get the shared file storage dir for this cluster.
+
+    """
+    return self._config_data.cluster.shared_file_storage_dir
+
+  @locking.ssynchronized(_config_lock, shared=1)
   def GetHypervisorType(self):
     """Get the hypervisor type for this cluster.
 
@@ -1057,6 +1071,17 @@ class ConfigWriter:
     """
     return self._config_data.nodegroups.keys()
 
+  @locking.ssynchronized(_config_lock, shared=1)
+  def GetNodeGroupMembersByNodes(self, nodes):
+    """Get nodes which are member in the same nodegroups as the given nodes.
+
+    """
+    ngfn = lambda node_name: self._UnlockedGetNodeInfo(node_name).group
+    return frozenset(member_name
+                     for node_name in nodes
+                     for member_name in
+                       self._UnlockedGetNodeGroup(ngfn(node_name)).members)
+
   @locking.ssynchronized(_config_lock)
   def AddInstance(self, instance, ec_id):
     """Add an instance to the config.
@@ -1194,14 +1219,12 @@ class ConfigWriter:
     """
     return self._UnlockedGetInstanceList()
 
-  @locking.ssynchronized(_config_lock, shared=1)
   def ExpandInstanceName(self, short_name):
     """Attempt to expand an incomplete instance name.
 
     """
-    return utils.MatchNameComponent(short_name,
-                                    self._config_data.instances.keys(),
-                                    case_sensitive=False)
+    # Locking is done in L{ConfigWriter.GetInstanceList}
+    return _MatchNameComponentIgnoreCase(short_name, self.GetInstanceList())
 
   def _UnlockedGetInstanceInfo(self, instance_name):
     """Returns information about an instance.
@@ -1231,6 +1254,25 @@ class ConfigWriter:
     return self._UnlockedGetInstanceInfo(instance_name)
 
   @locking.ssynchronized(_config_lock, shared=1)
+  def GetInstanceNodeGroups(self, instance_name, primary_only=False):
+    """Returns set of node group UUIDs for instance's nodes.
+
+    @rtype: frozenset
+
+    """
+    instance = self._UnlockedGetInstanceInfo(instance_name)
+    if not instance:
+      raise errors.ConfigurationError("Unknown instance '%s'" % instance_name)
+
+    if primary_only:
+      nodes = [instance.primary_node]
+    else:
+      nodes = instance.all_nodes
+
+    return frozenset(self._UnlockedGetNodeInfo(node_name).group
+                     for node_name in nodes)
+
+  @locking.ssynchronized(_config_lock, shared=1)
   def GetAllInstancesInfo(self):
     """Get the configuration of all instances.
 
@@ -1277,14 +1319,12 @@ class ConfigWriter:
     self._config_data.cluster.serial_no += 1
     self._WriteConfig()
 
-  @locking.ssynchronized(_config_lock, shared=1)
   def ExpandNodeName(self, short_name):
-    """Attempt to expand an incomplete instance name.
+    """Attempt to expand an incomplete node name.
 
     """
-    return utils.MatchNameComponent(short_name,
-                                    self._config_data.nodes.keys(),
-                                    case_sensitive=False)
+    # Locking is done in L{ConfigWriter.GetNodeList}
+    return _MatchNameComponentIgnoreCase(short_name, self.GetNodeList())
 
   def _UnlockedGetNodeInfo(self, node_name):
     """Get the configuration of a node, as stored in the config.
@@ -1336,6 +1376,26 @@ class ConfigWriter:
         sec.append(inst.name)
     return (pri, sec)
 
+  @locking.ssynchronized(_config_lock, shared=1)
+  def GetNodeGroupInstances(self, uuid, primary_only=False):
+    """Get the instances of a node group.
+
+    @param uuid: Node group UUID
+    @param primary_only: Whether to only consider primary nodes
+    @rtype: frozenset
+    @return: List of instance names in node group
+
+    """
+    if primary_only:
+      nodes_fn = lambda inst: [inst.primary_node]
+    else:
+      nodes_fn = lambda inst: inst.all_nodes
+
+    return frozenset(inst.name
+                     for inst in self._config_data.instances.values()
+                     for node_name in nodes_fn(inst)
+                     if self._UnlockedGetNodeInfo(node_name).group == uuid)
+
   def _UnlockedGetNodeList(self):
     """Return the list of nodes which are in the configuration.
 
@@ -1745,10 +1805,11 @@ class ConfigWriter:
                   self._config_data.nodegroups.values()]
     nodegroups_data = fn(utils.NiceSort(nodegroups))
 
-    return {
+    ssconf_values = {
       constants.SS_CLUSTER_NAME: cluster.cluster_name,
       constants.SS_CLUSTER_TAGS: cluster_tags,
       constants.SS_FILE_STORAGE_DIR: cluster.file_storage_dir,
+      constants.SS_SHARED_FILE_STORAGE_DIR: cluster.shared_file_storage_dir,
       constants.SS_MASTER_CANDIDATES: mc_data,
       constants.SS_MASTER_CANDIDATES_IPS: mc_ips_data,
       constants.SS_MASTER_IP: cluster.master_ip,
@@ -1767,6 +1828,13 @@ class ConfigWriter:
       constants.SS_UID_POOL: uid_pool,
       constants.SS_NODEGROUPS: nodegroups_data,
       }
+    bad_values = [(k, v) for k, v in ssconf_values.items()
+                  if not isinstance(v, (str, basestring))]
+    if bad_values:
+      err = utils.CommaJoin("%s=%s" % (k, v) for k, v in bad_values)
+      raise errors.ConfigurationError("Some ssconf key(s) have non-string"
+                                      " values: %s" % err)
+    return ssconf_values
 
   @locking.ssynchronized(_config_lock, shared=1)
   def GetSsconfValues(self):