So far the generation of client certificates was only called from ssl_update.py used in when calling 'gnt-cluster renew-crypto'. This patch moves the function from ssl_update.py to tools/common.py, because it will also be needed by prepare_node_join.py when adding nodes (see next patch in the series).
Signed-off-by: Helga Velroyen <[email protected]> --- lib/tools/common.py | 30 +++++++++++ lib/tools/ssl_update.py | 31 +---------- test/py/ganeti.tools.common_unittest.py | 82 ++++++++++++++++++++++++++++ test/py/ganeti.tools.ssl_update_unittest.py | 84 ----------------------------- 4 files changed, 113 insertions(+), 114 deletions(-) create mode 100755 test/py/ganeti.tools.common_unittest.py delete mode 100755 test/py/ganeti.tools.ssl_update_unittest.py diff --git a/lib/tools/common.py b/lib/tools/common.py index 2b39308..547c072 100644 --- a/lib/tools/common.py +++ b/lib/tools/common.py @@ -33,9 +33,12 @@ import logging import OpenSSL +import os +import time from cStringIO import StringIO from ganeti import constants +from ganeti import pathutils from ganeti import utils from ganeti import serializer from ganeti import ssconf @@ -138,3 +141,30 @@ def LoadData(raw, data_check): """ return serializer.LoadAndVerifyJson(raw, data_check) + + +def GenerateClientCertificate( + data, error_fn, client_cert=pathutils.NODED_CLIENT_CERT_FILE, + signing_cert=pathutils.NODED_CERT_FILE): + """Regenerates the client certificate of the node. + + @type data: string + @param data: the JSON-formated input data + + """ + if not os.path.exists(signing_cert): + raise error_fn("The signing certificate '%s' cannot be found." + % signing_cert) + + # TODO: This sets the serial number to the number of seconds + # since epoch. This is technically not a correct serial number + # (in the way SSL is supposed to be used), but it serves us well + # enough for now, as we don't have any infrastructure for keeping + # track of the number of signed certificates yet. + serial_no = int(time.time()) + + # The hostname of the node is provided with the input data. + hostname = data.get(constants.NDS_NODE_NAME) + + utils.GenerateSignedSslCert(client_cert, serial_no, signing_cert, + common_name=hostname) diff --git a/lib/tools/ssl_update.py b/lib/tools/ssl_update.py index 3764e2d..4d17d9d 100644 --- a/lib/tools/ssl_update.py +++ b/lib/tools/ssl_update.py @@ -36,14 +36,12 @@ import os.path import optparse import sys import logging -import time from ganeti import cli from ganeti import constants from ganeti import errors from ganeti import utils from ganeti import ht -from ganeti import pathutils from ganeti.tools import common @@ -77,33 +75,6 @@ def ParseOptions(): return common.VerifyOptions(parser, opts, args) -def RegenerateClientCertificate( - data, client_cert=pathutils.NODED_CLIENT_CERT_FILE, - signing_cert=pathutils.NODED_CERT_FILE): - """Regenerates the client certificate of the node. - - @type data: string - @param data: the JSON-formated input data - - """ - if not os.path.exists(signing_cert): - raise SslSetupError("The signing certificate '%s' cannot be found." - % signing_cert) - - # TODO: This sets the serial number to the number of seconds - # since epoch. This is technically not a correct serial number - # (in the way SSL is supposed to be used), but it serves us well - # enough for now, as we don't have any infrastructure for keeping - # track of the number of signed certificates yet. - serial_no = int(time.time()) - - # The hostname of the node is provided with the input data. - hostname = data.get(constants.NDS_NODE_NAME) - - utils.GenerateSignedSslCert(client_cert, serial_no, signing_cert, - common_name=hostname) - - def Main(): """Main routine. @@ -121,7 +92,7 @@ def Main(): # is the same as on this node. common.VerifyCertificate(data, SslSetupError) - RegenerateClientCertificate(data) + common.GenerateClientCertificate(data, SslSetupError) except Exception, err: # pylint: disable=W0703 logging.debug("Caught unhandled exception", exc_info=True) diff --git a/test/py/ganeti.tools.common_unittest.py b/test/py/ganeti.tools.common_unittest.py new file mode 100755 index 0000000..1652088 --- /dev/null +++ b/test/py/ganeti.tools.common_unittest.py @@ -0,0 +1,82 @@ +#!/usr/bin/python +# + +# Copyright (C) 2015 Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +"""Script for testing ganeti.tools.ssl_update""" + +import unittest +import shutil +import tempfile +import os.path +import OpenSSL +import time + +from ganeti import constants +from ganeti import utils +from ganeti.tools import common + +import testutils + + +class TestGenerateClientCert(unittest.TestCase): + + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + + self.client_cert = os.path.join(self.tmpdir, "client.pem") + + self.server_cert = os.path.join(self.tmpdir, "server.pem") + some_serial_no = int(time.time()) + utils.GenerateSelfSignedSslCert(self.server_cert, some_serial_no) + + def tearDown(self): + shutil.rmtree(self.tmpdir) + + def testRegnerateClientCertificate(self): + my_node_name = "mynode.example.com" + data = {constants.NDS_CLUSTER_NAME: "winnie_poohs_cluster", + constants.NDS_NODE_DAEMON_CERTIFICATE: "some_cert", + constants.NDS_NODE_NAME: my_node_name} + + common.GenerateClientCertificate(data, Exception, + client_cert=self.client_cert, + signing_cert=self.server_cert) + + client_cert_pem = utils.ReadFile(self.client_cert) + server_cert_pem = utils.ReadFile(self.server_cert) + client_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, + client_cert_pem) + signing_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, + server_cert_pem) + self.assertEqual(client_cert.get_issuer().CN, signing_cert.get_subject().CN) + self.assertEqual(client_cert.get_subject().CN, my_node_name) + + +if __name__ == "__main__": + testutils.GanetiTestProgram() diff --git a/test/py/ganeti.tools.ssl_update_unittest.py b/test/py/ganeti.tools.ssl_update_unittest.py deleted file mode 100755 index e4b3ad9..0000000 --- a/test/py/ganeti.tools.ssl_update_unittest.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/python -# - -# Copyright (C) 2015 Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -"""Script for testing ganeti.tools.ssl_update""" - -import unittest -import shutil -import tempfile -import os.path -import OpenSSL -import time - -from ganeti import errors -from ganeti import constants -from ganeti import serializer -from ganeti import pathutils -from ganeti import compat -from ganeti import utils -from ganeti.tools import ssl_update - -import testutils - - -class TestGenerateClientCert(unittest.TestCase): - def setUp(self): - self.tmpdir = tempfile.mkdtemp() - - self.client_cert = os.path.join(self.tmpdir, "client.pem") - - self.server_cert = os.path.join(self.tmpdir, "server.pem") - some_serial_no = int(time.time()) - utils.GenerateSelfSignedSslCert(self.server_cert, some_serial_no) - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def testRegnerateClientCertificate(self): - my_node_name = "mynode.example.com" - data = {constants.NDS_CLUSTER_NAME: "winnie_poohs_cluster", - constants.NDS_NODE_DAEMON_CERTIFICATE: "some_cert", - constants.NDS_NODE_NAME: my_node_name} - - ssl_update.RegenerateClientCertificate(data, client_cert=self.client_cert, - signing_cert=self.server_cert) - - client_cert_pem = utils.ReadFile(self.client_cert) - server_cert_pem = utils.ReadFile(self.server_cert) - client_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, - client_cert_pem) - signing_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, - server_cert_pem) - self.assertEqual(client_cert.get_issuer().CN, signing_cert.get_subject().CN) - self.assertEqual(client_cert.get_subject().CN, my_node_name) - - -if __name__ == "__main__": - testutils.GanetiTestProgram() -- 2.4.3.573.g4eafbef
