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
>
>

Reply via email to