diff --git a/htools/Ganeti/HTools/Cluster.hs b/htools/Ganeti/HTools/Cluster.hs
index 901c981c91514d460c69a10b53bf9162ad73fb00..1cc61174e3dccc1bd361791bef4730fa3e5bfdcb 100644
--- a/htools/Ganeti/HTools/Cluster.hs
+++ b/htools/Ganeti/HTools/Cluster.hs
@@ -74,6 +74,7 @@ module Ganeti.HTools.Cluster
     ) where
 
 import Data.Function (on)
+import qualified Data.IntSet as IntSet
 import Data.List
 import Data.Ord (comparing)
 import Text.Printf (printf)
@@ -1103,3 +1104,25 @@ associateIdxs :: [Idx] -- ^ Instance indices to be split/associated
 associateIdxs idxs =
     map (\(gdx, (nl, il)) ->
              (gdx, (nl, il, filter (`Container.member` il) idxs)))
+
+-- | Compute the list of nodes that are to be evacuated, given a list
+-- of instances and an evacuation mode.
+nodesToEvacuate :: Instance.List -- ^ The cluster-wide instance list
+                -> EvacMode      -- ^ The evacuation mode we're using
+                -> [Idx]         -- ^ List of instance indices being evacuated
+                -> IntSet.IntSet -- ^ Set of node indices
+nodesToEvacuate il mode =
+    IntSet.delete Node.noSecondary .
+    foldl' (\ns idx ->
+                let i = Container.find idx il
+                    pdx = Instance.pNode i
+                    sdx = Instance.sNode i
+                    dt = Instance.diskTemplate i
+                    withSecondary = case dt of
+                                      DTDrbd8 -> IntSet.insert sdx ns
+                                      _ -> ns
+                in case mode of
+                     ChangePrimary   -> IntSet.insert pdx ns
+                     ChangeSecondary -> withSecondary
+                     ChangeAll       -> IntSet.insert pdx withSecondary
+           ) IntSet.empty