Convert os api version file name to a constant
[ganeti-local] / lib / bootstrap.py
index d4e5a09..b228433 100644 (file)
@@ -28,6 +28,7 @@ import os.path
 import re
 import logging
 import tempfile
+import time
 
 from ganeti import rpc
 from ganeti import ssh
@@ -62,11 +63,7 @@ def _InitSSHSetup():
     raise errors.OpExecError("Could not generate ssh keypair, error %s" %
                              result.output)
 
-  f = open(pub_key, 'r')
-  try:
-    utils.AddAuthorizedKey(auth_keys, f.read(8192))
-  finally:
-    f.close()
+  utils.AddAuthorizedKey(auth_keys, utils.ReadFile(pub_key))
 
 
 def _GenerateSelfSignedSslCert(file_name, validity=(365 * 5)):
@@ -116,6 +113,11 @@ def _InitGanetiServerSetup():
   if not os.path.exists(constants.RAPI_CERT_FILE):
     _GenerateSelfSignedSslCert(constants.RAPI_CERT_FILE)
 
+  if not os.path.exists(constants.HMAC_CLUSTER_KEY):
+    utils.WriteFile(constants.HMAC_CLUSTER_KEY,
+                    data=utils.GenerateSecret(),
+                    mode=0400)
+
   result = utils.RunCmd([constants.NODE_INITD_SCRIPT, "restart"])
 
   if result.failed:
@@ -128,7 +130,7 @@ def InitCluster(cluster_name, mac_prefix,
                 master_netdev, file_storage_dir, candidate_pool_size,
                 secondary_ip=None, vg_name=None, beparams=None,
                 nicparams=None, hvparams=None, enabled_hypervisors=None,
-                default_hypervisor=None, modify_etc_hosts=True):
+                modify_etc_hosts=True):
   """Initialise the cluster.
 
   @type candidate_pool_size: int
@@ -139,6 +141,14 @@ def InitCluster(cluster_name, mac_prefix,
   if config.ConfigWriter.IsCluster():
     raise errors.OpPrereqError("Cluster is already initialised")
 
+  if not enabled_hypervisors:
+    raise errors.OpPrereqError("Enabled hypervisors list must contain at"
+                               " least one member")
+  invalid_hvs = set(enabled_hypervisors) - constants.HYPER_TYPES
+  if invalid_hvs:
+    raise errors.OpPrereqError("Enabled hypervisors contains invalid"
+                               " entries: %s" % invalid_hvs)
+
   hostname = utils.HostInfo()
 
   if hostname.ip.startswith("127."):
@@ -226,11 +236,7 @@ def InitCluster(cluster_name, mac_prefix,
   _InitGanetiServerSetup()
 
   # set up ssh config and /etc/hosts
-  f = open(constants.SSH_HOST_RSA_PUB, 'r')
-  try:
-    sshline = f.read()
-  finally:
-    f.close()
+  sshline = utils.ReadFile(constants.SSH_HOST_RSA_PUB)
   sshkey = sshline.split(" ")[1]
 
   if modify_etc_hosts:
@@ -238,6 +244,8 @@ def InitCluster(cluster_name, mac_prefix,
 
   _InitSSHSetup()
 
+  now = time.time()
+
   # init of cluster config file
   cluster_config = objects.Cluster(
     serial_no=1,
@@ -252,12 +260,14 @@ def InitCluster(cluster_name, mac_prefix,
     cluster_name=clustername.name,
     file_storage_dir=file_storage_dir,
     enabled_hypervisors=enabled_hypervisors,
-    default_hypervisor=default_hypervisor,
     beparams={constants.PP_DEFAULT: beparams},
     nicparams={constants.PP_DEFAULT: nicparams},
     hvparams=hvparams,
     candidate_pool_size=candidate_pool_size,
     modify_etc_hosts=modify_etc_hosts,
+    ctime=now,
+    mtime=now,
+    uuid=utils.NewUUID(),
     )
   master_node_config = objects.Node(name=hostname.name,
                                     primary_ip=hostname.ip,
@@ -298,11 +308,13 @@ def InitConfig(version, cluster_config, master_node_config,
     master_node_config.name: master_node_config,
     }
 
+  now = time.time()
   config_data = objects.ConfigData(version=version,
                                    cluster=cluster_config,
                                    nodes=nodes,
                                    instances={},
-                                   serial_no=1)
+                                   serial_no=1,
+                                   ctime=now, mtime=now)
   utils.WriteFile(cfg_file,
                   data=serializer.Dump(config_data.ToDict()),
                   mode=0600)
@@ -316,11 +328,11 @@ def FinalizeClusterDestroy(master):
 
   """
   result = rpc.RpcRunner.call_node_stop_master(master, True)
-  msg = result.RemoteFailMsg()
+  msg = result.fail_msg
   if msg:
     logging.warning("Could not disable the master role: %s" % msg)
   result = rpc.RpcRunner.call_node_leave_cluster(master)
-  msg = result.RemoteFailMsg()
+  msg = result.fail_msg
   if msg:
     logging.warning("Could not shutdown the node daemon and cleanup"
                     " the node: %s", msg)
@@ -342,19 +354,23 @@ def SetupNodeDaemon(cluster_name, node, ssh_key_check):
 
   noded_cert = utils.ReadFile(constants.SSL_CERT_FILE)
   rapi_cert = utils.ReadFile(constants.RAPI_CERT_FILE)
+  hmac_key = utils.ReadFile(constants.HMAC_CLUSTER_KEY)
 
   # in the base64 pem encoding, neither '!' nor '.' are valid chars,
   # so we use this to detect an invalid certificate; as long as the
   # cert doesn't contain this, the here-document will be correctly
-  # parsed by the shell sequence below
-  if (re.search('^!EOF\.', noded_cert, re.MULTILINE) or
-      re.search('^!EOF\.', rapi_cert, re.MULTILINE)):
-    raise errors.OpExecError("invalid PEM encoding in the SSL certificate")
+  # parsed by the shell sequence below. HMAC keys are hexadecimal strings,
+  # so the same restrictions apply.
+  for content in (noded_cert, rapi_cert, hmac_key):
+    if re.search('^!EOF\.', content, re.MULTILINE):
+      raise errors.OpExecError("invalid SSL certificate or HMAC key")
 
   if not noded_cert.endswith("\n"):
     noded_cert += "\n"
   if not rapi_cert.endswith("\n"):
     rapi_cert += "\n"
+  if not hmac_key.endswith("\n"):
+    hmac_key += "\n"
 
   # set up inter-node password and certificate and restarts the node daemon
   # and then connect with ssh to set password and start ganeti-noded
@@ -365,11 +381,15 @@ def SetupNodeDaemon(cluster_name, node, ssh_key_check):
                "%s!EOF.\n"
                "cat > '%s' << '!EOF.' && \n"
                "%s!EOF.\n"
-               "chmod 0400 %s %s && "
+               "cat > '%s' << '!EOF.' && \n"
+               "%s!EOF.\n"
+               "chmod 0400 %s %s %s && "
                "%s restart" %
                (constants.SSL_CERT_FILE, noded_cert,
                 constants.RAPI_CERT_FILE, rapi_cert,
+                constants.HMAC_CLUSTER_KEY, hmac_key,
                 constants.SSL_CERT_FILE, constants.RAPI_CERT_FILE,
+                constants.HMAC_CLUSTER_KEY,
                 constants.NODE_INITD_SCRIPT))
 
   result = sshrunner.Run(node, 'root', mycommand, batch=False,
@@ -435,7 +455,7 @@ def MasterFailover(no_voting=False):
   logging.info("Setting master to %s, old master: %s", new_master, old_master)
 
   result = rpc.RpcRunner.call_node_stop_master(old_master, True)
-  msg = result.RemoteFailMsg()
+  msg = result.fail_msg
   if msg:
     logging.error("Could not disable the master role on the old master"
                  " %s, please disable manually: %s", old_master, msg)
@@ -453,7 +473,7 @@ def MasterFailover(no_voting=False):
   cfg.Update(cluster_info)
 
   result = rpc.RpcRunner.call_node_start_master(new_master, True, no_voting)
-  msg = result.RemoteFailMsg()
+  msg = result.fail_msg
   if msg:
     logging.error("Could not start the master role on the new master"
                   " %s, please check: %s", new_master, msg)
@@ -516,7 +536,7 @@ def GatherMasterVotes(node_list):
   for node in results:
     nres = results[node]
     data = nres.payload
-    msg = nres.RemoteFailMsg()
+    msg = nres.fail_msg
     fail = False
     if msg:
       logging.warning("Error contacting node %s: %s", node, msg)