diff --git a/Makefile.am b/Makefile.am
index 7c31f56a2ff1190feee8af480aef765070ae6628..ec2e6470e68526489b9cc0d2d9aac539f3de4137 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -407,7 +407,7 @@ docrst = \
 	doc/walkthrough.rst
 
 HS_PROGS = htools/htools htools/mon-collector
-HS_BIN_ROLES = hbal hscan hspace hinfo hcheck
+HS_BIN_ROLES = hbal hscan hspace hinfo hcheck hroller
 HS_HTOOLS_PROGS = $(HS_BIN_ROLES) hail
 
 HS_ALL_PROGS = \
@@ -481,6 +481,7 @@ HS_LIB_SRCS = \
 	htools/Ganeti/HTools/Program/Hinfo.hs \
 	htools/Ganeti/HTools/Program/Hscan.hs \
 	htools/Ganeti/HTools/Program/Hspace.hs \
+	htools/Ganeti/HTools/Program/Hroller.hs \
 	htools/Ganeti/HTools/Types.hs \
 	htools/Ganeti/Hash.hs \
 	htools/Ganeti/JQueue.hs \
@@ -851,6 +852,7 @@ man_MANS = \
 	man/hinfo.1 \
 	man/hscan.1 \
 	man/hspace.1 \
+	man/hroller.1 \
 	man/htools.1 \
 	man/mon-collector.7
 
diff --git a/autotools/run-in-tempdir b/autotools/run-in-tempdir
index fa698fe7c5fd117f943906f3f9a735da9bde1802..d5bdb7a063cae6bd2586efdcf573b58f50d16906 100755
--- a/autotools/run-in-tempdir
+++ b/autotools/run-in-tempdir
@@ -24,7 +24,7 @@ for hfile in htools ganeti-confd mon-collector; do
 done
 
 for hfile in hpc-htools test offline-test.sh cli-tests-defs.sh \
-  hbal hscan hspace hinfo hcheck hail hpc-mon-collector; do
+  hbal hscan hspace hinfo hcheck hail hroller hpc-mon-collector; do
   if [ -e htest/$hfile ]; then
     cp -p htest/$hfile $tmpdir/htest/
   fi
diff --git a/htest/cli-tests-defs.sh b/htest/cli-tests-defs.sh
index 1facff4b808391849efc75b4749e6c550e720611..86dd64f1d19415815d256ef8ace2ab52b5d3ea1b 100644
--- a/htest/cli-tests-defs.sh
+++ b/htest/cli-tests-defs.sh
@@ -48,4 +48,8 @@ hcheck() {
   HTOOLS=hinfo $HBINARY "$@"
 }
 
-ALL_ROLES="hbal hscan hail hspace hinfo hcheck"
+hroller() {
+  HTOOLS=hroller $HBINARY "$@"
+}
+
+ALL_ROLES="hbal hscan hail hspace hinfo hcheck hroller"
diff --git a/htest/shelltests/htools-basic.test b/htest/shelltests/htools-basic.test
index 325bd9a0fc02380de7e88a0b52111d2288578c6d..e462f7fa2d780644a0d8bcbd754fd8eb1047e852 100644
--- a/htest/shelltests/htools-basic.test
+++ b/htest/shelltests/htools-basic.test
@@ -23,3 +23,7 @@
 >>>= 0
 ./htest/hcheck --help
 >>>= 0
+./htest/hroller --version
+>>>= 0
+./htest/hroller --help
+>>>= 0
diff --git a/htools/Ganeti/HTools/Program.hs b/htools/Ganeti/HTools/Program.hs
index 7e9554643715fb5f14685bd78152b02257ea32fd..46e012b566a2d439f8e8b4004790a6928ea64bf2 100644
--- a/htools/Ganeti/HTools/Program.hs
+++ b/htools/Ganeti/HTools/Program.hs
@@ -36,30 +36,35 @@ 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
+import qualified Ganeti.HTools.Program.Hroller as Hroller
 
 -- | Supported binaries.
 personalities :: PersonalityList Options
 personalities =
-  [ ("hail",   (Hail.main,   Hail.options,   Hail.arguments,
-                "Ganeti IAllocator plugin that implements the instance\
-                \ placement and movement using the same algorithm as\
-                \ hbal(1)"))
-  , ("hbal",   (Hbal.main,   Hbal.options,   Hbal.arguments,
-                "cluster balancer that looks at the current state of\
-                \ the cluster and computes a series of steps designed\
-                \ to bring the cluster into a better state"))
-  , ("hcheck", (Hcheck.main, Hcheck.options, Hcheck.arguments,
-               "cluster checker; prints information about cluster's\
-               \ health and checks whether a rebalance done using\
-               \ hbal would help"))
-  , ("hscan",  (Hscan.main,  Hscan.options,  Hscan.arguments,
-               "tool for scanning clusters via RAPI and saving their\
-               \ data in the input format used by hbal(1) and hspace(1)"))
-  , ("hspace", (Hspace.main, Hspace.options, Hspace.arguments,
-               "computes how many additional instances can be fit on a\
-               \ cluster, while maintaining N+1 status."))
-  , ("hinfo",  (Hinfo.main,  Hinfo.options,  Hinfo.arguments,
-               "cluster information printer; it prints information\
-               \ about the current cluster state and its residing\
-               \ nodes/instances"))
+  [ ("hail",    (Hail.main,    Hail.options,    Hail.arguments,
+                 "Ganeti IAllocator plugin that implements the instance\
+                 \ placement and movement using the same algorithm as\
+                 \ hbal(1)"))
+  , ("hbal",    (Hbal.main,    Hbal.options,    Hbal.arguments,
+                 "cluster balancer that looks at the current state of\
+                 \ the cluster and computes a series of steps designed\
+                 \ to bring the cluster into a better state"))
+  , ("hcheck",  (Hcheck.main,  Hcheck.options,  Hcheck.arguments,
+                "cluster checker; prints information about cluster's\
+                \ health and checks whether a rebalance done using\
+                \ hbal would help"))
+  , ("hscan",   (Hscan.main,   Hscan.options,   Hscan.arguments,
+                "tool for scanning clusters via RAPI and saving their\
+                \ data in the input format used by hbal(1) and hspace(1)"))
+  , ("hspace",  (Hspace.main,  Hspace.options,  Hspace.arguments,
+                "computes how many additional instances can be fit on a\
+                \ cluster, while maintaining N+1 status."))
+  , ("hinfo",   (Hinfo.main,   Hinfo.options,   Hinfo.arguments,
+                "cluster information printer; it prints information\
+                \ about the current cluster state and its residing\
+                \ nodes/instances"))
+  , ("hroller", (Hroller.main, Hroller.options, Hroller.arguments,
+                "cluster rolling maintenance helper; it helps scheduling\
+                \ node reboots in a manner that doesn't conflict with the\
+                \ instances' topology"))
   ]
diff --git a/htools/Ganeti/HTools/Program/Hroller.hs b/htools/Ganeti/HTools/Program/Hroller.hs
new file mode 100644
index 0000000000000000000000000000000000000000..166973d259849cfb81b305b278c71d6940c8decd
--- /dev/null
+++ b/htools/Ganeti/HTools/Program/Hroller.hs
@@ -0,0 +1,57 @@
+{-| Cluster rolling maintenance helper.
+
+-}
+
+{-
+
+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 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.Program.Hroller
+  ( main
+  , options
+  , arguments
+  ) where
+
+import Ganeti.Common
+import Ganeti.HTools.CLI
+
+-- | Options list and functions.
+options :: IO [OptType]
+options = do
+  luxi <- oLuxiSocket
+  return
+    [ luxi
+    , oRapiMaster
+    , oDataFile
+    , oIAllocSrc
+    , oOfflineNode
+    , oVerbose
+    , oQuiet
+    , oNoHeaders
+    , oSaveCluster
+    ]
+
+-- | The list of arguments supported by the program.
+arguments :: [ArgCompletion]
+arguments = []
+
+-- | Main function.
+main :: Options -> [String] -> IO ()
+main _ _ = return ()
diff --git a/man/hroller.rst b/man/hroller.rst
new file mode 100644
index 0000000000000000000000000000000000000000..ee7aebca1ca8367d91f6e6f0fe2b830d1e04f66b
--- /dev/null
+++ b/man/hroller.rst
@@ -0,0 +1,53 @@
+HROLLER(1) Ganeti | Version @GANETI_VERSION@
+============================================
+
+NAME
+----
+
+hroller \- Cluster rolling maintenance scheduler for Ganeti
+
+SYNOPSIS
+--------
+
+**hroller** {backend options...} [algorithm options...] [reporting options...]
+
+**hroller** \--version
+
+
+Backend options:
+
+{ **-m** *cluster* | **-L[** *path* **]** | **-t** *data-file* |
+**-I** *path* }
+
+Algorithm options:
+
+**[ -O *name...* ]**
+
+Reporting options:
+
+**[ -v... | -q ]**
+**[ -S *file* ]**
+
+DESCRIPTION
+-----------
+
+hroller is a cluster maintenance reboot scheduler. It can calculate
+which set of nodes can be rebooted at the same time while avoiding
+having both primary and secondary nodes being rebooted at the same time.
+
+OPTIONS
+-------
+
+Currently only standard htools options are supported. For a description of them
+check **htools(7)** and **hbal(1)**.
+
+BUGS
+----
+
+The program does nothing.
+
+.. vim: set textwidth=72 :
+.. Local Variables:
+.. mode: rst
+.. fill-column: 72
+.. End:
diff --git a/man/htools.rst b/man/htools.rst
index ea9019f7d656638d4f3d6e3bd744eb3c054ab60e..e19ce820935f9afebdaf02e0c12afe79855aaf72 100644
--- a/man/htools.rst
+++ b/man/htools.rst
@@ -27,11 +27,12 @@ SYNOPSIS
 **hinfo**
   cluster information printer
 
+**hroller**
+  cluster rolling maintenance scheduler
 
 DESCRIPTION
 -----------
 
-
 ``htools`` is a suite of tools designed to help with allocation/movement
 of instances and balancing of Ganeti clusters. ``htools`` is also the
 generic binary that must be symlinked or hardlinked under each tool's
@@ -57,6 +58,9 @@ saves it to files which can later be reused by the other roles.
 Installed as ``hinfo``, it prints information about the current cluster
 state.
 
+Installed as ``hroller``, it helps scheduling maintenances that require
+node reboots on a cluster.
+
 COMMON OPTIONS
 --------------