diff --git a/htest/Test/Ganeti/Utils.hs b/htest/Test/Ganeti/Utils.hs index 461d1b27eb959852aea3af82d60d6440e92a0937..cb357a14cd9632675d4923a28007e8c8c18cd0db 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 9f7e9c579cce17d98f25fbe5ac26464ab005b5d9..eed65dd59faca26c302a795964772fa4dd937090 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 900b4bc476636a96e538008a8c555f47a708ccba..2d106f193f7d601f62a9df69987bd1e4da18fdd5 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 ab7225ff69ac60bf0f1d7cba0d7c7b6519f5d3a8..69cc0a3f9852accb5d975e4ecadc0af0386c2478 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 bb0a1237c5a5e95999c042f818027369eaaace2c..f9675a8478e0660f5f11b2f9bf50e9b898550a8b 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):