AddNode: move the initial setup to boostrap
authorGuido Trotter <ultrotter@google.com>
Fri, 27 Jun 2008 14:28:50 +0000 (14:28 +0000)
committerGuido Trotter <ultrotter@google.com>
Fri, 27 Jun 2008 14:28:50 +0000 (14:28 +0000)
From the master node we can't start ssh and connect to the remote node,
nor we can do it from ganeti-noded as this ssh section will possibly ask
for key confirmation and password. So the code to copy the ganeti-noded
password and SSL key has been moved to bootstrap.py, and it's called by
gnt-node before the AddNode opcode.

Reviewed-by: iustinp

lib/bootstrap.py
lib/cmdlib.py
scripts/gnt-node

index 6cd7424..92cc6e5 100644 (file)
@@ -227,3 +227,54 @@ def InitCluster(cluster_name, hypervisor_type, mac_prefix, def_bridge,
                  mac_prefix, vg_name, def_bridge)
 
   ssh.WriteKnownHostsFile(cfg, ss, constants.SSH_KNOWN_HOSTS_FILE)
+
+def SetupNodeDaemon(node):
+  """Add a node to the cluster.
+
+  This function must be called before the actual opcode, and will ssh to the
+  remote node, copy the needed files, and start ganeti-noded, allowing the master
+  to do the rest via normal rpc calls.
+
+  Args:
+    node: fully qualified domain name for the new node
+
+  """
+  ss = ssconf.SimpleStore()
+  sshrunner = ssh.SshRunner(ss)
+  gntpass = ss.GetNodeDaemonPassword()
+  if not re.match('^[a-zA-Z0-9.]{1,64}$', gntpass):
+    raise errors.OpExecError("ganeti password corruption detected")
+  f = open(constants.SSL_CERT_FILE)
+  try:
+    gntpem = f.read(8192)
+  finally:
+    f.close()
+  # 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\.', gntpem, re.MULTILINE):
+    raise errors.OpExecError("invalid PEM encoding in the SSL certificate")
+  if not gntpem.endswith("\n"):
+    raise errors.OpExecError("PEM must end with newline")
+
+  # set up inter-node password and certificate and restarts the node daemon
+  # and then connect with ssh to set password and start ganeti-noded
+  # note that all the below variables are sanitized at this point,
+  # either by being constants or by the checks above
+  mycommand = ("umask 077 && "
+               "echo '%s' > '%s' && "
+               "cat > '%s' << '!EOF.' && \n"
+               "%s!EOF.\n%s restart" %
+               (gntpass, ss.KeyToFilename(ss.SS_NODED_PASS),
+                constants.SSL_CERT_FILE, gntpem,
+                constants.NODE_INITD_SCRIPT))
+
+  result = sshrunner.Run(node, 'root', mycommand, batch=False, ask_key=True)
+  if result.failed:
+    raise errors.OpExecError("Remote command on node %s, error: %s,"
+                             " output: %s" %
+                             (node, result.fail_reason, result.output))
+
+  return 0
+
index 1b85486..eabd8eb 100644 (file)
@@ -1529,46 +1529,7 @@ class LUAddNode(LogicalUnit):
     new_node = self.new_node
     node = new_node.name
 
-    # set up inter-node password and certificate and restarts the node daemon
-    gntpass = self.sstore.GetNodeDaemonPassword()
-    if not re.match('^[a-zA-Z0-9.]{1,64}$', gntpass):
-      raise errors.OpExecError("ganeti password corruption detected")
-    f = open(constants.SSL_CERT_FILE)
-    try:
-      gntpem = f.read(8192)
-    finally:
-      f.close()
-    # 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\.', gntpem, re.MULTILINE):
-      raise errors.OpExecError("invalid PEM encoding in the SSL certificate")
-    if not gntpem.endswith("\n"):
-      raise errors.OpExecError("PEM must end with newline")
-    logger.Info("copy cluster pass to %s and starting the node daemon" % node)
-
-    # and then connect with ssh to set password and start ganeti-noded
-    # note that all the below variables are sanitized at this point,
-    # either by being constants or by the checks above
-    ss = self.sstore
-    mycommand = ("umask 077 && "
-                 "echo '%s' > '%s' && "
-                 "cat > '%s' << '!EOF.' && \n"
-                 "%s!EOF.\n%s restart" %
-                 (gntpass, ss.KeyToFilename(ss.SS_NODED_PASS),
-                  constants.SSL_CERT_FILE, gntpem,
-                  constants.NODE_INITD_SCRIPT))
-
-    result = self.ssh.Run(node, 'root', mycommand, batch=False, ask_key=True)
-    if result.failed:
-      raise errors.OpExecError("Remote command on node %s, error: %s,"
-                               " output: %s" %
-                               (node, result.fail_reason, result.output))
-
     # check connectivity
-    time.sleep(4)
-
     result = rpc.call_version([node])[node]
     if result:
       if constants.PROTOCOL_VERSION == result:
index 552e75b..dc988cc 100755 (executable)
@@ -28,6 +28,7 @@ from ganeti import logger
 from ganeti import utils
 from ganeti import constants
 from ganeti import errors
+from ganeti import bootstrap
 
 
 _LIST_DEF_FIELDS = [
@@ -59,6 +60,8 @@ def AddNode(opts, args):
     "on the target machine (%s) with the ones of the current one\n"
     "and grant full intra-cluster ssh root access to/from it\n" % node)
 
+  bootstrap.SetupNodeDaemon(node)
+
   op = opcodes.OpAddNode(node_name=args[0], secondary_ip=opts.secondary_ip,
                          readd=opts.readd)
   SubmitOpCode(op)