commit 26d62e4ced78ba5f3fea05583dae54b1324ed33a
Author: Iustin Pop <iustin@google.com>
Date:   Thu Oct 4 22:39:29 2012 +0100

    Rename Ganeti/HTools/Utils.hs to Ganeti/Utils.hs
    
    This is, I believe, the last non-htools specific file that still lived
    in the htools directory; it's already widely used in non-htools code,
    so let's move it before we add more functionality to this module.
    
    All changes are related to the name change, imports fixup, etc.; there
    are no other changes in this patch.
    
    Signed-off-by: Iustin Pop <iustin@google.com>
    Reviewed-by: Michael Hanselmann <hansmi@google.com>

diff --git a/Makefile.am b/Makefile.am
index 9d39232..c199d6b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -421,7 +421,6 @@ HS_LIB_SRCS = \
 	htools/Ganeti/HTools/Simu.hs \
 	htools/Ganeti/HTools/Text.hs \
 	htools/Ganeti/HTools/Types.hs \
-	htools/Ganeti/HTools/Utils.hs \
 	htools/Ganeti/HTools/Program.hs \
 	htools/Ganeti/HTools/Program/Hail.hs \
 	htools/Ganeti/HTools/Program/Hbal.hs \
@@ -456,7 +455,8 @@ HS_LIB_SRCS = \
 	htools/Ganeti/Rpc.hs \
 	htools/Ganeti/Runtime.hs \
 	htools/Ganeti/Ssconf.hs \
-	htools/Ganeti/THH.hs
+	htools/Ganeti/THH.hs \
+	htools/Ganeti/Utils.hs
 
 HS_TEST_SRCS = \
 	htest/Test/Ganeti/BasicTypes.hs \
@@ -473,7 +473,6 @@ HS_TEST_SRCS = \
 	htest/Test/Ganeti/HTools/Simu.hs \
 	htest/Test/Ganeti/HTools/Text.hs \
 	htest/Test/Ganeti/HTools/Types.hs \
-	htest/Test/Ganeti/HTools/Utils.hs \
 	htest/Test/Ganeti/JSON.hs \
 	htest/Test/Ganeti/Jobs.hs \
 	htest/Test/Ganeti/Luxi.hs \
@@ -486,7 +485,8 @@ HS_TEST_SRCS = \
 	htest/Test/Ganeti/Ssconf.hs \
 	htest/Test/Ganeti/TestCommon.hs \
 	htest/Test/Ganeti/TestHTools.hs \
-	htest/Test/Ganeti/TestHelper.hs
+	htest/Test/Ganeti/TestHelper.hs \
+	htest/Test/Ganeti/Utils.hs
 
 HS_LIBTEST_SRCS = $(HS_LIB_SRCS) $(HS_TEST_SRCS)
 
diff --git a/htest/Test/Ganeti/HTools/Text.hs b/htest/Test/Ganeti/HTools/Text.hs
index c1c23c5..d64cb17 100644
--- a/htest/Test/Ganeti/HTools/Text.hs
+++ b/htest/Test/Ganeti/HTools/Text.hs
@@ -48,7 +48,7 @@ import qualified Ganeti.HTools.Loader as Loader
 import qualified Ganeti.HTools.Node as Node
 import qualified Ganeti.HTools.Text as Text
 import qualified Ganeti.HTools.Types as Types
-import qualified Ganeti.HTools.Utils as Utils
+import qualified Ganeti.Utils as Utils
 
 -- * Instance text loader tests
 
diff --git a/htest/Test/Ganeti/HTools/Utils.hs b/htest/Test/Ganeti/HTools/Utils.hs
deleted file mode 100644
index abb3e32..0000000
--- a/htest/Test/Ganeti/HTools/Utils.hs
+++ /dev/null
@@ -1,132 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-
-{-| Unittests for ganeti-htools.
-
--}
-
-{-
-
-Copyright (C) 2009, 2010, 2011, 2012 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.
-
--}
-
-module Test.Ganeti.HTools.Utils (testHTools_Utils) where
-
-import Test.QuickCheck
-
-import qualified Text.JSON as J
-
-import Test.Ganeti.TestHelper
-import Test.Ganeti.TestCommon
-
-import qualified Ganeti.JSON as JSON
-import qualified Ganeti.HTools.Types as Types
-import qualified Ganeti.HTools.Utils as Utils
-
--- | Helper to generate a small string that doesn't contain commas.
-genNonCommaString :: Gen String
-genNonCommaString = do
-  size <- choose (0, 20) -- arbitrary max size
-  vectorOf size (arbitrary `suchThat` (/=) ',')
-
--- | If the list is not just an empty element, and if the elements do
--- not contain commas, then join+split should be idempotent.
-prop_commaJoinSplit :: Property
-prop_commaJoinSplit =
-  forAll (choose (0, 20)) $ \llen ->
-  forAll (vectorOf llen genNonCommaString `suchThat` (/=) [""]) $ \lst ->
-  Utils.sepSplit ',' (Utils.commaJoin lst) ==? lst
-
--- | Split and join should always be idempotent.
-prop_commaSplitJoin :: String -> Property
-prop_commaSplitJoin s =
-  Utils.commaJoin (Utils.sepSplit ',' s) ==? s
-
--- | fromObjWithDefault, we test using the Maybe monad and an integer
--- value.
-prop_fromObjWithDefault :: Integer -> String -> Bool
-prop_fromObjWithDefault def_value random_key =
-  -- a missing key will be returned with the default
-  JSON.fromObjWithDefault [] random_key def_value == Just def_value &&
-  -- a found key will be returned as is, not with default
-  JSON.fromObjWithDefault [(random_key, J.showJSON def_value)]
-       random_key (def_value+1) == Just def_value
-
--- | Test that functional if' behaves like the syntactic sugar if.
-prop_if'if :: Bool -> Int -> Int -> Gen Prop
-prop_if'if cnd a b =
-  Utils.if' cnd a b ==? if cnd then a else b
-
--- | Test basic select functionality
-prop_select :: Int      -- ^ Default result
-            -> [Int]    -- ^ List of False values
-            -> [Int]    -- ^ List of True values
-            -> Gen Prop -- ^ Test result
-prop_select def lst1 lst2 =
-  Utils.select def (flist ++ tlist) ==? expectedresult
-    where expectedresult = Utils.if' (null lst2) def (head lst2)
-          flist = zip (repeat False) lst1
-          tlist = zip (repeat True)  lst2
-
--- | Test basic select functionality with undefined default
-prop_select_undefd :: [Int]            -- ^ List of False values
-                   -> NonEmptyList Int -- ^ List of True values
-                   -> Gen Prop         -- ^ Test result
-prop_select_undefd lst1 (NonEmpty lst2) =
-  Utils.select undefined (flist ++ tlist) ==? head lst2
-    where flist = zip (repeat False) lst1
-          tlist = zip (repeat True)  lst2
-
--- | Test basic select functionality with undefined list values
-prop_select_undefv :: [Int]            -- ^ List of False values
-                   -> NonEmptyList Int -- ^ List of True values
-                   -> Gen Prop         -- ^ Test result
-prop_select_undefv lst1 (NonEmpty lst2) =
-  Utils.select undefined cndlist ==? head lst2
-    where flist = zip (repeat False) lst1
-          tlist = zip (repeat True)  lst2
-          cndlist = flist ++ tlist ++ [undefined]
-
-prop_parseUnit :: NonNegative Int -> Property
-prop_parseUnit (NonNegative n) =
-  Utils.parseUnit (show n) ==? Types.Ok n .&&.
-  Utils.parseUnit (show n ++ "m") ==? Types.Ok n .&&.
-  Utils.parseUnit (show n ++ "M") ==? Types.Ok (truncate n_mb::Int) .&&.
-  Utils.parseUnit (show n ++ "g") ==? Types.Ok (n*1024) .&&.
-  Utils.parseUnit (show n ++ "G") ==? Types.Ok (truncate n_gb::Int) .&&.
-  Utils.parseUnit (show n ++ "t") ==? Types.Ok (n*1048576) .&&.
-  Utils.parseUnit (show n ++ "T") ==? Types.Ok (truncate n_tb::Int) .&&.
-  printTestCase "Internal error/overflow?"
-    (n_mb >=0 && n_gb >= 0 && n_tb >= 0) .&&.
-  property (Types.isBad (Utils.parseUnit (show n ++ "x")::Types.Result Int))
-  where n_mb = (fromIntegral n::Rational) * 1000 * 1000 / 1024 / 1024
-        n_gb = n_mb * 1000
-        n_tb = n_gb * 1000
-
--- | Test list for the Utils module.
-testSuite "HTools/Utils"
-            [ 'prop_commaJoinSplit
-            , 'prop_commaSplitJoin
-            , 'prop_fromObjWithDefault
-            , 'prop_if'if
-            , 'prop_select
-            , 'prop_select_undefd
-            , 'prop_select_undefv
-            , 'prop_parseUnit
-            ]
diff --git a/htest/Test/Ganeti/Utils.hs b/htest/Test/Ganeti/Utils.hs
new file mode 100644
index 0000000..e2ce7d7
--- /dev/null
+++ b/htest/Test/Ganeti/Utils.hs
@@ -0,0 +1,132 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+{-| Unittests for ganeti-htools.
+
+-}
+
+{-
+
+Copyright (C) 2009, 2010, 2011, 2012 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.
+
+-}
+
+module Test.Ganeti.Utils (testUtils) where
+
+import Test.QuickCheck
+
+import qualified Text.JSON as J
+
+import Test.Ganeti.TestHelper
+import Test.Ganeti.TestCommon
+
+import qualified Ganeti.JSON as JSON
+import qualified Ganeti.HTools.Types as Types
+import qualified Ganeti.Utils as Utils
+
+-- | Helper to generate a small string that doesn't contain commas.
+genNonCommaString :: Gen String
+genNonCommaString = do
+  size <- choose (0, 20) -- arbitrary max size
+  vectorOf size (arbitrary `suchThat` (/=) ',')
+
+-- | If the list is not just an empty element, and if the elements do
+-- not contain commas, then join+split should be idempotent.
+prop_commaJoinSplit :: Property
+prop_commaJoinSplit =
+  forAll (choose (0, 20)) $ \llen ->
+  forAll (vectorOf llen genNonCommaString `suchThat` (/=) [""]) $ \lst ->
+  Utils.sepSplit ',' (Utils.commaJoin lst) ==? lst
+
+-- | Split and join should always be idempotent.
+prop_commaSplitJoin :: String -> Property
+prop_commaSplitJoin s =
+  Utils.commaJoin (Utils.sepSplit ',' s) ==? s
+
+-- | fromObjWithDefault, we test using the Maybe monad and an integer
+-- value.
+prop_fromObjWithDefault :: Integer -> String -> Bool
+prop_fromObjWithDefault def_value random_key =
+  -- a missing key will be returned with the default
+  JSON.fromObjWithDefault [] random_key def_value == Just def_value &&
+  -- a found key will be returned as is, not with default
+  JSON.fromObjWithDefault [(random_key, J.showJSON def_value)]
+       random_key (def_value+1) == Just def_value
+
+-- | Test that functional if' behaves like the syntactic sugar if.
+prop_if'if :: Bool -> Int -> Int -> Gen Prop
+prop_if'if cnd a b =
+  Utils.if' cnd a b ==? if cnd then a else b
+
+-- | Test basic select functionality
+prop_select :: Int      -- ^ Default result
+            -> [Int]    -- ^ List of False values
+            -> [Int]    -- ^ List of True values
+            -> Gen Prop -- ^ Test result
+prop_select def lst1 lst2 =
+  Utils.select def (flist ++ tlist) ==? expectedresult
+    where expectedresult = Utils.if' (null lst2) def (head lst2)
+          flist = zip (repeat False) lst1
+          tlist = zip (repeat True)  lst2
+
+-- | Test basic select functionality with undefined default
+prop_select_undefd :: [Int]            -- ^ List of False values
+                   -> NonEmptyList Int -- ^ List of True values
+                   -> Gen Prop         -- ^ Test result
+prop_select_undefd lst1 (NonEmpty lst2) =
+  Utils.select undefined (flist ++ tlist) ==? head lst2
+    where flist = zip (repeat False) lst1
+          tlist = zip (repeat True)  lst2
+
+-- | Test basic select functionality with undefined list values
+prop_select_undefv :: [Int]            -- ^ List of False values
+                   -> NonEmptyList Int -- ^ List of True values
+                   -> Gen Prop         -- ^ Test result
+prop_select_undefv lst1 (NonEmpty lst2) =
+  Utils.select undefined cndlist ==? head lst2
+    where flist = zip (repeat False) lst1
+          tlist = zip (repeat True)  lst2
+          cndlist = flist ++ tlist ++ [undefined]
+
+prop_parseUnit :: NonNegative Int -> Property
+prop_parseUnit (NonNegative n) =
+  Utils.parseUnit (show n) ==? Types.Ok n .&&.
+  Utils.parseUnit (show n ++ "m") ==? Types.Ok n .&&.
+  Utils.parseUnit (show n ++ "M") ==? Types.Ok (truncate n_mb::Int) .&&.
+  Utils.parseUnit (show n ++ "g") ==? Types.Ok (n*1024) .&&.
+  Utils.parseUnit (show n ++ "G") ==? Types.Ok (truncate n_gb::Int) .&&.
+  Utils.parseUnit (show n ++ "t") ==? Types.Ok (n*1048576) .&&.
+  Utils.parseUnit (show n ++ "T") ==? Types.Ok (truncate n_tb::Int) .&&.
+  printTestCase "Internal error/overflow?"
+    (n_mb >=0 && n_gb >= 0 && n_tb >= 0) .&&.
+  property (Types.isBad (Utils.parseUnit (show n ++ "x")::Types.Result Int))
+  where n_mb = (fromIntegral n::Rational) * 1000 * 1000 / 1024 / 1024
+        n_gb = n_mb * 1000
+        n_tb = n_gb * 1000
+
+-- | Test list for the Utils module.
+testSuite "Utils"
+            [ 'prop_commaJoinSplit
+            , 'prop_commaSplitJoin
+            , 'prop_fromObjWithDefault
+            , 'prop_if'if
+            , 'prop_select
+            , 'prop_select_undefd
+            , 'prop_select_undefv
+            , 'prop_parseUnit
+            ]
diff --git a/htest/test.hs b/htest/test.hs
index 9e00d36..9100095 100644
--- a/htest/test.hs
+++ b/htest/test.hs
@@ -44,7 +44,6 @@ import Test.Ganeti.HTools.PeerMap
 import Test.Ganeti.HTools.Simu
 import Test.Ganeti.HTools.Text
 import Test.Ganeti.HTools.Types
-import Test.Ganeti.HTools.Utils
 import Test.Ganeti.Jobs
 import Test.Ganeti.JSON
 import Test.Ganeti.Luxi
@@ -55,6 +54,7 @@ import Test.Ganeti.Query.Language
 import Test.Ganeti.Query.Query
 import Test.Ganeti.Rpc
 import Test.Ganeti.Ssconf
+import Test.Ganeti.Utils
 
 -- | Our default test options, overring the built-in test-framework
 -- ones (but not the supplied command line parameters).
@@ -85,7 +85,6 @@ allTests =
   , testHTools_Simu
   , testHTools_Text
   , testHTools_Types
-  , testHTools_Utils
   , testJSON
   , testJobs
   , testLuxi
@@ -96,6 +95,7 @@ allTests =
   , testQuery_Query
   , testRpc
   , testSsconf
+  , testUtils
   ]
 
 -- | Main function. Note we don't use defaultMain since we want to
diff --git a/htools/Ganeti/Confd/Server.hs b/htools/Ganeti/Confd/Server.hs
index b14eb43..5644f11 100644
--- a/htools/Ganeti/Confd/Server.hs
+++ b/htools/Ganeti/Confd/Server.hs
@@ -47,13 +47,13 @@ import System.INotify
 import Ganeti.Daemon
 import Ganeti.JSON
 import Ganeti.HTools.Types
-import Ganeti.HTools.Utils
 import Ganeti.Objects
 import Ganeti.Confd
 import Ganeti.Confd.Utils
 import Ganeti.Config
 import Ganeti.Hash
 import Ganeti.Logging
+import Ganeti.Utils
 import qualified Ganeti.Constants as C
 import qualified Ganeti.Path as Path
 import Ganeti.Query.Server (runQueryD)
diff --git a/htools/Ganeti/Confd/Utils.hs b/htools/Ganeti/Confd/Utils.hs
index 043ded0..01c7ee7 100644
--- a/htools/Ganeti/Confd/Utils.hs
+++ b/htools/Ganeti/Confd/Utils.hs
@@ -42,7 +42,7 @@ import Ganeti.Hash
 import qualified Ganeti.Constants as C
 import qualified Ganeti.Path as Path
 import Ganeti.JSON
-import Ganeti.HTools.Utils
+import Ganeti.Utils
 
 -- | Returns the HMAC key.
 getClusterHmac :: IO HashKey
diff --git a/htools/Ganeti/Daemon.hs b/htools/Ganeti/Daemon.hs
index 2b715b5..1a53086 100644
--- a/htools/Ganeti/Daemon.hs
+++ b/htools/Ganeti/Daemon.hs
@@ -65,7 +65,7 @@ import Ganeti.Common as Common
 import Ganeti.Logging
 import Ganeti.Runtime
 import Ganeti.BasicTypes
-import Ganeti.HTools.Utils
+import Ganeti.Utils
 import qualified Ganeti.Constants as C
 import qualified Ganeti.Ssconf as Ssconf
 
diff --git a/htools/Ganeti/HTools/CLI.hs b/htools/Ganeti/HTools/CLI.hs
index fee8df8..67b51a1 100644
--- a/htools/Ganeti/HTools/CLI.hs
+++ b/htools/Ganeti/HTools/CLI.hs
@@ -1,7 +1,7 @@
 {-| Implementation of command-line functions.
 
 This module holds the common command-line related functions for the
-binaries, separated into this module since "Ganeti.HTools.Utils" is
+binaries, separated into this module since "Ganeti.Utils" is
 used in many other places and this is more IO oriented.
 
 -}
@@ -95,9 +95,9 @@ import qualified Ganeti.HTools.Container as Container
 import qualified Ganeti.HTools.Node as Node
 import qualified Ganeti.Path as Path
 import Ganeti.HTools.Types
-import Ganeti.HTools.Utils
 import Ganeti.BasicTypes
 import Ganeti.Common as Common
+import Ganeti.Utils
 
 -- * Data types
 
diff --git a/htools/Ganeti/HTools/Cluster.hs b/htools/Ganeti/HTools/Cluster.hs
index deb56dd..b36b5de 100644
--- a/htools/Ganeti/HTools/Cluster.hs
+++ b/htools/Ganeti/HTools/Cluster.hs
@@ -86,9 +86,9 @@ import qualified Ganeti.HTools.Instance as Instance
 import qualified Ganeti.HTools.Node as Node
 import qualified Ganeti.HTools.Group as Group
 import Ganeti.HTools.Types
-import Ganeti.HTools.Utils
 import Ganeti.Compat
 import qualified Ganeti.OpCodes as OpCodes
+import Ganeti.Utils
 
 -- * Types
 
diff --git a/htools/Ganeti/HTools/ExtLoader.hs b/htools/Ganeti/HTools/ExtLoader.hs
index 797a66f..2ecd100 100644
--- a/htools/Ganeti/HTools/ExtLoader.hs
+++ b/htools/Ganeti/HTools/ExtLoader.hs
@@ -51,7 +51,7 @@ import Ganeti.HTools.Loader (mergeData, checkData, ClusterData(..)
 
 import Ganeti.HTools.Types
 import Ganeti.HTools.CLI
-import Ganeti.HTools.Utils (sepSplit, tryRead, exitIfBad, exitWhen)
+import Ganeti.Utils (sepSplit, tryRead, exitIfBad, exitWhen)
 
 -- | Error beautifier.
 wrapIO :: IO (Result a) -> IO (Result a)
diff --git a/htools/Ganeti/HTools/Instance.hs b/htools/Ganeti/HTools/Instance.hs
index 9d13556..62803ff 100644
--- a/htools/Ganeti/HTools/Instance.hs
+++ b/htools/Ganeti/HTools/Instance.hs
@@ -60,7 +60,7 @@ module Ganeti.HTools.Instance
 import qualified Ganeti.HTools.Types as T
 import qualified Ganeti.HTools.Container as Container
 
-import Ganeti.HTools.Utils
+import Ganeti.Utils
 
 -- * Type declarations
 
diff --git a/htools/Ganeti/HTools/Loader.hs b/htools/Ganeti/HTools/Loader.hs
index 71893e3..9acf96d 100644
--- a/htools/Ganeti/HTools/Loader.hs
+++ b/htools/Ganeti/HTools/Loader.hs
@@ -52,7 +52,7 @@ import qualified Ganeti.HTools.Cluster as Cluster
 
 import Ganeti.BasicTypes
 import Ganeti.HTools.Types
-import Ganeti.HTools.Utils
+import Ganeti.Utils
 
 -- * Constants
 
diff --git a/htools/Ganeti/HTools/Program/Hbal.hs b/htools/Ganeti/HTools/Program/Hbal.hs
index dc103d3..90a056e 100644
--- a/htools/Ganeti/HTools/Program/Hbal.hs
+++ b/htools/Ganeti/HTools/Program/Hbal.hs
@@ -50,9 +50,9 @@ import qualified Ganeti.HTools.Instance as Instance
 
 import Ganeti.HTools.CLI
 import Ganeti.HTools.ExtLoader
-import Ganeti.HTools.Utils
 import Ganeti.HTools.Types
 import Ganeti.HTools.Loader
+import Ganeti.Utils
 
 import qualified Ganeti.Luxi as L
 import Ganeti.Jobs
diff --git a/htools/Ganeti/HTools/Program/Hinfo.hs b/htools/Ganeti/HTools/Program/Hinfo.hs
index 37f5bba..2c5200e 100644
--- a/htools/Ganeti/HTools/Program/Hinfo.hs
+++ b/htools/Ganeti/HTools/Program/Hinfo.hs
@@ -38,10 +38,10 @@ import qualified Ganeti.HTools.Node as Node
 import qualified Ganeti.HTools.Group as Group
 import qualified Ganeti.HTools.Instance as Instance
 
-import Ganeti.HTools.Utils
 import Ganeti.HTools.CLI
 import Ganeti.HTools.ExtLoader
 import Ganeti.HTools.Loader
+import Ganeti.Utils
 
 -- | Options list and functions.
 options :: [OptType]
diff --git a/htools/Ganeti/HTools/Program/Hspace.hs b/htools/Ganeti/HTools/Program/Hspace.hs
index 960d4fd..605b4ff 100644
--- a/htools/Ganeti/HTools/Program/Hspace.hs
+++ b/htools/Ganeti/HTools/Program/Hspace.hs
@@ -40,11 +40,11 @@ import qualified Ganeti.HTools.Cluster as Cluster
 import qualified Ganeti.HTools.Node as Node
 import qualified Ganeti.HTools.Instance as Instance
 
-import Ganeti.HTools.Utils
 import Ganeti.HTools.Types
 import Ganeti.HTools.CLI
 import Ganeti.HTools.ExtLoader
 import Ganeti.HTools.Loader
+import Ganeti.Utils
 
 -- | Options list and functions.
 options :: [OptType]
diff --git a/htools/Ganeti/HTools/Simu.hs b/htools/Ganeti/HTools/Simu.hs
index ec8b8b6..2e61ed7 100644
--- a/htools/Ganeti/HTools/Simu.hs
+++ b/htools/Ganeti/HTools/Simu.hs
@@ -33,7 +33,7 @@ module Ganeti.HTools.Simu
 import Control.Monad (mplus, zipWithM)
 import Text.Printf (printf)
 
-import Ganeti.HTools.Utils
+import Ganeti.Utils
 import Ganeti.HTools.Types
 import Ganeti.HTools.Loader
 import qualified Ganeti.HTools.Container as Container
diff --git a/htools/Ganeti/HTools/Text.hs b/htools/Ganeti/HTools/Text.hs
index 39a568c..3731bcc 100644
--- a/htools/Ganeti/HTools/Text.hs
+++ b/htools/Ganeti/HTools/Text.hs
@@ -47,7 +47,7 @@ import Data.List
 
 import Text.Printf (printf)
 
-import Ganeti.HTools.Utils
+import Ganeti.Utils
 import Ganeti.HTools.Loader
 import Ganeti.HTools.Types
 import qualified Ganeti.HTools.Container as Container
diff --git a/htools/Ganeti/HTools/Utils.hs b/htools/Ganeti/HTools/Utils.hs
deleted file mode 100644
index 0efe7fe..0000000
--- a/htools/Ganeti/HTools/Utils.hs
+++ /dev/null
@@ -1,232 +0,0 @@
-{-| Utility functions. -}
-
-{-
-
-Copyright (C) 2009, 2010, 2011, 2012 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.
-
--}
-
-module Ganeti.HTools.Utils
-  ( debug
-  , debugFn
-  , debugXy
-  , sepSplit
-  , stdDev
-  , if'
-  , select
-  , applyIf
-  , commaJoin
-  , ensureQuoted
-  , tryRead
-  , formatTable
-  , printTable
-  , parseUnit
-  , plural
-  , exitIfBad
-  , exitErr
-  , exitWhen
-  , exitUnless
-  ) where
-
-import Data.Char (toUpper, isAlphaNum)
-import Data.List
-
-import Debug.Trace
-
-import Ganeti.BasicTypes
-import System.IO
-import System.Exit
-
--- * Debug functions
-
--- | To be used only for debugging, breaks referential integrity.
-debug :: Show a => a -> a
-debug x = trace (show x) x
-
--- | Displays a modified form of the second parameter before returning
--- it.
-debugFn :: Show b => (a -> b) -> a -> a
-debugFn fn x = debug (fn x) `seq` x
-
--- | Show the first parameter before returning the second one.
-debugXy :: Show a => a -> b -> b
-debugXy = seq . debug
-
--- * Miscellaneous
-
--- | Apply the function if condition holds, otherwise use default value.
-applyIf :: Bool -> (a -> a) -> a -> a
-applyIf b f x = if b then f x else x
-
--- | Comma-join a string list.
-commaJoin :: [String] -> String
-commaJoin = intercalate ","
-
--- | Split a list on a separator and return an array.
-sepSplit :: Eq a => a -> [a] -> [[a]]
-sepSplit sep s
-  | null s    = []
-  | null xs   = [x]
-  | null ys   = [x,[]]
-  | otherwise = x:sepSplit sep ys
-  where (x, xs) = break (== sep) s
-        ys = drop 1 xs
-
--- | Simple pluralize helper
-plural :: Int -> String -> String -> String
-plural 1 s _ = s
-plural _ _ p = p
-
--- | Ensure a value is quoted if needed.
-ensureQuoted :: String -> String
-ensureQuoted v = if not (all (\c -> isAlphaNum c || c == '.') v)
-                 then '\'':v ++ "'"
-                 else v
-
--- * Mathematical functions
-
--- Simple and slow statistical functions, please replace with better
--- versions
-
--- | Standard deviation function.
-stdDev :: [Double] -> Double
-stdDev lst =
-  -- first, calculate the list length and sum lst in a single step,
-  -- for performance reasons
-  let (ll', sx) = foldl' (\(rl, rs) e ->
-                           let rl' = rl + 1
-                               rs' = rs + e
-                           in rl' `seq` rs' `seq` (rl', rs')) (0::Int, 0) lst
-      ll = fromIntegral ll'::Double
-      mv = sx / ll
-      av = foldl' (\accu em -> let d = em - mv in accu + d * d) 0.0 lst
-  in sqrt (av / ll) -- stddev
-
--- *  Logical functions
-
--- Avoid syntactic sugar and enhance readability. These functions are proposed
--- by some for inclusion in the Prelude, and at the moment they are present
--- (with various definitions) in the utility-ht package. Some rationale and
--- discussion is available at <http://www.haskell.org/haskellwiki/If-then-else>
-
--- | \"if\" as a function, rather than as syntactic sugar.
-if' :: Bool -- ^ condition
-    -> a    -- ^ \"then\" result
-    -> a    -- ^ \"else\" result
-    -> a    -- ^ \"then\" or "else" result depending on the condition
-if' True x _ = x
-if' _    _ y = y
-
--- * Parsing utility functions
-
--- | Parse results from readsPrec.
-parseChoices :: (Monad m, Read a) => String -> String -> [(a, String)] -> m a
-parseChoices _ _ ((v, ""):[]) = return v
-parseChoices name s ((_, e):[]) =
-    fail $ name ++ ": leftover characters when parsing '"
-           ++ s ++ "': '" ++ e ++ "'"
-parseChoices name s _ = fail $ name ++ ": cannot parse string '" ++ s ++ "'"
-
--- | Safe 'read' function returning data encapsulated in a Result.
-tryRead :: (Monad m, Read a) => String -> String -> m a
-tryRead name s = parseChoices name s $ reads s
-
--- | Format a table of strings to maintain consistent length.
-formatTable :: [[String]] -> [Bool] -> [[String]]
-formatTable vals numpos =
-    let vtrans = transpose vals  -- transpose, so that we work on rows
-                                 -- rather than columns
-        mlens = map (maximum . map length) vtrans
-        expnd = map (\(flds, isnum, ml) ->
-                         map (\val ->
-                                  let delta = ml - length val
-                                      filler = replicate delta ' '
-                                  in if delta > 0
-                                     then if isnum
-                                          then filler ++ val
-                                          else val ++ filler
-                                     else val
-                             ) flds
-                    ) (zip3 vtrans numpos mlens)
-   in transpose expnd
-
--- | Constructs a printable table from given header and rows
-printTable :: String -> [String] -> [[String]] -> [Bool] -> String
-printTable lp header rows isnum =
-  unlines . map ((++) lp . (:) ' ' . unwords) $
-  formatTable (header:rows) isnum
-
--- | Converts a unit (e.g. m or GB) into a scaling factor.
-parseUnitValue :: (Monad m) => String -> m Rational
-parseUnitValue unit
-  -- binary conversions first
-  | null unit                     = return 1
-  | unit == "m" || upper == "MIB" = return 1
-  | unit == "g" || upper == "GIB" = return kbBinary
-  | unit == "t" || upper == "TIB" = return $ kbBinary * kbBinary
-  -- SI conversions
-  | unit == "M" || upper == "MB"  = return mbFactor
-  | unit == "G" || upper == "GB"  = return $ mbFactor * kbDecimal
-  | unit == "T" || upper == "TB"  = return $ mbFactor * kbDecimal * kbDecimal
-  | otherwise = fail $ "Unknown unit '" ++ unit ++ "'"
-  where upper = map toUpper unit
-        kbBinary = 1024 :: Rational
-        kbDecimal = 1000 :: Rational
-        decToBin = kbDecimal / kbBinary -- factor for 1K conversion
-        mbFactor = decToBin * decToBin -- twice the factor for just 1K
-
--- | Tries to extract number and scale from the given string.
---
--- Input must be in the format NUMBER+ SPACE* [UNIT]. If no unit is
--- specified, it defaults to MiB. Return value is always an integral
--- value in MiB.
-parseUnit :: (Monad m, Integral a, Read a) => String -> m a
-parseUnit str =
-  -- TODO: enhance this by splitting the unit parsing code out and
-  -- accepting floating-point numbers
-  case (reads str::[(Int, String)]) of
-    [(v, suffix)] ->
-      let unit = dropWhile (== ' ') suffix
-      in do
-        scaling <- parseUnitValue unit
-        return $ truncate (fromIntegral v * scaling)
-    _ -> fail $ "Can't parse string '" ++ str ++ "'"
-
--- | Unwraps a 'Result', exiting the program if it is a 'Bad' value,
--- otherwise returning the actual contained value.
-exitIfBad :: String -> Result a -> IO a
-exitIfBad msg (Bad s) = do
-  hPutStrLn stderr $ "Error: " ++ msg ++ ": " ++ s
-  exitWith (ExitFailure 1)
-exitIfBad _ (Ok v) = return v
-
--- | Exits immediately with an error message.
-exitErr :: String -> IO a
-exitErr errmsg = do
-  hPutStrLn stderr $ "Error: " ++ errmsg ++ "."
-  exitWith (ExitFailure 1)
-
--- | Exits with an error message if the given boolean condition if true.
-exitWhen :: Bool -> String -> IO ()
-exitWhen True msg = exitErr msg
-exitWhen False _  = return ()
-
--- | Exits with an error message /unless/ the given boolean condition
--- if true, the opposite of 'exitWhen'.
-exitUnless :: Bool -> String -> IO ()
-exitUnless cond = exitWhen (not cond)
diff --git a/htools/Ganeti/Luxi.hs b/htools/Ganeti/Luxi.hs
index 16fb27d..12dc6ed 100644
--- a/htools/Ganeti/Luxi.hs
+++ b/htools/Ganeti/Luxi.hs
@@ -69,7 +69,7 @@ import qualified Network.Socket as S
 
 import Ganeti.JSON
 import Ganeti.HTools.Types
-import Ganeti.HTools.Utils
+import Ganeti.Utils
 
 import Ganeti.Constants
 import Ganeti.Jobs (JobStatus)
diff --git a/htools/Ganeti/Ssconf.hs b/htools/Ganeti/Ssconf.hs
index 47a2e04..bf3713b 100644
--- a/htools/Ganeti/Ssconf.hs
+++ b/htools/Ganeti/Ssconf.hs
@@ -48,7 +48,7 @@ import System.IO.Error (isDoesNotExistError)
 import qualified Ganeti.Constants as C
 import qualified Ganeti.Path as Path
 import Ganeti.BasicTypes
-import Ganeti.HTools.Utils
+import Ganeti.Utils
 
 -- | Maximum ssconf file size we support.
 maxFileSize :: Int
diff --git a/htools/Ganeti/Utils.hs b/htools/Ganeti/Utils.hs
new file mode 100644
index 0000000..708755e
--- /dev/null
+++ b/htools/Ganeti/Utils.hs
@@ -0,0 +1,232 @@
+{-| Utility functions. -}
+
+{-
+
+Copyright (C) 2009, 2010, 2011, 2012 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.
+
+-}
+
+module Ganeti.Utils
+  ( debug
+  , debugFn
+  , debugXy
+  , sepSplit
+  , stdDev
+  , if'
+  , select
+  , applyIf
+  , commaJoin
+  , ensureQuoted
+  , tryRead
+  , formatTable
+  , printTable
+  , parseUnit
+  , plural
+  , exitIfBad
+  , exitErr
+  , exitWhen
+  , exitUnless
+  ) where
+
+import Data.Char (toUpper, isAlphaNum)
+import Data.List
+
+import Debug.Trace
+
+import Ganeti.BasicTypes
+import System.IO
+import System.Exit
+
+-- * Debug functions
+
+-- | To be used only for debugging, breaks referential integrity.
+debug :: Show a => a -> a
+debug x = trace (show x) x
+
+-- | Displays a modified form of the second parameter before returning
+-- it.
+debugFn :: Show b => (a -> b) -> a -> a
+debugFn fn x = debug (fn x) `seq` x
+
+-- | Show the first parameter before returning the second one.
+debugXy :: Show a => a -> b -> b
+debugXy = seq . debug
+
+-- * Miscellaneous
+
+-- | Apply the function if condition holds, otherwise use default value.
+applyIf :: Bool -> (a -> a) -> a -> a
+applyIf b f x = if b then f x else x
+
+-- | Comma-join a string list.
+commaJoin :: [String] -> String
+commaJoin = intercalate ","
+
+-- | Split a list on a separator and return an array.
+sepSplit :: Eq a => a -> [a] -> [[a]]
+sepSplit sep s
+  | null s    = []
+  | null xs   = [x]
+  | null ys   = [x,[]]
+  | otherwise = x:sepSplit sep ys
+  where (x, xs) = break (== sep) s
+        ys = drop 1 xs
+
+-- | Simple pluralize helper
+plural :: Int -> String -> String -> String
+plural 1 s _ = s
+plural _ _ p = p
+
+-- | Ensure a value is quoted if needed.
+ensureQuoted :: String -> String
+ensureQuoted v = if not (all (\c -> isAlphaNum c || c == '.') v)
+                 then '\'':v ++ "'"
+                 else v
+
+-- * Mathematical functions
+
+-- Simple and slow statistical functions, please replace with better
+-- versions
+
+-- | Standard deviation function.
+stdDev :: [Double] -> Double
+stdDev lst =
+  -- first, calculate the list length and sum lst in a single step,
+  -- for performance reasons
+  let (ll', sx) = foldl' (\(rl, rs) e ->
+                           let rl' = rl + 1
+                               rs' = rs + e
+                           in rl' `seq` rs' `seq` (rl', rs')) (0::Int, 0) lst
+      ll = fromIntegral ll'::Double
+      mv = sx / ll
+      av = foldl' (\accu em -> let d = em - mv in accu + d * d) 0.0 lst
+  in sqrt (av / ll) -- stddev
+
+-- *  Logical functions
+
+-- Avoid syntactic sugar and enhance readability. These functions are proposed
+-- by some for inclusion in the Prelude, and at the moment they are present
+-- (with various definitions) in the utility-ht package. Some rationale and
+-- discussion is available at <http://www.haskell.org/haskellwiki/If-then-else>
+
+-- | \"if\" as a function, rather than as syntactic sugar.
+if' :: Bool -- ^ condition
+    -> a    -- ^ \"then\" result
+    -> a    -- ^ \"else\" result
+    -> a    -- ^ \"then\" or "else" result depending on the condition
+if' True x _ = x
+if' _    _ y = y
+
+-- * Parsing utility functions
+
+-- | Parse results from readsPrec.
+parseChoices :: (Monad m, Read a) => String -> String -> [(a, String)] -> m a
+parseChoices _ _ ((v, ""):[]) = return v
+parseChoices name s ((_, e):[]) =
+    fail $ name ++ ": leftover characters when parsing '"
+           ++ s ++ "': '" ++ e ++ "'"
+parseChoices name s _ = fail $ name ++ ": cannot parse string '" ++ s ++ "'"
+
+-- | Safe 'read' function returning data encapsulated in a Result.
+tryRead :: (Monad m, Read a) => String -> String -> m a
+tryRead name s = parseChoices name s $ reads s
+
+-- | Format a table of strings to maintain consistent length.
+formatTable :: [[String]] -> [Bool] -> [[String]]
+formatTable vals numpos =
+    let vtrans = transpose vals  -- transpose, so that we work on rows
+                                 -- rather than columns
+        mlens = map (maximum . map length) vtrans
+        expnd = map (\(flds, isnum, ml) ->
+                         map (\val ->
+                                  let delta = ml - length val
+                                      filler = replicate delta ' '
+                                  in if delta > 0
+                                     then if isnum
+                                          then filler ++ val
+                                          else val ++ filler
+                                     else val
+                             ) flds
+                    ) (zip3 vtrans numpos mlens)
+   in transpose expnd
+
+-- | Constructs a printable table from given header and rows
+printTable :: String -> [String] -> [[String]] -> [Bool] -> String
+printTable lp header rows isnum =
+  unlines . map ((++) lp . (:) ' ' . unwords) $
+  formatTable (header:rows) isnum
+
+-- | Converts a unit (e.g. m or GB) into a scaling factor.
+parseUnitValue :: (Monad m) => String -> m Rational
+parseUnitValue unit
+  -- binary conversions first
+  | null unit                     = return 1
+  | unit == "m" || upper == "MIB" = return 1
+  | unit == "g" || upper == "GIB" = return kbBinary
+  | unit == "t" || upper == "TIB" = return $ kbBinary * kbBinary
+  -- SI conversions
+  | unit == "M" || upper == "MB"  = return mbFactor
+  | unit == "G" || upper == "GB"  = return $ mbFactor * kbDecimal
+  | unit == "T" || upper == "TB"  = return $ mbFactor * kbDecimal * kbDecimal
+  | otherwise = fail $ "Unknown unit '" ++ unit ++ "'"
+  where upper = map toUpper unit
+        kbBinary = 1024 :: Rational
+        kbDecimal = 1000 :: Rational
+        decToBin = kbDecimal / kbBinary -- factor for 1K conversion
+        mbFactor = decToBin * decToBin -- twice the factor for just 1K
+
+-- | Tries to extract number and scale from the given string.
+--
+-- Input must be in the format NUMBER+ SPACE* [UNIT]. If no unit is
+-- specified, it defaults to MiB. Return value is always an integral
+-- value in MiB.
+parseUnit :: (Monad m, Integral a, Read a) => String -> m a
+parseUnit str =
+  -- TODO: enhance this by splitting the unit parsing code out and
+  -- accepting floating-point numbers
+  case (reads str::[(Int, String)]) of
+    [(v, suffix)] ->
+      let unit = dropWhile (== ' ') suffix
+      in do
+        scaling <- parseUnitValue unit
+        return $ truncate (fromIntegral v * scaling)
+    _ -> fail $ "Can't parse string '" ++ str ++ "'"
+
+-- | Unwraps a 'Result', exiting the program if it is a 'Bad' value,
+-- otherwise returning the actual contained value.
+exitIfBad :: String -> Result a -> IO a
+exitIfBad msg (Bad s) = do
+  hPutStrLn stderr $ "Error: " ++ msg ++ ": " ++ s
+  exitWith (ExitFailure 1)
+exitIfBad _ (Ok v) = return v
+
+-- | Exits immediately with an error message.
+exitErr :: String -> IO a
+exitErr errmsg = do
+  hPutStrLn stderr $ "Error: " ++ errmsg ++ "."
+  exitWith (ExitFailure 1)
+
+-- | Exits with an error message if the given boolean condition if true.
+exitWhen :: Bool -> String -> IO ()
+exitWhen True msg = exitErr msg
+exitWhen False _  = return ()
+
+-- | Exits with an error message /unless/ the given boolean condition
+-- if true, the opposite of 'exitWhen'.
+exitUnless :: Bool -> String -> IO ()
+exitUnless cond = exitWhen (not cond)
diff --git a/htools/htools.hs b/htools/htools.hs
index 08a5a14..216fe3f 100644
--- a/htools/htools.hs
+++ b/htools/htools.hs
@@ -34,7 +34,7 @@ import System.Exit
 import System.IO
 import System.IO.Error (isDoesNotExistError)
 
-import Ganeti.HTools.Utils
+import Ganeti.Utils
 import Ganeti.HTools.CLI (parseOpts, genericOpts)
 import Ganeti.HTools.Program (personalities)
 
