Fix loading of plain instances via iallocator
[ganeti-local] / Ganeti / HTools / CLI.hs
index 3d14b4d..7a216cc 100644 (file)
@@ -7,11 +7,12 @@ and this is more IO oriented.
 -}
 
 module Ganeti.HTools.CLI
-    (
-      parseOpts
+    ( CLIOptions(..)
+    , EToolOptions(..)
+    , parseOpts
     , parseEnv
-    , showVersion
     , shTemplate
+    , loadExternalData
     ) where
 
 import System.Console.GetOpt
@@ -24,24 +25,48 @@ import Text.Printf (printf)
 import qualified Data.Version
 
 import qualified Ganeti.HTools.Version as Version(version)
+import qualified Ganeti.HTools.Rapi as Rapi
+import qualified Ganeti.HTools.Text as Text
+import qualified Ganeti.HTools.Loader as Loader
+
+import Ganeti.HTools.Types
+
+-- | Class for types which support show help and show version
+class CLIOptions a where
+    showHelp    :: a -> Bool
+    showVersion :: a -> Bool
+
+-- | Class for types which support the -i/-n/-m options
+class EToolOptions a where
+    nodeFile   :: a -> FilePath
+    nodeSet    :: a -> Bool
+    instFile   :: a -> FilePath
+    instSet    :: a -> Bool
+    masterName :: a -> String
+    silent     :: a -> Bool
 
 -- | Command line parser, using the 'options' structure.
-parseOpts :: [String]            -- ^ The command line arguments
+parseOpts :: (CLIOptions b) =>
+             [String]            -- ^ The command line arguments
           -> String              -- ^ The program name
           -> [OptDescr (b -> b)] -- ^ The supported command line options
           -> b                   -- ^ The default options record
-          -> (b -> Bool)         -- ^ The function which given the options
-                                 -- tells us whether we need to show help
           -> IO (b, [String])    -- ^ The resulting options a leftover
                                  -- arguments
-parseOpts argv progname options defaultOptions fn =
+parseOpts argv progname options defaultOptions =
     case getOpt Permute options argv of
       (o, n, []) ->
           do
             let resu@(po, _) = (foldl (flip id) defaultOptions o, n)
-            when (fn po) $ do
+            when (showHelp po) $ do
               putStr $ usageInfo header options
               exitWith ExitSuccess
+            when (showVersion po) $ do
+              printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n"
+                     progname Version.version
+                     compilerName (Data.Version.showVersion compilerVersion)
+                     os arch
+              exitWith ExitSuccess
             return resu
       (_, _, errs) ->
           ioError (userError (concat errs ++ usageInfo header options))
@@ -56,15 +81,6 @@ parseEnv () = do
   b <- getEnvDefault "HTOOLS_INSTANCES" "instances"
   return (a, b)
 
--- | Return a version string for the program
-showVersion :: String -- ^ The program name
-            -> String -- ^ The formatted version and other information data
-showVersion name =
-    printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n"
-           name Version.version
-           compilerName (Data.Version.showVersion compilerVersion)
-           os arch
-
 -- | A shell script template for autogenerated scripts
 shTemplate :: String
 shTemplate =
@@ -78,3 +94,34 @@ shTemplate =
            \    exit 0\n\
            \  fi\n\
            \}\n\n"
+
+-- | External tool data loader from a variety of sources
+loadExternalData :: (EToolOptions a) =>
+                    a
+                 -> IO (NodeList, InstanceList, String)
+loadExternalData opts = do
+  (env_node, env_inst) <- parseEnv ()
+  let nodef = if nodeSet opts then nodeFile opts
+              else env_node
+      instf = if instSet opts then instFile opts
+              else env_inst
+  input_data <-
+      case masterName opts of
+        "" -> Text.loadData nodef instf
+        host -> Rapi.loadData host
+
+  let ldresult = input_data >>= Loader.mergeData
+  (loaded_nl, il, csf) <-
+      (case ldresult of
+         Ok x -> return x
+         Bad s -> do
+           printf "Error: failed to load data. Details:\n%s\n" s
+           exitWith $ ExitFailure 1
+      )
+  let (fix_msgs, fixed_nl) = Loader.checkData loaded_nl il
+
+  unless (null fix_msgs || silent opts) $ do
+         putStrLn "Warning: cluster has inconsistent data:"
+         putStrLn . unlines . map (\s -> printf "  - %s" s) $ fix_msgs
+
+  return (fixed_nl, il, csf)