From 313fdabc5bd7b32e6e57e1d0a0cd57f8005607b5 Mon Sep 17 00:00:00 2001
From: Klaus Aehlig <aehlig@google.com>
Date: Thu, 2 May 2013 15:12:00 +0200
Subject: [PATCH] Add option to hroller to select nodes based on tags

Add option --node-tags to tell hroller to consider only nodes
with these tags. A use case would be a tag tracking on which
nodes the maintenance has not yet been carried out, e.g., if
rolling reboots are interleaved with other cluster operations.

Signed-off-by: Klaus Aehlig <aehlig@google.com>
Reviewed-by: Guido Trotter <ultrotter@google.com>
---
 man/hroller.rst                      |  5 +++++
 src/Ganeti/HTools/CLI.hs             | 10 ++++++++++
 src/Ganeti/HTools/Program/Hroller.hs | 12 ++++++++++--
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/man/hroller.rst b/man/hroller.rst
index 25ffa34b3..b96508b36 100644
--- a/man/hroller.rst
+++ b/man/hroller.rst
@@ -27,6 +27,8 @@ Algorithm options:
 
 **[ -O *name...* ]**
 
+**[ --node-tags** *tag,..* **]**
+
 Reporting options:
 
 **[ -v... | -q ]**
@@ -59,6 +61,9 @@ OPTIONS
 For a description of the standard options check **htools**\(7) and
 **hbal**\(1).
 
+\--node-tags *tag,...*
+  Restrict to nodes having at least one of the given tags.
+
 \--force
   Do not fail, even if the master node cannot be determined.
 
diff --git a/src/Ganeti/HTools/CLI.hs b/src/Ganeti/HTools/CLI.hs
index 8f55f6fb4..80fa89f64 100644
--- a/src/Ganeti/HTools/CLI.hs
+++ b/src/Ganeti/HTools/CLI.hs
@@ -69,6 +69,7 @@ module Ganeti.HTools.CLI
   , oNoHeaders
   , oNoSimulation
   , oNodeSim
+  , oNodeTags
   , oOfflineNode
   , oOutputDir
   , oPrintCommands
@@ -135,6 +136,7 @@ data Options = Options
   , optNoHeaders   :: Bool           -- ^ Do not show a header line
   , optNoSimulation :: Bool          -- ^ Skip the rebalancing dry-run
   , optNodeSim     :: [String]       -- ^ Cluster simulation mode
+  , optNodeTags    :: Maybe [String] -- ^ List of node tags to restrict to 
   , optOffline     :: [String]       -- ^ Names of offline nodes
   , optOutPath     :: FilePath       -- ^ Path to the output directory
   , optSaveCluster :: Maybe FilePath -- ^ Save cluster state to this file
@@ -182,6 +184,7 @@ defaultOptions  = Options
   , optNoHeaders   = False
   , optNoSimulation = False
   , optNodeSim     = []
+  , optNodeTags    = Nothing
   , optOffline     = []
   , optOutPath     = "."
   , optSaveCluster = Nothing
@@ -452,6 +455,13 @@ oNodeSim =
    \ 'alloc_policy,num_nodes,disk,ram,cpu'",
    OptComplString)
 
+oNodeTags :: OptType
+oNodeTags =
+  (Option "" ["node-tags"]
+   (ReqArg (\ f opts -> Ok opts { optNodeTags = Just $ sepSplit ',' f })
+    "TAG,...") "Restrict to nodes with the given tags",
+   OptComplString)
+     
 oOfflineNode :: OptType
 oOfflineNode =
   (Option "O" ["offline"]
diff --git a/src/Ganeti/HTools/Program/Hroller.hs b/src/Ganeti/HTools/Program/Hroller.hs
index 98aa30f13..356cea5b8 100644
--- a/src/Ganeti/HTools/Program/Hroller.hs
+++ b/src/Ganeti/HTools/Program/Hroller.hs
@@ -60,6 +60,7 @@ options = do
     , oVerbose
     , oQuiet
     , oNoHeaders
+    , oNodeTags
     , oSaveCluster
     , oGroup
     , oForce
@@ -92,6 +93,11 @@ hasGroup :: Maybe Group.Group -> Node.Node -> Bool
 hasGroup Nothing _ = True
 hasGroup (Just grp) node = Node.group node == Group.idx grp 
 
+-- | Predicate of having at least one tag in a given set.
+hasTag :: Maybe [String] -> Node.Node -> Bool
+hasTag Nothing _ = True
+hasTag (Just tags) node = not . null $ Node.nTags node `intersect` tags
+
 -- | Put the master node last.
 -- Reorder a list of lists of nodes such that the master node (if present)
 -- is the last node of the last group.
@@ -130,8 +136,10 @@ main opts args = do
       Nothing -> exitErr "Cannot find target group."
       Just grp -> return (Just grp)
 
-  let nodes = IntMap.filter
-              (liftA2 (&&) (not . Node.offline) (hasGroup wantedGroup))
+  let nodes = IntMap.filter (foldl (liftA2 (&&)) (const True)
+                             [ (not . Node.offline) 
+                             , (hasTag $ optNodeTags opts)
+                             , hasGroup wantedGroup ])
               nlf
 
   -- TODO: fail if instances are running (with option to warn only)
-- 
GitLab