Commit 827f753e authored by Guido Trotter's avatar Guido Trotter

AddNode: move the initial setup to boostrap

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
parent 05ccd983
...@@ -227,3 +227,54 @@ def InitCluster(cluster_name, hypervisor_type, mac_prefix, def_bridge, ...@@ -227,3 +227,54 @@ def InitCluster(cluster_name, hypervisor_type, mac_prefix, def_bridge,
mac_prefix, vg_name, def_bridge) mac_prefix, vg_name, def_bridge)
ssh.WriteKnownHostsFile(cfg, ss, constants.SSH_KNOWN_HOSTS_FILE) 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
...@@ -1529,46 +1529,7 @@ class LUAddNode(LogicalUnit): ...@@ -1529,46 +1529,7 @@ class LUAddNode(LogicalUnit):
new_node = self.new_node new_node = self.new_node
node = new_node.name 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 # check connectivity
time.sleep(4)
result = rpc.call_version([node])[node] result = rpc.call_version([node])[node]
if result: if result:
if constants.PROTOCOL_VERSION == result: if constants.PROTOCOL_VERSION == result:
......
...@@ -28,6 +28,7 @@ from ganeti import logger ...@@ -28,6 +28,7 @@ from ganeti import logger
from ganeti import utils from ganeti import utils
from ganeti import constants from ganeti import constants
from ganeti import errors from ganeti import errors
from ganeti import bootstrap
_LIST_DEF_FIELDS = [ _LIST_DEF_FIELDS = [
...@@ -59,6 +60,8 @@ def AddNode(opts, args): ...@@ -59,6 +60,8 @@ def AddNode(opts, args):
"on the target machine (%s) with the ones of the current one\n" "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) "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, op = opcodes.OpAddNode(node_name=args[0], secondary_ip=opts.secondary_ip,
readd=opts.readd) readd=opts.readd)
SubmitOpCode(op) SubmitOpCode(op)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment