This patch makes renew-crypto actually use the bulk-adding
function of SSH keys rather than adding each key
individually. This patch also adds a unit tests where the
bulk-adding is tested with a diverse set of keys (master
candidates, potential master candidates, normal nodes).

Signed-off-by: Helga Velroyen <[email protected]>
---
 lib/backend.py                     | 32 +++++++++++++++++--------
 test/py/ganeti.backend_unittest.py | 48 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+), 10 deletions(-)

diff --git a/lib/backend.py b/lib/backend.py
index c847ca8..ce5bb6a 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -1514,6 +1514,10 @@ def AddNodeSshKeyBulk(node_list,
     ssconf_store = ssconf.SimpleStore()
 
   for node_info in node_list:
+    # replacement not necessary for keys that are not supposed to be in the
+    # list of public keys
+    if not node_info.to_public_keys:
+      continue
     # Check and fix sanity of key file
     keys_by_name = ssh.QueryPubKeyFile([node_info.name], key_file=pub_key_file)
     keys_by_uuid = ssh.QueryPubKeyFile([node_info.uuid], key_file=pub_key_file)
@@ -2009,6 +2013,10 @@ def RenewSshKeys(node_uuids, node_names, 
master_candidate_uuids,
   all_node_errors = []
 
   # process non-master nodes
+
+  # keys to add in bulk at the end
+  node_keys_to_add = []
+
   for node_uuid, node_name in node_uuid_name_map:
     if node_name == master_node_name:
       continue
@@ -2070,16 +2078,20 @@ def RenewSshKeys(node_uuids, node_names, 
master_candidate_uuids,
       ssh.AddPublicKey(node_uuid, pub_key, key_file=pub_key_file)
 
     logging.debug("Add ssh key of node '%s'.", node_name)
-    node_errors = AddNodeSshKey(
-        node_uuid, node_name, potential_master_candidates,
-        to_authorized_keys=master_candidate,
-        to_public_keys=potential_master_candidate,
-        get_public_keys=True,
-        pub_key_file=pub_key_file, ssconf_store=ssconf_store,
-        noded_cert_file=noded_cert_file,
-        run_cmd_fn=run_cmd_fn)
-    if node_errors:
-      all_node_errors = all_node_errors + node_errors
+    node_info = SshAddNodeInfo(name=node_name,
+                               uuid=node_uuid,
+                               to_authorized_keys=master_candidate,
+                               to_public_keys=potential_master_candidate,
+                               get_public_keys=True)
+    node_keys_to_add.append(node_info)
+
+  node_errors = AddNodeSshKeyBulk(
+      node_keys_to_add, potential_master_candidates,
+      pub_key_file=pub_key_file, ssconf_store=ssconf_store,
+      noded_cert_file=noded_cert_file,
+      run_cmd_fn=run_cmd_fn)
+  if node_errors:
+    all_node_errors = all_node_errors + node_errors
 
   # Renewing the master node's key
 
diff --git a/test/py/ganeti.backend_unittest.py 
b/test/py/ganeti.backend_unittest.py
index 6185592..43d2dde 100755
--- a/test/py/ganeti.backend_unittest.py
+++ b/test/py/ganeti.backend_unittest.py
@@ -1269,6 +1269,54 @@ class 
TestAddRemoveGenerateNodeSshKey(testutils.GanetiTestCase):
       self._ssh_file_manager.AssertNoNodeHasAuthorizedKey(
           key_map[node_info.name])
 
+  def _GetNewNumberedNode(self, num):
+    """Returns the properties of a node.
+
+    This will in round-robin style return a master candidate, a
+    potential master candiate and a normal node.
+
+    """
+    is_master_candidate = num % 3 == 0
+    is_potential_master_candidate = num % 3 == 0 or num % 3 == 1
+    is_master = False
+    return ("new_node_name_%s" % num,
+            "new_node_uuid_%s" % num,
+            "new_node_key_%s" % num,
+            is_master_candidate, is_potential_master_candidate, is_master)
+
+  def testAddDiverseNodeBulk(self):
+    """Tests adding keys of several nodes with several qualities.
+
+    This tests subsumes previous tests. However, we leave the previous
+    tests here, because debugging problems with this all-embracing test
+    is much more tedious than having one of the one-purpose tests fail.
+
+    """
+    num_nodes = 9
+    (node_list, key_map) = self._SetupNodeBulk(
+        num_nodes, self._GetNewNumberedNode)
+
+    backend.AddNodeSshKeyBulk(node_list,
+                              self._potential_master_candidates,
+                              pub_key_file=self._pub_key_file,
+                              ssconf_store=self._ssconf_mock,
+                              noded_cert_file=self.noded_cert_file,
+                              run_cmd_fn=self._run_cmd_mock)
+
+    for node_info in node_list:
+      if node_info.to_authorized_keys:
+        self._ssh_file_manager.AssertAllNodesHaveAuthorizedKey(
+            key_map[node_info.name])
+      else:
+        self._ssh_file_manager.AssertNoNodeHasAuthorizedKey(
+            key_map[node_info.name])
+      if node_info.to_public_keys:
+        
self._ssh_file_manager.AssertPotentialMasterCandidatesOnlyHavePublicKey(
+            node_info.name)
+      else:
+        self._ssh_file_manager.AssertNoNodeHasPublicKey(
+            node_info.uuid, key_map[node_info.name])
+
   def testPromoteToMasterCandidate(self):
     # Get one of the potential master candidates
     node_name, node_info = \
-- 
2.6.0.rc2.230.g3dd15c0

Reply via email to