On adding a new node, a new public/private SSH key pair will be generated. The public key pair needs (possibly) to be added to the 'ganeti_pub_keys' file and the 'authorized_keys' file of other cluster nodes. This patch provides the mechanism to fetch the new node's public SSH key via ssh. Node that at this point, no new public/private key pair is generated yet. This will come in a later patch of this series as we first want to have all infrastructure in place.
Signed-off-by: Helga Velroyen <hel...@google.com> --- lib/client/gnt_node.py | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/lib/client/gnt_node.py b/lib/client/gnt_node.py index d77d031..264c07b 100644 --- a/lib/client/gnt_node.py +++ b/lib/client/gnt_node.py @@ -40,6 +40,7 @@ from ganeti import netutils from ganeti import pathutils from ganeti import ssh from ganeti import compat +from ganeti import ssconf from ganeti import confd from ganeti.confd import client as confd_client @@ -183,6 +184,47 @@ def _ReadSshKeys(keyfiles, _tostderr_fn=ToStderr): return result +def _ReadRemoteSshPubKeys(keyfiles, node, cluster_name, port, ask_key, + strict_host_check, _tosterr_fn=ToStderr): + """Fetches the public SSH keys from a node via SSH. + + @type keyfiles: dict from string to (string, string) tuples + @param keyfiles: a dictionary mapping the type of key (e.g. rsa, dsa) to a + tuple consisting of the file name of the private and public key + + """ + family = ssconf.SimpleStore().GetPrimaryIPFamily() + ssh_runner = ssh.SshRunner(cluster_name, + ipv6=(family == netutils.IP6Address.family)) + + failed_results = {} + fetched_keys = {} + for (kind, (_, public_key_file)) in keyfiles.items(): + cmd = ["cat", public_key_file] + ssh_cmd = ssh_runner.BuildCmd(node, constants.SSH_LOGIN_USER, + utils.ShellQuoteArgs(cmd), + batch=False, ask_key=ask_key, quiet=False, + strict_host_check=strict_host_check, + use_cluster_key=False, + port=port) + + result = utils.RunCmd(ssh_cmd) + if result.failed: + failed_results[kind] = (result.cmd, result.fail_reason) + else: + fetched_keys[kind] = result.stdout + + if len(fetched_keys.keys()) < 1: + error_msg = "Could not fetch any public SSH key." + for (kind, (cmd, fail_reason)) in failed_results.items(): + error_msg += "Could not fetch the public '%s' SSH key from node '%s':" \ + " ran command '%s', failure reason: '%s'. " % \ + (kind, node, cmd, fail_reason) + raise errors.OpPrereqError(error_msg) + + return fetched_keys + + def _SetupSSH(options, cluster_name, node, ssh_port, cl): """Configures a destination node's SSH daemon. @@ -232,6 +274,15 @@ def _SetupSSH(options, cluster_name, node, ssh_port, cl): options.ssh_key_check, options.ssh_key_check, ssh_port, data) + fetched_keys = _ReadRemoteSshPubKeys(root_keyfiles, node, cluster_name, + ssh_port, options.ssh_key_check, + options.ssh_key_check) + for pub_key in fetched_keys.values(): + # Unfortunately, we have to add the key with the node name rather than + # the node's UUID here, because at this point, we do not have a UUID yet. + # The entry will be corrected in noded later. + ssh.AddPublicKey(node, pub_key) + @UsesRPC def AddNode(opts, args): -- 2.0.0.526.g5318336