On Tue, Mar 17, 2015 at 04:22:19PM +0000, Helga Velroyen wrote:
Hi!
thanks for the comments. All adressed, see interdiff:
diff --git a/lib/cmdlib/cluster.py b/lib/cmdlib/cluster.py
index a99fcc7..0f4b2eb 100644
--- a/lib/cmdlib/cluster.py
+++ b/lib/cmdlib/cluster.py
@@ -164,20 +164,19 @@ class LUClusterRenewCrypto(NoHooksLU):
feedback_fn("* Skipping offline node %s" % node_info.name)
continue
if node_uuid != master_uuid:
- num_try = 0
- successful = False
- while not successful and num_try < self._MAX_NUM_RETRIES:
- num_try += 1
+ for _ in range(self._MAX_NUM_RETRIES):
try:
new_digest = CreateNewClientCert(self, node_uuid)
if node_info.master_candidate:
utils.AddNodeToCandidateCerts(node_uuid,
new_digest,
cluster.candidate_certs)
- successful = True
- except errors.OpExecError as e:
- if num_try == self._MAX_NUM_RETRIES:
- node_errors[node_uuid] = e
+ break
+ except errors.OpExecError as last_exception:
+ pass
+ else:
+ if last_exception:
+ node_errors[node_uuid] = last_exception
I didn't realize here that we need to keep the last exception.
I was a bit baffled that Python allows the binding of 'last_exception' to
escape the 'except' scope, but apparently it does the trick nicely.
if node_errors:
msg = ("Some nodes' SSL client certificates could not be renewed."
diff --git a/test/py/cmdlib/cluster_unittest.py
b/test/py/cmdlib/cluster_unittest.py
index dfb5c12..073b8de 100644
--- a/test/py/cmdlib/cluster_unittest.py
+++ b/test/py/cmdlib/cluster_unittest.py
@@ -2481,12 +2481,11 @@ class TestLUClusterRenewCrypto(CmdlibTestCase):
.CreateSuccessfulNodeResult(node_uuid,
[(constants.CRYPTO_TYPE_SSL_DIGEST,
self._GetFakeDigest(node_uuid))])
- @patchPathutils("cluster")
- def testNonMasterRetriesSuccess(self, pathutils):
+ def _NonMasterRetries(self, pathutils, max_retries):
self._InitPathutils(pathutils)
self._master_uuid = self.cfg.GetMasterNode()
- self._max_retries = 2
+ self._max_retries = max_retries
self._retries = 0
self.rpc.call_node_crypto_tokens =
self._RpcSuccessfulAfterRetriesNonMaster
@@ -2498,27 +2497,17 @@ class TestLUClusterRenewCrypto(CmdlibTestCase):
self._AssertCertFiles(pathutils)
- cluster = self.cfg.GetClusterInfo()
+ return self.cfg.GetClusterInfo()
+
+ @patchPathutils("cluster")
+ def testNonMasterRetriesSuccess(self, pathutils):
+ cluster = self._NonMasterRetries(pathutils, 2)
self.assertEqual(2, len(cluster.candidate_certs.values()))
@patchPathutils("cluster")
def testNonMasterRetriesFail(self, pathutils):
- self._InitPathutils(pathutils)
-
- self._master_uuid = self.cfg.GetMasterNode()
- self._max_retries = 5
- self._retries = 0
- self.rpc.call_node_crypto_tokens =
self._RpcSuccessfulAfterRetriesNonMaster
-
- # Add one non-master node
- self.cfg.AddNewNode()
+ cluster = self._NonMasterRetries(pathutils, 5)
- op = opcodes.OpClusterRenewCrypto()
- self.ExecOpCode(op)
-
- self._AssertCertFiles(pathutils)
-
- cluster = self.cfg.GetClusterInfo()
# Only the master digest should be in the cert list
self.assertEqual(1, len(cluster.candidate_certs.values()))
self.assertTrue(self._master_uuid in cluster.candidate_certs)
On Mon, 16 Mar 2015 at 16:11 Petr Pudlak <[email protected]> wrote:
On Thu, Mar 05, 2015 at 11:11:04PM +0100, 'Helga Velroyen' via
ganeti-devel wrote:
>If renewing the SSL certificate for non-master nodes fails,
>try retring two more times. Unit tests included.
>
>Signed-off-by: Helga Velroyen <[email protected]>
>---
> lib/cmdlib/cluster.py | 22 ++++++++++------
> test/py/cmdlib/cluster_unittest.py | 54 ++++++++++++++++++++++++++++++
+++++++-
> 2 files changed, 67 insertions(+), 9 deletions(-)
>
>diff --git a/lib/cmdlib/cluster.py b/lib/cmdlib/cluster.py
>index fb32eec..92935e6 100644
>--- a/lib/cmdlib/cluster.py
>+++ b/lib/cmdlib/cluster.py
>@@ -166,14 +166,20 @@ class LUClusterRenewCrypto(NoHooksLU):
> feedback_fn("* Skipping offline node %s" % node_info.name)
> continue
> if node_uuid != master_uuid:
>- try:
>- new_digest = CreateNewClientCert(self, node_uuid)
>- if node_info.master_candidate:
>- utils.AddNodeToCandidateCerts(node_uuid,
>- new_digest,
>- cluster.candidate_certs)
>- except errors.OpExecError as e:
>- node_errors[node_uuid] = e
>+ num_try = 0
>+ successful = False
>+ while not successful and num_try < self._MAX_NUM_RETRIES:
>+ num_try += 1
>+ try:
>+ new_digest = CreateNewClientCert(self, node_uuid)
>+ if node_info.master_candidate:
>+ utils.AddNodeToCandidateCerts(node_uuid,
>+ new_digest,
>+ cluster.candidate_certs)
>+ successful = True
>+ except errors.OpExecError as e:
>+ if num_try == self._MAX_NUM_RETRIES:
>+ node_errors[node_uuid] = e
Same idea as in the previous patch, to get rid of `num_try` and
`successful`
:)
>
> if node_errors:
> msg = ("Some nodes' SSL client certificates could not be renewed."
>diff --git a/test/py/cmdlib/cluster_unittest.py b/test/py/cmdlib/cluster_
unittest.py
>index 917ff14..354fdf8 100644
>--- a/test/py/cmdlib/cluster_unittest.py
>+++ b/test/py/cmdlib/cluster_unittest.py
>@@ -2469,7 +2469,59 @@ class TestLUClusterRenewCrypto(CmdlibTestCase):
> self._AssertCertFiles(pathutils)
>
> cluster = self.cfg.GetClusterInfo()
>- self.assertFalse(cluster.candidate_certs.values)
>+ self.assertFalse(cluster.candidate_certs)
>+
>+ def _RpcSuccessfulAfterRetriesNonMaster(self, node_uuid, _):
>+ if self._retries < self._max_retries and node_uuid !=
self._master_uuid:
>+ self._retries += 1
>+ return self.RpcResultsBuilder() \
>+ .CreateFailedNodeResult(node_uuid)
>+ else:
>+ return self.RpcResultsBuilder() \
>+ .CreateSuccessfulNodeResult(node_uuid,
>+ [(constants.CRYPTO_TYPE_SSL_DIGEST,
self._GetFakeDigest(node_uuid))])
>+
>+ @patchPathutils("cluster")
>+ def testNonMasterRetriesSuccess(self, pathutils):
>+ self._InitPathutils(pathutils)
>+
>+ self._master_uuid = self.cfg.GetMasterNode()
>+ self._max_retries = 2
>+ self._retries = 0
>+ self.rpc.call_node_crypto_tokens = self._
RpcSuccessfulAfterRetriesNonMaster
>+
>+ # Add one non-master node
>+ self.cfg.AddNewNode()
>+
>+ op = opcodes.OpClusterRenewCrypto()
>+ self.ExecOpCode(op)
>+
>+ self._AssertCertFiles(pathutils)
>+
>+ cluster = self.cfg.GetClusterInfo()
>+ self.assertEqual(2, len(cluster.candidate_certs.values()))
>+
>+ @patchPathutils("cluster")
>+ def testNonMasterRetriesFail(self, pathutils):
>+ self._InitPathutils(pathutils)
>+
>+ self._master_uuid = self.cfg.GetMasterNode()
>+ self._max_retries = 5
>+ self._retries = 0
>+ self.rpc.call_node_crypto_tokens = self._
RpcSuccessfulAfterRetriesNonMaster
>+
>+ # Add one non-master node
>+ self.cfg.AddNewNode()
>+
>+ op = opcodes.OpClusterRenewCrypto()
>+ self.ExecOpCode(op)
>+
>+ self._AssertCertFiles(pathutils)
>+
>+ cluster = self.cfg.GetClusterInfo()
>+ # Only the master digest should be in the cert list
>+ self.assertEqual(1, len(cluster.candidate_certs.values()))
>+ self.assertTrue(self._master_uuid in cluster.candidate_certs)
These two methods are always the same, maybe it make sense to add a helper
that accepts a number of retries and returns 'cluster' for inspection?
>
>
> if __name__ == "__main__":
>--
>2.2.0.rc0.207.ga3a616c
>
Rest LGTM, thanks
LGTM, thanks