From 80a0546be9633c6f41a62dc224456d4aecab6a66 Mon Sep 17 00:00:00 2001
From: Michele Tartara <mtartara@google.com>
Date: Thu, 20 Dec 2012 09:03:15 +0000
Subject: [PATCH] Add function for generating UUIDs in the Haskell codebase

Its first use will be to generate the salt for ConfD requests of the Haskell
client, as in the Python client.

Unit test added as well.

Signed-off-by: Michele Tartara <mtartara@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 htest/Test/Ganeti/Utils.hs | 17 ++++++++++++++++-
 htools/Ganeti/Utils.hs     | 10 ++++++++++
 lib/constants.py           |  6 ++++++
 lib/utils/__init__.py      |  3 +--
 lib/utils/io.py            |  6 +-----
 5 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/htest/Test/Ganeti/Utils.hs b/htest/Test/Ganeti/Utils.hs
index 461d1b27e..cb357a14c 100644
--- a/htest/Test/Ganeti/Utils.hs
+++ b/htest/Test/Ganeti/Utils.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TemplateHaskell, CPP #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 {-| Unittests for ganeti-htools.
@@ -34,11 +34,15 @@ import Test.HUnit
 import Data.Char (isSpace)
 import Data.List
 import qualified Text.JSON as J
+#ifndef NO_REGEX_PCRE
+import Text.Regex.PCRE
+#endif
 
 import Test.Ganeti.TestHelper
 import Test.Ganeti.TestCommon
 
 import Ganeti.BasicTypes
+import qualified Ganeti.Constants as C
 import qualified Ganeti.JSON as JSON
 import Ganeti.Utils
 
@@ -219,6 +223,14 @@ prop_rStripSpace (NonEmpty str) =
               rStripSpace "" ==? ""
           ]
 
+#ifndef NO_REGEX_PCRE
+-- | Tests that the newUUID function produces valid UUIDs.
+case_new_uuid :: Assertion
+case_new_uuid = do
+  uuid <- newUUID
+  assertBool "newUUID" $ uuid =~ C.uuidRegex
+#endif
+
 -- | Test list for the Utils module.
 testSuite "Utils"
             [ 'prop_commaJoinSplit
@@ -235,4 +247,7 @@ testSuite "Utils"
             , 'prop_niceSort_numbers
             , 'prop_niceSortKey_equiv
             , 'prop_rStripSpace
+#ifndef NO_REGEX_PCRE
+            , 'case_new_uuid
+#endif
             ]
diff --git a/htools/Ganeti/Utils.hs b/htools/Ganeti/Utils.hs
index 9f7e9c579..eed65dd59 100644
--- a/htools/Ganeti/Utils.hs
+++ b/htools/Ganeti/Utils.hs
@@ -44,6 +44,7 @@ module Ganeti.Utils
   , exitWhen
   , exitUnless
   , rStripSpace
+  , newUUID
   ) where
 
 import Data.Char (toUpper, isAlphaNum, isDigit, isSpace)
@@ -53,6 +54,7 @@ import Data.List
 import Debug.Trace
 
 import Ganeti.BasicTypes
+import qualified Ganeti.Constants as C
 import System.IO
 import System.Exit
 
@@ -277,3 +279,11 @@ niceSortKey keyfn =
 -- expensive, should only be run on small strings.
 rStripSpace :: String -> String
 rStripSpace = reverse . dropWhile isSpace . reverse
+
+-- | Returns a random UUID.
+-- This is a Linux-specific method as it uses the /proc filesystem.
+newUUID :: IO String
+newUUID = do
+  contents <- readFile C.randomUuidFile
+  let stripNewlines = reverse . dropWhile (=='\n') . reverse
+  return $! stripNewlines $ take 128 contents
diff --git a/lib/constants.py b/lib/constants.py
index 900b4bc47..2d106f193 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -2210,5 +2210,11 @@ NDS_NODE_DAEMON_CERTIFICATE = "node_daemon_certificate"
 NDS_SSCONF = "ssconf"
 NDS_START_NODE_DAEMON = "start_node_daemon"
 
+# Path generating random UUID
+RANDOM_UUID_FILE = "/proc/sys/kernel/random/uuid"
+
+# Regex string for verifying a UUID
+UUID_REGEX = "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$"
+
 # Do not re-export imported modules
 del re, _vcsversion, _autoconf, socket, pathutils, compat
diff --git a/lib/utils/__init__.py b/lib/utils/__init__.py
index ab7225ff6..69cc0a3f9 100644
--- a/lib/utils/__init__.py
+++ b/lib/utils/__init__.py
@@ -59,8 +59,7 @@ from ganeti.utils.x509 import *
 
 _VALID_SERVICE_NAME_RE = re.compile("^[-_.a-zA-Z0-9]{1,128}$")
 
-UUID_RE = re.compile("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-"
-                     "[a-f0-9]{4}-[a-f0-9]{12}$")
+UUID_RE = re.compile(constants.UUID_REGEX)
 
 
 def ForceDictType(target, key_types, allowed_values=None):
diff --git a/lib/utils/io.py b/lib/utils/io.py
index bb0a1237c..f9675a847 100644
--- a/lib/utils/io.py
+++ b/lib/utils/io.py
@@ -35,10 +35,6 @@ from ganeti import constants
 from ganeti import pathutils
 from ganeti.utils import filelock
 
-
-#: Path generating random UUID
-_RANDOM_UUID_FILE = "/proc/sys/kernel/random/uuid"
-
 #: Directory used by fsck(8) to store recovered data, usually at a file
 #: system's root directory
 _LOST_AND_FOUND = "lost+found"
@@ -1029,7 +1025,7 @@ def NewUUID():
   @rtype: str
 
   """
-  return ReadFile(_RANDOM_UUID_FILE, size=128).rstrip("\n")
+  return ReadFile(constants.RANDOM_UUID_FILE, size=128).rstrip("\n")
 
 
 class TemporaryFileManager(object):
-- 
GitLab