Don't pass sstore to LUs anymore
[ganeti-local] / lib / config.py
index f44340b..57c56d8 100644 (file)
@@ -43,19 +43,16 @@ from ganeti import constants
 from ganeti import rpc
 from ganeti import objects
 from ganeti import serializer
-from ganeti import ssconf
 
 
 _config_lock = locking.SharedLock()
 
 
-def ValidateConfig():
-  sstore = ssconf.SimpleStore()
-
-  if sstore.GetConfigVersion() != constants.CONFIG_VERSION:
+def _ValidateConfig(data):
+  if data.version != constants.CONFIG_VERSION:
     raise errors.ConfigurationError("Cluster configuration version"
                                     " mismatch, got %s instead of %s" %
-                                    (sstore.GetConfigVersion(),
+                                    (data.version,
                                      constants.CONFIG_VERSION))
 
 
@@ -126,6 +123,25 @@ class ConfigWriter:
     all_macs = self._AllMACs()
     return mac in all_macs
 
+  @locking.ssynchronized(_config_lock, shared=1)
+  def GenerateDRBDSecret(self):
+    """Generate a DRBD secret.
+
+    This checks the current disks for duplicates.
+
+    """
+    self._OpenConfig()
+    all_secrets = self._AllDRBDSecrets()
+    retries = 64
+    while retries > 0:
+      secret = utils.GenerateSecret()
+      if secret not in all_secrets:
+        break
+      retries -= 1
+    else:
+      raise errors.ConfigurationError("Can't generate unique DRBD secret")
+    return secret
+
   def _ComputeAllLVs(self):
     """Compute the list of all LVs.
 
@@ -185,6 +201,25 @@ class ConfigWriter:
 
     return result
 
+  def _AllDRBDSecrets(self):
+    """Return all DRBD secrets present in the config.
+
+    """
+    def helper(disk, result):
+      """Recursively gather secrets from this disk."""
+      if disk.dev_type == constants.DT_DRBD8:
+        result.append(disk.logical_id[5])
+      if disk.children:
+        for child in disk.children:
+          helper(child, result)
+
+    result = []
+    for instance in self._config_data.instances.values():
+      for disk in instance.disks:
+        helper(disk, result)
+
+    return result
+
   @locking.ssynchronized(_config_lock, shared=1)
   def VerifyConfig(self):
     """Stub verify function.
@@ -268,7 +303,7 @@ class ConfigWriter:
     if disk.logical_id is None and disk.physical_id is not None:
       return
     if disk.dev_type == constants.LD_DRBD8:
-      pnode, snode, port, pminor, sminor = disk.logical_id
+      pnode, snode, port, pminor, sminor, secret = disk.logical_id
       if node_name not in (pnode, snode):
         raise errors.ConfigurationError("DRBD device not knowing node %s" %
                                         node_name)
@@ -280,9 +315,9 @@ class ConfigWriter:
       p_data = (pnode_info.secondary_ip, port)
       s_data = (snode_info.secondary_ip, port)
       if pnode == node_name:
-        disk.physical_id = p_data + s_data + (pminor,)
+        disk.physical_id = p_data + s_data + (pminor, secret)
       else: # it must be secondary, we tested above
-        disk.physical_id = s_data + p_data + (sminor,)
+        disk.physical_id = s_data + p_data + (sminor, secret)
     else:
       disk.physical_id = disk.logical_id
     return
@@ -354,8 +389,8 @@ class ConfigWriter:
 
     """
     def _AppendUsedPorts(instance_name, disk, used):
-      if disk.dev_type == constants.LD_DRBD8 and len(disk.logical_id) == 5:
-        nodeA, nodeB, dummy, minorA, minorB = disk.logical_id
+      if disk.dev_type == constants.LD_DRBD8 and len(disk.logical_id) >= 5:
+        nodeA, nodeB, dummy, minorA, minorB = disk.logical_id[:5]
         for node, port in ((nodeA, minorA), (nodeB, minorB)):
           assert node in used, "Instance node not found in node list"
           if port in used[node]:
@@ -434,6 +469,69 @@ class ConfigWriter:
         del self._temporary_drbds[key]
 
   @locking.ssynchronized(_config_lock, shared=1)
+  def GetConfigVersion(self):
+    """Get the configuration version.
+
+    @return: Config version
+
+    """
+    return self._config_data.version
+
+  @locking.ssynchronized(_config_lock, shared=1)
+  def GetClusterName(self):
+    """Get cluster name.
+
+    @return: Cluster name
+
+    """
+    self._OpenConfig()
+    return self._config_data.cluster.cluster_name
+
+  @locking.ssynchronized(_config_lock, shared=1)
+  def GetMasterNode(self):
+    """Get the hostname of the master node for this cluster.
+
+    @return: Master hostname
+
+    """
+    self._OpenConfig()
+    return self._config_data.cluster.master_node
+
+  @locking.ssynchronized(_config_lock, shared=1)
+  def GetMasterIP(self):
+    """Get the IP of the master node for this cluster.
+
+    @return: Master IP
+
+    """
+    self._OpenConfig()
+    return self._config_data.cluster.master_ip
+
+  @locking.ssynchronized(_config_lock, shared=1)
+  def GetMasterNetdev(self):
+    """Get the master network device for this cluster.
+
+    """
+    self._OpenConfig()
+    return self._config_data.cluster.master_netdev
+
+  @locking.ssynchronized(_config_lock, shared=1)
+  def GetFileStorageDir(self):
+    """Get the file storage dir for this cluster.
+
+    """
+    self._OpenConfig()
+    return self._config_data.cluster.file_storage_dir
+
+  @locking.ssynchronized(_config_lock, shared=1)
+  def GetHypervisorType(self):
+    """Get the hypervisor type for this cluster.
+
+    """
+    self._OpenConfig()
+    return self._config_data.cluster.hypervisor
+
+  @locking.ssynchronized(_config_lock, shared=1)
   def GetHostKey(self):
     """Return the rsa hostkey from the config.
 
@@ -713,13 +811,6 @@ class ConfigWriter:
                     for node in self._UnlockedGetNodeList()])
     return my_dict
 
-  @locking.ssynchronized(_config_lock, shared=1)
-  def DumpConfig(self):
-    """Return the entire configuration of the cluster.
-    """
-    self._OpenConfig()
-    return self._config_data
-
   def _BumpSerialNo(self):
     """Bump up the serial number of the config.
 
@@ -746,9 +837,6 @@ class ConfigWriter:
       # data is current, so skip loading of config file
       return
 
-    # Make sure the configuration has the right version
-    ValidateConfig()
-
     f = open(self._cfg_file, 'r')
     try:
       try:
@@ -757,6 +845,10 @@ class ConfigWriter:
         raise errors.ConfigurationError(err)
     finally:
       f.close()
+
+    # Make sure the configuration has the right version
+    _ValidateConfig(data)
+
     if (not hasattr(data, 'cluster') or
         not hasattr(data.cluster, 'rsahostkeypub')):
       raise errors.ConfigurationError("Incomplete configuration"
@@ -823,36 +915,28 @@ class ConfigWriter:
     self._DistributeConfig()
 
   @locking.ssynchronized(_config_lock)
-  def InitConfig(self, node, primary_ip, secondary_ip,
-                 hostkeypub, mac_prefix, vg_name, def_bridge):
+  def InitConfig(self, version, cluster_config, master_node_config):
     """Create the initial cluster configuration.
 
     It will contain the current node, which will also be the master
-    node, and no instances or operating systmes.
+    node, and no instances.
 
-    Args:
-      node: the nodename of the initial node
-      primary_ip: the IP address of the current host
-      secondary_ip: the secondary IP of the current host or None
-      hostkeypub: the public hostkey of this host
-
-    """
-    hu_port = constants.FIRST_DRBD_PORT - 1
-    globalconfig = objects.Cluster(serial_no=1,
-                                   rsahostkeypub=hostkeypub,
-                                   highest_used_port=hu_port,
-                                   mac_prefix=mac_prefix,
-                                   volume_group_name=vg_name,
-                                   default_bridge=def_bridge,
-                                   tcpudp_port_pool=set())
-    if secondary_ip is None:
-      secondary_ip = primary_ip
-    nodeconfig = objects.Node(name=node, primary_ip=primary_ip,
-                              secondary_ip=secondary_ip, serial_no=1)
-
-    self._config_data = objects.ConfigData(nodes={node: nodeconfig},
+    @type version: int
+    @param version: Configuration version
+    @type cluster_config: objects.Cluster
+    @param cluster_config: Cluster configuration
+    @type master_node_config: objects.Node
+    @param master_node_config: Master node configuration
+
+    """
+    nodes = {
+      master_node_config.name: master_node_config,
+      }
+
+    self._config_data = objects.ConfigData(version=version,
+                                           cluster=cluster_config,
+                                           nodes=nodes,
                                            instances={},
-                                           cluster=globalconfig,
                                            serial_no=1)
     self._WriteConfig()