On Thu, Dec 19, 2013 at 3:49 PM, Helga Velroyen <[email protected]> wrote:
> This patch adds a couple of utility functions to manipulate > the map of master candidate SSL certificate digests. > > Signed-off-by: Helga Velroyen <[email protected]> > --- > Makefile.am | 2 + > lib/utils/security.py | 76 > +++++++++++++++++++++++++++++++ > test/py/ganeti.utils.security_unittest.py | 74 > ++++++++++++++++++++++++++++++ > 3 files changed, 152 insertions(+) > create mode 100644 lib/utils/security.py > create mode 100755 test/py/ganeti.utils.security_unittest.py > > diff --git a/Makefile.am b/Makefile.am > index e74f58b..96e1284 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -490,6 +490,7 @@ utils_PYTHON = \ > lib/utils/nodesetup.py \ > lib/utils/process.py \ > lib/utils/retry.py \ > + lib/utils/security.py \ > lib/utils/storage.py \ > lib/utils/text.py \ > lib/utils/version.py \ > @@ -1473,6 +1474,7 @@ python_tests = \ > test/py/ganeti.utils.nodesetup_unittest.py \ > test/py/ganeti.utils.process_unittest.py \ > test/py/ganeti.utils.retry_unittest.py \ > + test/py/ganeti.utils.security_unittest.py \ > test/py/ganeti.utils.storage_unittest.py \ > test/py/ganeti.utils.text_unittest.py \ > test/py/ganeti.utils.version_unittest.py \ > diff --git a/lib/utils/security.py b/lib/utils/security.py > new file mode 100644 > index 0000000..221b587 > --- /dev/null > +++ b/lib/utils/security.py > @@ -0,0 +1,76 @@ > +# > +# > + > +# Copyright (C) 2013 Google Inc. > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 2 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, but > +# WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +# General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program; if not, write to the Free Software > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > +# 02110-1301, USA. > + > +"""Utility functions for security features of Ganeti. > + > +""" > + > +import logging > + > + > +def AddNodeToCandidateCerts(node_uuid, cert_digest, candidate_certs, > + info_fn=logging.info, warn_fn=logging.warn): > + """Adds an entry to the candidate certificate map. > + > + @type node_uuid: string > + @param node_uuid: the node's UUID > + @type cert_digest: string > + @param cert_digest: the digest of the node's client SSL certificate > + @type candidate_certs: dict of strings to strings > + @param candidate_certs: map of node UUIDs to the digests of their client > + SSL certificates, will be manipulated in this function > + @type info_fn: function > + @param info_fn: logging function for information messages > + @type warn_fn: function > + @param warn_fn: logging function for warning messages > + > + """ > + assert candidate_certs is not None > + > + if node_uuid in candidate_certs: > + old_cert_digest = candidate_certs[node_uuid] > + if old_cert_digest == cert_digest: > + info_fn("Certificate digest for node %s already in config." > + "Not doing anything.") > The node identifier is not injected into the logging message here. > + return > + else: > + warn_fn("Overriding differing certificate digest for node %s" > + % node_uuid) > Regarding the node_uuid, a more general question: Do we have some standards regarding what goes into a log? A node uuid will identify the node, but I guess a node name is more useful to the user. If this is what we do elsewhere, then let it be :) > + candidate_certs[node_uuid] = cert_digest > + > + > +def RemoveNodeFromCandidateCerts(node_uuid, candidate_certs, > + warn_fn=logging.warn): > + """Removes the entry of the given node in the certificate map. > + > + @type node_uuid: string > + @param node_uuid: the node's UUID > + @type candidate_certs: dict of strings to strings > + @param candidate_certs: map of node UUIDs to the digests of their client > + SSL certificates, will be manipulated in this function > + @type warn_fn: function > + @param warn_fn: logging function for warning messages > + > + """ > + if node_uuid not in candidate_certs: > + warn_fn("Cannot remove certifcate for node %s, because it's not in > the" > + "candidate map.") > Again, missing identifier, and a typo: s/certifcate/certificate/ > + return > + del candidate_certs[node_uuid] > diff --git a/test/py/ganeti.utils.security_unittest.py b/test/py/ > ganeti.utils.security_unittest.py > new file mode 100755 > index 0000000..08c6b58 > --- /dev/null > +++ b/test/py/ganeti.utils.security_unittest.py > @@ -0,0 +1,74 @@ > +#!/usr/bin/python > +# > + > +# Copyright (C) 2013 Google Inc. > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 2 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, but > +# WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +# General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program; if not, write to the Free Software > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > +# 02110-1301, USA. > + > + > +"""Script for unittesting the ganeti.utils.storage module""" > + > +import mock > +import unittest > + > +from ganeti.utils import security > + > +import testutils > + > + > +class TestCandidateCerts(unittest.TestCase): > + > + def setUp(self): > + self._warn_fn = mock.Mock() > + self._info_fn = mock.Mock() > + self._candidate_certs = {} > + > + def testAddAndRemoveCerts(self): > + self.assertEqual(0, len(self._candidate_certs)) > + > + node_uuid = "1234" > + cert_digest = "foobar" > + security.AddNodeToCandidateCerts(node_uuid, cert_digest, > + self._candidate_certs, warn_fn=self._warn_fn, info_fn=self._info_fn) > + self.assertEqual(1, len(self._candidate_certs)) > + > + # Try adding the same cert again > + security.AddNodeToCandidateCerts(node_uuid, cert_digest, > + self._candidate_certs, warn_fn=self._warn_fn, info_fn=self._info_fn) > + self.assertEqual(1, len(self._candidate_certs)) > + self.assertTrue(self._candidate_certs[node_uuid] == cert_digest) > + > + # Overriding cert > + other_digest = "barfoo" > + security.AddNodeToCandidateCerts(node_uuid, other_digest, > + self._candidate_certs, warn_fn=self._warn_fn, info_fn=self._info_fn) > + self.assertEqual(1, len(self._candidate_certs)) > + self.assertTrue(self._candidate_certs[node_uuid] == other_digest) > + > + # Try removing a certificate from a node that is not in the list > + other_node_uuid = "5678" > + security.RemoveNodeFromCandidateCerts( > + other_node_uuid, self._candidate_certs, warn_fn=self._warn_fn) > + self.assertEqual(1, len(self._candidate_certs)) > + > + # Remove a certificate from a node that is in the list > + security.RemoveNodeFromCandidateCerts( > + node_uuid, self._candidate_certs, warn_fn=self._warn_fn) > + self.assertEqual(0, len(self._candidate_certs)) > + > + > +if __name__ == "__main__": > + testutils.GanetiTestProgram() > -- > 1.8.5.1 > >
