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

Reply via email to