Commit 112aee5f authored by Iustin Pop's avatar Iustin Pop
Browse files

Merge branch 'stable-2.6'



* stable-2.6: (72 commits)
  Make Ganeti 2.6.0 rc3 release
  Allow reinstall even when secondaries are offline
  Prepare NEWS file for Ganeti 2.6.0 rc3
  QA updated to test instance removing when sec. is offline
  Ignore offline node errors when removing disks
  Allow instance disc activation with offline secondaries
  RAPI regression beparams/memory fix
  Fix redistribution of files w.r.t. offline nodes
  Fix cluster verify error on master-ip-setup script
  Add a Makefile rule to test unclean git status
  Add test helpers to .gitignore
  Fix a typo in NEWS
  Release Ganeti 2.6.0rc2
  Prepare NEWS file for 2.6.0 rc2
  Update time on Haskell binaries after build
  hcheck: add two simple type aliases for readability
  hcheck: rework output mode
  hcheck: reword and fix typo in instance/offline msg
  Add hlint warning for wrong use of 'length'
  Remove can_rebalance functionality from hcheck
  ...

Conflicts:
        htools/Ganeti/HTools/QC.hs: due to the cleanup of missing type
        signatures, and the fact that in master two test functions had
        a changed argument list, trivial to fix
Signed-off-by: default avatarIustin Pop <iustin@google.com>
Reviewed-by: default avatarRené Nussbaumer <rn@google.com>
parents 76ae2e5b 88e14195
......@@ -81,6 +81,14 @@
/man/*.gen
/man/footer.man
# test
/test/hail
/test/hbal
/test/hcheck
/test/hinfo
/test/hscan
/test/hspace
# tools
/tools/kvm-ifup
/tools/ensure-dirs
......
......@@ -178,15 +178,17 @@ and a few has extra dependencies:
version 4.2.4
- `text <http://hackage.haskell.org/package/text>`_
- ``bytestring``, which usually comes with the compiler
- `hinotify <http://hackage.haskell.org/package/hinotify>`_
These libraries are available in Debian Wheezy (but not in Squeeze), so
you can use either apt::
$ apt-get install libghc-hslogger-dev libghc-crypto-dev libghc-text-dev
$ apt-get install libghc-hslogger-dev libghc-crypto-dev libghc-text-dev \
libghc-hinotify-dev
or ``cabal``::
$ cabal install hslogger Crypto text
$ cabal install hslogger Crypto text hinotify
to install them.
......
......@@ -356,7 +356,7 @@ docrst = \
doc/walkthrough.rst
HS_PROGS = htools/htools
HS_BIN_ROLES = hbal hscan hspace hinfo
HS_BIN_ROLES = hbal hscan hspace hinfo hcheck
HS_ALL_PROGS = $(HS_PROGS) htools/test htools/hpc-htools htools/hconfd
HS_PROG_SRCS = $(patsubst %,%.hs,$(HS_ALL_PROGS))
......@@ -399,6 +399,7 @@ HS_LIB_SRCS = \
htools/Ganeti/HTools/Program.hs \
htools/Ganeti/HTools/Program/Hail.hs \
htools/Ganeti/HTools/Program/Hbal.hs \
htools/Ganeti/HTools/Program/Hcheck.hs \
htools/Ganeti/HTools/Program/Hinfo.hs \
htools/Ganeti/HTools/Program/Hscan.hs \
htools/Ganeti/HTools/Program/Hspace.hs \
......@@ -548,6 +549,8 @@ $(HS_ALL_PROGS): %: %.hs $(HS_LIB_SRCS) $(HS_BUILT_SRCS) Makefile
$(HTOOLS_NOCURL) $(HTOOLS_PARALLEL3) \
-osuf $$BINARY.o -hisuf $$BINARY.hi \
$(HEXTRA) $(HEXTRA_INT) $@
@touch "$@"
# for the htools/test binary, we need to enable profiling/coverage
htools/test: HEXTRA_INT=-fhpc
......@@ -691,6 +694,7 @@ man_MANS = \
man/gnt-os.8 \
man/hail.1 \
man/hbal.1 \
man/hcheck.1 \
man/hinfo.1 \
man/hscan.1 \
man/hspace.1 \
......@@ -733,6 +737,7 @@ TEST_FILES = \
test/data/htools/hail-invalid-reloc.json \
test/data/htools/hail-node-evac.json \
test/data/htools/hail-reloc-drbd.json \
test/data/htools/hbal-split-insts.data \
test/data/htools/common-suffix.data \
test/data/htools/invalid-node.data \
test/data/htools/missing-resources.data \
......@@ -1517,6 +1522,14 @@ live-test: all
commit-check: distcheck lint apidoc
.PHONY: gitignore-check
gitignore-check:
@if [ -n "`git status --short`" ]; then \
echo "Git status is not clean!" 1>&2 ; \
git status --short; \
exit 1; \
fi
-include ./Makefile.local
# vim: set noet :
......@@ -2,10 +2,10 @@ News
====
Version 2.6.0 beta2
-------------------
Version 2.6.0 rc3
-----------------
*(Released Mon, 11 Jun 2012)*
*(Released Fri, 13 Jul 2012)*
New features
~~~~~~~~~~~~
......@@ -240,6 +240,10 @@ accept the target size of the disk, instead of the delta; this can be
more safe since two runs in absolute mode will be idempotent, and
sometimes it's also easier to specify the desired size directly.
Also the handling of instances with regard to offline secondaries has
been improved. Instance operations should not fail because one of it's
secondary nodes is offline, even though it's safe to proceed.
API changes
~~~~~~~~~~~
......@@ -295,6 +299,67 @@ verification. This will remove some rare but hard to diagnose errors in
import-export.
Version 2.6.0 rc2
-----------------
*(Released Tue, 03 Jul 2012)*
Second release candidate for 2.6. The following changes were done from
rc2 to rc3:
- Fixed ``gnt-cluster verify`` regarding ``master-ip-script`` on non
master candidates
- Fixed a RAPI regression on missing beparams/memory
- Fixed redistribution of files on offline nodes
- Added possibility to run activate-disks even though secondaries are
offline. With this change it relaxes also the strictness on some other
commands which use activate disks internally:
* ``gnt-instance start|reboot|rename|backup|export``
- Made it possible to remove safely an instance if its secondaries are
offline
- Made it possible to reinstall even though secondaries are offline
Version 2.6.0 rc1
-----------------
*(Released Mon, 25 Jun 2012)*
First release candidate for 2.6. The following changes were done from
rc1 to rc2:
- Fixed bugs with disk parameters and ``rbd`` templates as well as
``instance_os_add``
- Made ``gnt-instance modify`` more consistent regarding new NIC/Disk
behaviour. It supports now the modify operation
- ``hcheck`` implemented to analyze cluster health and possibility of
improving health by rebalance
- ``hbal`` has been improved in dealing with split instances
Version 2.6.0 beta2
-------------------
*(Released Mon, 11 Jun 2012)*
Second beta release of 2.6. The following changes were done from beta2
to rc1:
- Fixed ``daemon-util`` with non-root user models
- Fixed creation of plain instances with ``--no-wait-for-sync``
- Fix wrong iv_names when running ``cfgupgrade``
- Export more information in RAPI group queries
- Fixed bug when changing instance network interfaces
- Extended burnin to do NIC changes
- query: Added ``<``, ``>``, ``<=``, ``>=`` comparison operators
- Changed default for DRBD barriers
- Fixed DRBD error reporting for syncer rate
- Verify the options on disk parameters
And of course various fixes to documentation and improved unittests and
QA.
Version 2.6.0 beta1
-------------------
......
......@@ -2,7 +2,7 @@
m4_define([gnt_version_major], [2])
m4_define([gnt_version_minor], [6])
m4_define([gnt_version_revision], [0])
m4_define([gnt_version_suffix], [~beta2])
m4_define([gnt_version_suffix], [~rc3])
m4_define([gnt_version_full],
m4_format([%d.%d.%d%s],
gnt_version_major, gnt_version_minor,
......@@ -235,7 +235,7 @@ AC_ARG_ENABLE([drbd-barriers],
DRBD_BARRIERS=n
DRBD_NO_META_FLUSH=False
else
DRBD_BARRIERS=bfd
DRBD_BARRIERS=bf
DRBD_NO_META_FLUSH=True
fi
]],
......
......@@ -148,16 +148,6 @@ Changes a node's parameters.
:pre-execution: master node, the target node
:post-execution: master node, the target node
OP_NODE_EVACUATE
++++++++++++++++
Relocate secondary instances from a node.
:directory: node-evacuate
:env. vars: NEW_SECONDARY, NODE_NAME
:pre-execution: master node, target node
:post-execution: master node, target node
OP_NODE_MIGRATE
++++++++++++++++
......@@ -344,16 +334,6 @@ Remove an instance.
:pre-execution: master node
:post-execution: master node, primary and secondary nodes
OP_INSTANCE_REPLACE_DISKS
+++++++++++++++++++++++++
Replace an instance's disks.
:directory: mirror-replace
:env. vars: MODE, NEW_SECONDARY, OLD_SECONDARY
:pre-execution: master node, primary and secondary nodes
:post-execution: master node, primary and secondary nodes
OP_INSTANCE_GROW_DISK
+++++++++++++++++++++
......
......@@ -220,8 +220,8 @@ The instance policy specification is a dict with the following fields:
The numbers of nics used
:pyeval:`constants.ISPEC_SPINDLE_USE`
The numbers of virtual disk spindles used by this instance. They are
not real, but useful for account the spindle usage on the residing
node.
not real in the sense of actual HDD spindles, but useful for
accounting the spindle usage on the residing node
:pyeval:`constants.IPOLICY_DTS`
A `list` of disk templates allowed for instances using this policy
:pyeval:`constants.IPOLICY_VCPU_RATIO`
......@@ -388,12 +388,12 @@ features:
rlib2._NODE_EVAC_RES1])
:pyeval:`rlib2._INST_CREATE_REQV1`
Instance creation request data version 1 supported.
Instance creation request data version 1 supported
:pyeval:`rlib2._INST_REINSTALL_REQV1`
Instance reinstall supports body parameters.
Instance reinstall supports body parameters
:pyeval:`rlib2._NODE_MIGRATE_REQV1`
Whether migrating a node (``/2/nodes/[node_name]/migrate``) supports
request body parameters.
request body parameters
:pyeval:`rlib2._NODE_EVAC_RES1`
Whether evacuating a node (``/2/nodes/[node_name]/evacuate``) returns
a new-style result (see resource description)
......@@ -449,7 +449,7 @@ If the optional bool *bulk* argument is provided and set to a true value
(i.e ``?bulk=1``), the output contains detailed information about node
groups as a list.
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.G_FIELDS))`
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.G_FIELDS))`.
Example::
......@@ -508,7 +508,7 @@ It supports the following commands: ``GET``, ``DELETE``.
Returns information about a node group, similar to the bulk output from
the node group list.
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.G_FIELDS))`
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.G_FIELDS))`.
``DELETE``
~~~~~~~~~~
......@@ -657,7 +657,7 @@ If the optional bool *bulk* argument is provided and set to a true value
(i.e ``?bulk=1``), the output contains detailed information about
instances as a list.
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.I_FIELDS))`
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.I_FIELDS))`.
Example::
......@@ -732,7 +732,7 @@ It supports the following commands: ``GET``, ``DELETE``.
Returns information about an instance, similar to the bulk output from
the instance list.
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.I_FIELDS))`
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.I_FIELDS))`.
``DELETE``
~~~~~~~~~~
......@@ -1120,25 +1120,25 @@ console. Contained keys:
])
``instance``
Instance name.
Instance name
``kind``
Console type, one of :pyeval:`constants.CONS_SSH`,
:pyeval:`constants.CONS_VNC`, :pyeval:`constants.CONS_SPICE`
or :pyeval:`constants.CONS_MESSAGE`.
or :pyeval:`constants.CONS_MESSAGE`
``message``
Message to display (:pyeval:`constants.CONS_MESSAGE` type only).
Message to display (:pyeval:`constants.CONS_MESSAGE` type only)
``host``
Host to connect to (:pyeval:`constants.CONS_SSH`,
:pyeval:`constants.CONS_VNC` or :pyeval:`constants.CONS_SPICE` only).
:pyeval:`constants.CONS_VNC` or :pyeval:`constants.CONS_SPICE` only)
``port``
TCP port to connect to (:pyeval:`constants.CONS_VNC` or
:pyeval:`constants.CONS_SPICE` only).
:pyeval:`constants.CONS_SPICE` only)
``user``
Username to use (:pyeval:`constants.CONS_SSH` only).
Username to use (:pyeval:`constants.CONS_SSH` only)
``command``
Command to execute on machine (:pyeval:`constants.CONS_SSH` only)
``display``
VNC display number (:pyeval:`constants.CONS_VNC` only).
VNC display number (:pyeval:`constants.CONS_VNC` only)
``/2/instances/[instance_name]/tags``
......@@ -1201,7 +1201,7 @@ as a list.
Returned fields for bulk requests (unlike other bulk requests, these
fields are not the same as for per-job requests):
:pyeval:`utils.CommaJoin(sorted(rlib2.J_FIELDS_BULK))`
:pyeval:`utils.CommaJoin(sorted(rlib2.J_FIELDS_BULK))`.
``/2/jobs/[job_id]``
++++++++++++++++++++
......@@ -1309,14 +1309,14 @@ Waits for changes on a job. Takes the following body parameters in a
dict:
``fields``
The job fields on which to watch for changes.
The job fields on which to watch for changes
``previous_job_info``
Previously received field values or None if not yet available.
Previously received field values or None if not yet available
``previous_log_serial``
Highest log serial number received so far or None if not yet
available.
available
Returns None if no changes have been detected and a dict with two keys,
``job_info`` and ``log_entries`` otherwise.
......@@ -1351,7 +1351,7 @@ If the optional bool *bulk* argument is provided and set to a true value
(i.e ``?bulk=1``), the output contains detailed information about nodes
as a list.
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.N_FIELDS))`
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.N_FIELDS))`.
Example::
......@@ -1378,7 +1378,7 @@ Returns information about a node.
It supports the following commands: ``GET``.
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.N_FIELDS))`
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.N_FIELDS))`.
``/2/nodes/[node_name]/powercycle``
+++++++++++++++++++++++++++++++++++
......
......@@ -39,6 +39,8 @@ module Ganeti.HTools.CLI
, maybePrintNodes
, maybePrintInsts
, maybeShowWarnings
, printKeys
, printFinal
, setNodeStatus
-- * The options
, oDataFile
......@@ -62,6 +64,7 @@ module Ganeti.HTools.CLI
, oMinGainLim
, oMinScore
, oNoHeaders
, oNoSimulation
, oNodeSim
, oOfflineNode
, oOutputDir
......@@ -82,6 +85,7 @@ module Ganeti.HTools.CLI
) where
import Control.Monad
import Data.Char (toUpper)
import Data.Maybe (fromMaybe)
import qualified Data.Version
import System.Console.GetOpt
......@@ -133,6 +137,7 @@ data Options = Options
, optMinGainLim :: Score -- ^ Limit below which we apply mingain
, optMinScore :: Score -- ^ The minimum score we aim for
, optNoHeaders :: Bool -- ^ Do not show a header line
, optNoSimulation :: Bool -- ^ Skip the rebalancing dry-run
, optNodeSim :: [String] -- ^ Cluster simulation mode
, optOffline :: [String] -- ^ Names of offline nodes
, optOutPath :: FilePath -- ^ Path to the output directory
......@@ -175,6 +180,7 @@ defaultOptions = Options
, optMinGainLim = 1e-1
, optMinScore = 1e-9
, optNoHeaders = False
, optNoSimulation = False
, optNodeSim = []
, optOffline = []
, optOutPath = "."
......@@ -349,10 +355,16 @@ oNoHeaders = Option "" ["no-headers"]
(NoArg (\ opts -> Ok opts { optNoHeaders = True }))
"do not show a header line"
oNoSimulation :: OptType
oNoSimulation = Option "" ["no-simulation"]
(NoArg (\opts -> Ok opts {optNoSimulation = True}))
"do not perform rebalancing simulation"
oNodeSim :: OptType
oNodeSim = Option "" ["simulate"]
(ReqArg (\ f o -> Ok o { optNodeSim = f:optNodeSim o }) "SPEC")
"simulate an empty cluster, given as 'num_nodes,disk,ram,cpu'"
"simulate an empty cluster, given as\
\ 'alloc_policy,num_nodes,disk,ram,cpu'"
oOfflineNode :: OptType
oOfflineNode = Option "O" ["offline"]
......@@ -555,6 +567,24 @@ maybeShowWarnings fix_msgs =
hPutStrLn stderr "Warning: cluster has inconsistent data:"
hPutStrLn stderr . unlines . map (printf " - %s") $ fix_msgs
-- | Format a list of key, value as a shell fragment.
printKeys :: String -- ^ Prefix to printed variables
-> [(String, String)] -- ^ List of (key, value) pairs to be printed
-> IO ()
printKeys prefix = mapM_ (\(k, v) ->
printf "%s_%s=%s\n" prefix (map toUpper k) (ensureQuoted v))
-- | Prints the final @OK@ marker in machine readable output.
printFinal :: String -- ^ Prefix to printed variable
-> Bool -- ^ Whether output should be machine readable
-- Note: if not, there is nothing to print
-> IO ()
printFinal prefix True =
-- this should be the final entry
printKeys prefix [("OK", "1")]
printFinal _ False = return ()
-- | Potentially set the node as offline based on passed offline list.
setNodeOffline :: [Ndx] -> Node.Node -> Node.Node
setNodeOffline offline_indices n =
......
......@@ -55,6 +55,7 @@ import qualified Ganeti.HTools.Container as Container
import qualified Ganeti.HTools.Instance as Instance
import qualified Ganeti.HTools.Node as Node
import qualified Ganeti.HTools.Group as Group
import qualified Ganeti.HTools.Cluster as Cluster
import Ganeti.HTools.Types
import Ganeti.HTools.Utils
......@@ -242,6 +243,13 @@ updateMovable selinsts exinsts inst =
then Instance.setMovable inst False
else inst
-- | Disables moves for instances with a split group.
disableSplitMoves :: Node.List -> Instance.Instance -> Instance.Instance
disableSplitMoves nl inst =
if not . isOk . Cluster.instanceGroup nl $ inst
then Instance.setMovable inst False
else inst
-- | Compute the longest common suffix of a list of strings that
-- starts with a dot.
longestDomain :: [String] -> String
......@@ -298,8 +306,9 @@ mergeData um extags selinsts exinsts cdata@(ClusterData gl nl il2 tags _) =
nl3 = Container.map (setNodePolicy gl .
computeAlias common_suffix .
(`Node.buildPeers` il4)) nl2
il5 = Container.map (disableSplitMoves nl3) il4
in if' (null lkp_unknown)
(Ok cdata { cdNodes = nl3, cdInstances = il4 })
(Ok cdata { cdNodes = nl3, cdInstances = il5 })
(Bad $ "Unknown instance(s): " ++ show(map lrContent lkp_unknown))
-- | Checks the cluster data for consistency.
......
......@@ -31,6 +31,7 @@ import Ganeti.HTools.CLI (OptType, Options)
import qualified Ganeti.HTools.Program.Hail as Hail
import qualified Ganeti.HTools.Program.Hbal as Hbal
import qualified Ganeti.HTools.Program.Hcheck as Hcheck
import qualified Ganeti.HTools.Program.Hscan as Hscan
import qualified Ganeti.HTools.Program.Hspace as Hspace
import qualified Ganeti.HTools.Program.Hinfo as Hinfo
......@@ -39,6 +40,7 @@ import qualified Ganeti.HTools.Program.Hinfo as Hinfo
personalities :: [(String, (Options -> [String] -> IO (), [OptType]))]
personalities = [ ("hail", (Hail.main, Hail.options))
, ("hbal", (Hbal.main, Hbal.options))
, ("hcheck", (Hcheck.main, Hcheck.options))
, ("hscan", (Hscan.main, Hscan.options))
, ("hspace", (Hspace.main, Hspace.options))
, ("hinfo", (Hinfo.main, Hinfo.options))
......
......@@ -23,7 +23,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-}
module Ganeti.HTools.Program.Hbal (main, options) where
module Ganeti.HTools.Program.Hbal
( main
, options
, iterateDepth
) where
import Control.Concurrent (threadDelay)
import Control.Exception (bracket)
......@@ -90,7 +94,8 @@ options =
we find a valid solution or we exceed the maximum depth.
-}
iterateDepth :: Cluster.Table -- ^ The starting table
iterateDepth :: Bool -- ^ Whether to print moves
-> Cluster.Table -- ^ The starting table
-> Int -- ^ Remaining length
-> Bool -- ^ Allow disk moves
-> Bool -- ^ Allow instance moves
......@@ -103,7 +108,7 @@ iterateDepth :: Cluster.Table -- ^ The starting table
-> Bool -- ^ Enable evacuation mode
-> IO (Cluster.Table, [MoveJob]) -- ^ The resulting table
-- and commands
iterateDepth ini_tbl max_rounds disk_moves inst_moves nmlen imlen
iterateDepth printmove ini_tbl max_rounds disk_moves inst_moves nmlen imlen
cmd_strs min_score mg_limit min_gain evac_mode =
let Cluster.Table ini_nl ini_il _ _ = ini_tbl
allowed_next = Cluster.doNextBalance ini_tbl max_rounds min_score
......@@ -121,9 +126,10 @@ iterateDepth ini_tbl max_rounds disk_moves inst_moves nmlen imlen
nmlen imlen cur_plc fin_plc_len
afn = Cluster.involvedNodes ini_il cur_plc
upd_cmd_strs = (afn, idx, move, cmds):cmd_strs
putStrLn sol_line
hFlush stdout
iterateDepth fin_tbl max_rounds disk_moves inst_moves
when printmove $ do
putStrLn sol_line
hFlush stdout
iterateDepth printmove fin_tbl max_rounds disk_moves inst_moves
nmlen imlen upd_cmd_strs min_score
mg_limit min_gain evac_mode
Nothing -> return (ini_tbl, cmd_strs)
......@@ -295,11 +301,10 @@ checkCluster verbose nl il = do
-- hbal doesn't currently handle split clusters
let split_insts = Cluster.findSplitInstances nl il
unless (null split_insts) $ do
unless (null split_insts || verbose <= 1) $ do
hPutStrLn stderr "Found instances belonging to multiple node groups:"
mapM_ (\i -> hPutStrLn stderr $ " " ++ Instance.name i) split_insts
hPutStrLn stderr "Aborting."
exitWith $ ExitFailure 1
hPutStrLn stderr "These instances will not be moved."
printf "Loaded %d nodes, %d instances\n"
(Container.size nl)
......@@ -323,7 +328,7 @@ checkGroup verbose gname nl il = do
"Initial check done: %d bad nodes, %d bad instances.\n"
(length bad_nodes) (length bad_instances)
when (length bad_nodes > 0) $
when (not (null bad_nodes)) $
putStrLn "Cluster is not N+1 happy, continuing but no guarantee \
\that the cluster will end N+1 happy."
......@@ -382,7 +387,7 @@ main opts args = do
let imlen = maximum . map (length . Instance.alias) $ Container.elems il
nmlen = maximum . map (length . Node.alias) $ Container.elems nl
(fin_tbl, cmd_strs) <- iterateDepth ini_tbl (optMaxLength opts)
(fin_tbl, cmd_strs) <- iterateDepth True ini_tbl (optMaxLength opts)
(optDiskMoves opts)
(optInstMoves opts)
nmlen imlen [] min_cv
......
{-| Cluster checker.
-}
{-
Copyright (C) 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 Gene52al 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.Program.Hcheck (main, options) where
import Control.Monad
import Data.List (transpose)
import System.Exit
import System.IO
import Text.Printf (printf)
import qualified Ganeti.HTools.Container as Container
import qualified Ganeti.HTools.Cluster as Cluster
import qualified Ganeti.HTools.Group as Group
import qualified Ganeti.HTools.Node as Node
import qualified Ganeti.HTools.Instance as Instance
import qualified Ganeti.HTools.Program.Hbal as Hbal
import Ganeti.HTools.CLI
import Ganeti.HTools.ExtLoader
import Ganeti.HTools.Loader
import Ganeti.HTools.Types
-- | Options list and functions.
options :: [OptType]
options =
[ oDataFile
, oDiskMoves
, oDynuFile
, oEvacMode
, oExInst
, oExTags
, oIAllocSrc
, oInstMoves
, oLuxiSocket
, oMachineReadable
, oMaxCpu
, oMaxSolLength
, oMinDisk
, oMinGain