This patch implements the removal of a node's SSH key from all nodes' "authorized_keys" files when it is demoted from being master candidate to being a normal node. It also adds the adding of a node's SSH key when it is promoted from normal node to master candidate.
Signed-off-by: Helga Velroyen <hel...@google.com> --- lib/backend.py | 27 ++++++++++++++++----------- lib/cmdlib/node.py | 4 +--- lib/config.py | 20 ++++++++++++++++++++ 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/lib/backend.py b/lib/backend.py index 717298c..efdc00a 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -1436,16 +1436,22 @@ def AddNodeSshKey(node_uuid, node_name, # Check and fix sanity of key file keys_by_name = ssh.QueryPubKeyFile([node_name], key_file=pub_key_file) - keys_by_uuid = {} - if not keys_by_name or node_name not in keys_by_name: - raise errors.SshUpdateError("No keys found for the new node '%s' in the" - " list of public SSH keys." % node_name) + keys_by_uuid = ssh.QueryPubKeyFile([node_uuid], key_file=pub_key_file) + + if (not keys_by_name or node_name not in keys_by_name) \ + and (not keys_by_uuid or node_uuid not in keys_by_uuid): + raise errors.SshUpdateError( + "No keys found for the new node '%s' (UUID %s) in the list of public" + " SSH keys, neither for the name or the UUID" % (node_name, node_uuid)) else: - # Replace the name by UUID in the file as the name should only be used - # temporarily - ssh.ReplaceNameByUuid(node_uuid, node_name, error_fn=errors.SshUpdateError, - key_file=pub_key_file) - keys_by_uuid[node_uuid] = keys_by_name[node_name] + if node_name in keys_by_name: + keys_by_uuid = {} + # Replace the name by UUID in the file as the name should only be used + # temporarily + ssh.ReplaceNameByUuid(node_uuid, node_name, + error_fn=errors.SshUpdateError, + key_file=pub_key_file) + keys_by_uuid[node_uuid] = keys_by_name[node_name] # Update the master node's key files if to_authorized_keys: @@ -1584,7 +1590,7 @@ def RemoveNodeSshKey(node_uuid, node_name, from_authorized_keys, ssh_port, base_data, ssconf_store) authorized_keys_to_clear = {} - if clear_authorized_keys or from_public_keys or from_authorized_keys: + if clear_authorized_keys or from_public_keys: data = {} _InitSshUpdateData(data, noded_cert_file, ssconf_store) cluster_name = data[constants.SSHS_CLUSTER_NAME] @@ -1595,7 +1601,6 @@ def RemoveNodeSshKey(node_uuid, node_name, from_authorized_keys, authorized_keys_to_clear = {} if clear_authorized_keys: - # We never clear a node's key from its own 'authorized_keys' file other_master_candidate_uuids = [uuid for uuid in master_candidate_uuids if uuid != node_uuid] candidate_keys = ssh.QueryPubKeyFile(other_master_candidate_uuids, diff --git a/lib/cmdlib/node.py b/lib/cmdlib/node.py index 823ebb6..1fc6f06 100644 --- a/lib/cmdlib/node.py +++ b/lib/cmdlib/node.py @@ -1563,9 +1563,7 @@ class LUNodeRemove(LogicalUnit): potential_master_candidate = \ self.op.node_name in potential_master_candidates ssh_port_map = GetSshPortMap(potential_master_candidates, self.cfg) - master_candidate_uuids = [uuid for (uuid, node_info) - in self.cfg.GetAllNodesInfo().items() - if node_info.master_candidate] + master_candidate_uuids = self.cfg.GetMasterCandidateUuids() master_node = self.cfg.GetMasterNode() result = self.rpc.call_node_ssh_key_remove( [master_node], diff --git a/lib/config.py b/lib/config.py index 6be2814..e2b2bd5 100644 --- a/lib/config.py +++ b/lib/config.py @@ -2576,6 +2576,26 @@ class ConfigWriter(object): return frozenset(self._UnlockedGetNodeInfo(uuid).group for uuid in node_uuids) + def _UnlockedGetMasterCandidateUuids(self): + """Get the list of UUIDs of master candidates. + + @rtype: list of strings + @return: list of UUIDs of all master candidates. + + """ + return [node.uuid for node in self._ConfigData().nodes.values() + if node.master_candidate] + + @_ConfigSync(shared=1) + def GetMasterCandidateUuids(self): + """Get the list of UUIDs of master candidates. + + @rtype: list of strings + @return: list of UUIDs of all master candidates. + + """ + return self._UnlockedGetMasterCandidateUuids() + def _UnlockedGetMasterCandidateStats(self, exceptions=None): """Get the number of current and maximum desired and possible candidates. -- 2.1.0.rc2.206.gedb03e5