---
Makefile.am | 2 +
lib/utils/__init__.py | 86 +---------------------------
lib/utils/hash.py | 112 +++++++++++++++++++++++++++++++++++
test/ganeti.utils.hash_unittest.py | 113 ++++++++++++++++++++++++++++++++++++
test/ganeti.utils_unittest.py | 77 ------------------------
5 files changed, 228 insertions(+), 162 deletions(-)
create mode 100644 lib/utils/hash.py
create mode 100755 test/ganeti.utils.hash_unittest.py
diff --git a/Makefile.am b/Makefile.am
index a8f133e..7704dd9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -214,6 +214,7 @@ server_PYTHON = \
utils_PYTHON = \
lib/utils/__init__.py \
lib/utils/algo.py \
+ lib/utils/hash.py \
lib/utils/log.py \
lib/utils/mlock.py \
lib/utils/retry.py \
@@ -484,6 +485,7 @@ python_tests = \
test/ganeti.ssh_unittest.py \
test/ganeti.uidpool_unittest.py \
test/ganeti.utils.algo_unittest.py \
+ test/ganeti.utils.hash_unittest.py \
test/ganeti.utils.mlock_unittest.py \
test/ganeti.utils.retry_unittest.py \
test/ganeti.utils.text_unittest.py \
diff --git a/lib/utils/__init__.py b/lib/utils/__init__.py
index c1cec2f..b876965 100644
--- a/lib/utils/__init__.py
+++ b/lib/utils/__init__.py
@@ -46,7 +46,6 @@ import signal
import OpenSSL
import datetime
import calendar
-import hmac
from cStringIO import StringIO
@@ -59,6 +58,7 @@ from ganeti.utils.retry import * # pylint: disable-msg=W0401
from ganeti.utils.text import * # pylint: disable-msg=W0401
from ganeti.utils.mlock import * # pylint: disable-msg=W0401
from ganeti.utils.log import * # pylint: disable-msg=W0401
+from ganeti.utils.hash import * # pylint: disable-msg=W0401
_locksheld = []
@@ -850,55 +850,6 @@ def ResetTempfileModule():
" '_once_lock' and '_name_sequence' attributes")
-def _FingerprintFile(filename):
- """Compute the fingerprint of a file.
-
- If the file does not exist, a None will be returned
- instead.
-
- @type filename: str
- @param filename: the filename to checksum
- @rtype: str
- @return: the hex digest of the sha checksum of the contents
- of the file
-
- """
- if not (os.path.exists(filename) and os.path.isfile(filename)):
- return None
-
- f = open(filename)
-
- fp = compat.sha1_hash()
- while True:
- data = f.read(4096)
- if not data:
- break
-
- fp.update(data)
-
- return fp.hexdigest()
-
-
-def FingerprintFiles(files):
- """Compute fingerprints for a list of files.
-
- @type files: list
- @param files: the list of filename to fingerprint
- @rtype: dict
- @return: a dictionary filename: fingerprint, holding only
- existing files
-
- """
- ret = {}
-
- for filename in files:
- cksum = _FingerprintFile(filename)
- if cksum:
- ret[filename] = cksum
-
- return ret
-
-
def ForceDictType(target, key_types, allowed_values=None):
"""Force the values of a dict to have certain types.
@@ -2541,41 +2492,6 @@ def LoadSignedX509Certificate(cert_pem, key):
return (cert, salt)
-def Sha1Hmac(key, text, salt=None):
- """Calculates the HMAC-SHA1 digest of a text.
-
- HMAC is defined in RFC2104.
-
- @type key: string
- @param key: Secret key
- @type text: string
-
- """
- if salt:
- salted_text = salt + text
- else:
- salted_text = text
-
- return hmac.new(key, salted_text, compat.sha1).hexdigest()
-
-
-def VerifySha1Hmac(key, text, digest, salt=None):
- """Verifies the HMAC-SHA1 digest of a text.
-
- HMAC is defined in RFC2104.
-
- @type key: string
- @param key: Secret key
- @type text: string
- @type digest: string
- @param digest: Expected digest
- @rtype: bool
- @return: Whether HMAC-SHA1 digest matches
-
- """
- return digest.lower() == Sha1Hmac(key, text, salt=salt).lower()
-
-
def FindMatch(data, name):
"""Tries to find an item in a dictionary matching a name.
diff --git a/lib/utils/hash.py b/lib/utils/hash.py
new file mode 100644
index 0000000..2358762
--- /dev/null
+++ b/lib/utils/hash.py
@@ -0,0 +1,112 @@
+#
+#
+
+# Copyright (C) 2006, 2007, 2010, 2011 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 hashing.
+
+"""
+
+import os
+import hmac
+
+from ganeti import compat
+
+
+def Sha1Hmac(key, text, salt=None):
+ """Calculates the HMAC-SHA1 digest of a text.
+
+ HMAC is defined in RFC2104.
+
+ @type key: string
+ @param key: Secret key
+ @type text: string
+
+ """
+ if salt:
+ salted_text = salt + text
+ else:
+ salted_text = text
+
+ return hmac.new(key, salted_text, compat.sha1).hexdigest()
+
+
+def VerifySha1Hmac(key, text, digest, salt=None):
+ """Verifies the HMAC-SHA1 digest of a text.
+
+ HMAC is defined in RFC2104.
+
+ @type key: string
+ @param key: Secret key
+ @type text: string
+ @type digest: string
+ @param digest: Expected digest
+ @rtype: bool
+ @return: Whether HMAC-SHA1 digest matches
+
+ """
+ return digest.lower() == Sha1Hmac(key, text, salt=salt).lower()
+
+
+def _FingerprintFile(filename):
+ """Compute the fingerprint of a file.
+
+ If the file does not exist, a None will be returned
+ instead.
+
+ @type filename: str
+ @param filename: the filename to checksum
+ @rtype: str
+ @return: the hex digest of the sha checksum of the contents
+ of the file
+
+ """
+ if not (os.path.exists(filename) and os.path.isfile(filename)):
+ return None
+
+ f = open(filename)
+
+ fp = compat.sha1_hash()
+ while True:
+ data = f.read(4096)
+ if not data:
+ break
+
+ fp.update(data)
+
+ return fp.hexdigest()
+
+
+def FingerprintFiles(files):
+ """Compute fingerprints for a list of files.
+
+ @type files: list
+ @param files: the list of filename to fingerprint
+ @rtype: dict
+ @return: a dictionary filename: fingerprint, holding only
+ existing files
+
+ """
+ ret = {}
+
+ for filename in files:
+ cksum = _FingerprintFile(filename)
+ if cksum:
+ ret[filename] = cksum
+
+ return ret
diff --git a/test/ganeti.utils.hash_unittest.py
b/test/ganeti.utils.hash_unittest.py
new file mode 100755
index 0000000..3095935
--- /dev/null
+++ b/test/ganeti.utils.hash_unittest.py
@@ -0,0 +1,113 @@
+#!/usr/bin/python
+#
+
+# Copyright (C) 2006, 2007, 2010, 2011 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 testing ganeti.utils.hash"""
+
+import unittest
+import random
+import operator
+import tempfile
+
+from ganeti import constants
+from ganeti import utils
+
+import testutils
+
+
+class TestHmacFunctions(unittest.TestCase):
+ # Digests can be checked with "openssl sha1 -hmac $key"
+ def testSha1Hmac(self):
+ self.assertEqual(utils.Sha1Hmac("", ""),
+ "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d")
+ self.assertEqual(utils.Sha1Hmac("3YzMxZWE", "Hello World"),
+ "ef4f3bda82212ecb2f7ce868888a19092481f1fd")
+ self.assertEqual(utils.Sha1Hmac("TguMTA2K", ""),
+ "f904c2476527c6d3e6609ab683c66fa0652cb1dc")
+
+ longtext = 1500 * "The quick brown fox jumps over the lazy dog\n"
+ self.assertEqual(utils.Sha1Hmac("3YzMxZWE", longtext),
+ "35901b9a3001a7cdcf8e0e9d7c2e79df2223af54")
+
+ def testSha1HmacSalt(self):
+ self.assertEqual(utils.Sha1Hmac("TguMTA2K", "", salt="abc0"),
+ "4999bf342470eadb11dfcd24ca5680cf9fd7cdce")
+ self.assertEqual(utils.Sha1Hmac("TguMTA2K", "", salt="abc9"),
+ "17a4adc34d69c0d367d4ffbef96fd41d4df7a6e8")
+ self.assertEqual(utils.Sha1Hmac("3YzMxZWE", "Hello World", salt="xyz0"),
+ "7f264f8114c9066afc9bb7636e1786d996d3cc0d")
+
+ def testVerifySha1Hmac(self):
+ self.assert_(utils.VerifySha1Hmac("", "", ("fbdb1d1b18aa6c08324b"
+ "7d64b71fb76370690e1d")))
+ self.assert_(utils.VerifySha1Hmac("TguMTA2K", "",
+ ("f904c2476527c6d3e660"
+ "9ab683c66fa0652cb1dc")))
+
+ digest = "ef4f3bda82212ecb2f7ce868888a19092481f1fd"
+ self.assert_(utils.VerifySha1Hmac("3YzMxZWE", "Hello World", digest))
+ self.assert_(utils.VerifySha1Hmac("3YzMxZWE", "Hello World",
+ digest.lower()))
+ self.assert_(utils.VerifySha1Hmac("3YzMxZWE", "Hello World",
+ digest.upper()))
+ self.assert_(utils.VerifySha1Hmac("3YzMxZWE", "Hello World",
+ digest.title()))
+
+ def testVerifySha1HmacSalt(self):
+ self.assert_(utils.VerifySha1Hmac("TguMTA2K", "",
+ ("17a4adc34d69c0d367d4"
+ "ffbef96fd41d4df7a6e8"),
+ salt="abc9"))
+ self.assert_(utils.VerifySha1Hmac("3YzMxZWE", "Hello World",
+ ("7f264f8114c9066afc9b"
+ "b7636e1786d996d3cc0d"),
+ salt="xyz0"))
+
+
+class TestFingerprintFiles(unittest.TestCase):
+ def setUp(self):
+ self.tmpfile = tempfile.NamedTemporaryFile()
+ self.tmpfile2 = tempfile.NamedTemporaryFile()
+ utils.WriteFile(self.tmpfile2.name, data="Hello World\n")
+ self.results = {
+ self.tmpfile.name: "da39a3ee5e6b4b0d3255bfef95601890afd80709",
+ self.tmpfile2.name: "648a6a6ffffdaa0badb23b8baf90b6168dd16b3a",
+ }
+
+ def testSingleFile(self):
+ self.assertEqual(utils.hash._FingerprintFile(self.tmpfile.name),
+ self.results[self.tmpfile.name])
+
+ self.assertEqual(utils.hash._FingerprintFile("/no/such/file"), None)
+
+ def testBigFile(self):
+ self.tmpfile.write("A" * 8192)
+ self.tmpfile.flush()
+ self.assertEqual(utils.hash._FingerprintFile(self.tmpfile.name),
+ "35b6795ca20d6dc0aff8c7c110c96cd1070b8c38")
+
+ def testMultiple(self):
+ all_files = self.results.keys()
+ all_files.append("/no/such/file")
+ self.assertEqual(utils.FingerprintFiles(self.results.keys()), self.results)
+
+
+if __name__ == "__main__":
+ testutils.GanetiTestProgram()
diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index 2f8b00c..574edf9 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -1471,34 +1471,6 @@ class RunInSeparateProcess(unittest.TestCase):
utils.RunInSeparateProcess, _exc)
-class TestFingerprintFiles(unittest.TestCase):
- def setUp(self):
- self.tmpfile = tempfile.NamedTemporaryFile()
- self.tmpfile2 = tempfile.NamedTemporaryFile()
- utils.WriteFile(self.tmpfile2.name, data="Hello World\n")
- self.results = {
- self.tmpfile.name: "da39a3ee5e6b4b0d3255bfef95601890afd80709",
- self.tmpfile2.name: "648a6a6ffffdaa0badb23b8baf90b6168dd16b3a",
- }
-
- def testSingleFile(self):
- self.assertEqual(utils._FingerprintFile(self.tmpfile.name),
- self.results[self.tmpfile.name])
-
- self.assertEqual(utils._FingerprintFile("/no/such/file"), None)
-
- def testBigFile(self):
- self.tmpfile.write("A" * 8192)
- self.tmpfile.flush()
- self.assertEqual(utils._FingerprintFile(self.tmpfile.name),
- "35b6795ca20d6dc0aff8c7c110c96cd1070b8c38")
-
- def testMultiple(self):
- all_files = self.results.keys()
- all_files.append("/no/such/file")
- self.assertEqual(utils.FingerprintFiles(self.results.keys()), self.results)
-
-
class TestGenerateSelfSignedX509Cert(unittest.TestCase):
def setUp(self):
self.tmpdir = tempfile.mkdtemp()
@@ -1829,55 +1801,6 @@ class TestVerifyCertificateInner(unittest.TestCase):
self.assertEqual(errcode, utils.CERT_ERROR)
-class TestHmacFunctions(unittest.TestCase):
- # Digests can be checked with "openssl sha1 -hmac $key"
- def testSha1Hmac(self):
- self.assertEqual(utils.Sha1Hmac("", ""),
- "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d")
- self.assertEqual(utils.Sha1Hmac("3YzMxZWE", "Hello World"),
- "ef4f3bda82212ecb2f7ce868888a19092481f1fd")
- self.assertEqual(utils.Sha1Hmac("TguMTA2K", ""),
- "f904c2476527c6d3e6609ab683c66fa0652cb1dc")
-
- longtext = 1500 * "The quick brown fox jumps over the lazy dog\n"
- self.assertEqual(utils.Sha1Hmac("3YzMxZWE", longtext),
- "35901b9a3001a7cdcf8e0e9d7c2e79df2223af54")
-
- def testSha1HmacSalt(self):
- self.assertEqual(utils.Sha1Hmac("TguMTA2K", "", salt="abc0"),
- "4999bf342470eadb11dfcd24ca5680cf9fd7cdce")
- self.assertEqual(utils.Sha1Hmac("TguMTA2K", "", salt="abc9"),
- "17a4adc34d69c0d367d4ffbef96fd41d4df7a6e8")
- self.assertEqual(utils.Sha1Hmac("3YzMxZWE", "Hello World", salt="xyz0"),
- "7f264f8114c9066afc9bb7636e1786d996d3cc0d")
-
- def testVerifySha1Hmac(self):
- self.assert_(utils.VerifySha1Hmac("", "", ("fbdb1d1b18aa6c08324b"
- "7d64b71fb76370690e1d")))
- self.assert_(utils.VerifySha1Hmac("TguMTA2K", "",
- ("f904c2476527c6d3e660"
- "9ab683c66fa0652cb1dc")))
-
- digest = "ef4f3bda82212ecb2f7ce868888a19092481f1fd"
- self.assert_(utils.VerifySha1Hmac("3YzMxZWE", "Hello World", digest))
- self.assert_(utils.VerifySha1Hmac("3YzMxZWE", "Hello World",
- digest.lower()))
- self.assert_(utils.VerifySha1Hmac("3YzMxZWE", "Hello World",
- digest.upper()))
- self.assert_(utils.VerifySha1Hmac("3YzMxZWE", "Hello World",
- digest.title()))
-
- def testVerifySha1HmacSalt(self):
- self.assert_(utils.VerifySha1Hmac("TguMTA2K", "",
- ("17a4adc34d69c0d367d4"
- "ffbef96fd41d4df7a6e8"),
- salt="abc9"))
- self.assert_(utils.VerifySha1Hmac("3YzMxZWE", "Hello World",
- ("7f264f8114c9066afc9b"
- "b7636e1786d996d3cc0d"),
- salt="xyz0"))
-
-
class TestIgnoreSignals(unittest.TestCase):
"""Test the IgnoreSignals decorator"""
--
1.7.3.1