root / src / Ganeti / HTools / Program / Hsqueeze.hs @ a5efec93
History | View | Annotate | Download (10.4 kB)
1 | 5f6e9cb9 | Klaus Aehlig | {-| Node freeing scheduler |
---|---|---|---|
2 | 5f6e9cb9 | Klaus Aehlig | |
3 | 5f6e9cb9 | Klaus Aehlig | -} |
4 | 5f6e9cb9 | Klaus Aehlig | |
5 | 5f6e9cb9 | Klaus Aehlig | {- |
6 | 5f6e9cb9 | Klaus Aehlig | |
7 | 5f6e9cb9 | Klaus Aehlig | Copyright (C) 2013 Google Inc. |
8 | 5f6e9cb9 | Klaus Aehlig | |
9 | 5f6e9cb9 | Klaus Aehlig | This program is free software; you can redistribute it and/or modify |
10 | 5f6e9cb9 | Klaus Aehlig | it under the terms of the GNU General Public License as published by |
11 | 5f6e9cb9 | Klaus Aehlig | the Free Software Foundation; either version 2 of the License, or |
12 | 5f6e9cb9 | Klaus Aehlig | (at your option) any later version. |
13 | 5f6e9cb9 | Klaus Aehlig | |
14 | 5f6e9cb9 | Klaus Aehlig | This program is distributed in the hope that it will be useful, but |
15 | 5f6e9cb9 | Klaus Aehlig | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | 5f6e9cb9 | Klaus Aehlig | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | 5f6e9cb9 | Klaus Aehlig | General Public License for more details. |
18 | 5f6e9cb9 | Klaus Aehlig | |
19 | 5f6e9cb9 | Klaus Aehlig | You should have received a copy of the GNU General Public License |
20 | 5f6e9cb9 | Klaus Aehlig | along with this program; if not, write to the Free Software |
21 | 5f6e9cb9 | Klaus Aehlig | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
22 | 5f6e9cb9 | Klaus Aehlig | 02110-1301, USA. |
23 | 5f6e9cb9 | Klaus Aehlig | |
24 | 5f6e9cb9 | Klaus Aehlig | -} |
25 | 5f6e9cb9 | Klaus Aehlig | |
26 | 5f6e9cb9 | Klaus Aehlig | module Ganeti.HTools.Program.Hsqueeze |
27 | 5f6e9cb9 | Klaus Aehlig | (main |
28 | 5f6e9cb9 | Klaus Aehlig | , options |
29 | 5f6e9cb9 | Klaus Aehlig | , arguments |
30 | 5f6e9cb9 | Klaus Aehlig | ) where |
31 | 5f6e9cb9 | Klaus Aehlig | |
32 | 5f6e9cb9 | Klaus Aehlig | import Control.Applicative |
33 | 5f6e9cb9 | Klaus Aehlig | import Control.Monad |
34 | 5f6e9cb9 | Klaus Aehlig | import Data.Function |
35 | 5f6e9cb9 | Klaus Aehlig | import Data.List |
36 | 5f6e9cb9 | Klaus Aehlig | import Data.Maybe |
37 | 5f6e9cb9 | Klaus Aehlig | import qualified Data.IntMap as IntMap |
38 | 268fb0bd | Klaus Aehlig | import Text.Printf (printf) |
39 | 5f6e9cb9 | Klaus Aehlig | |
40 | 5f6e9cb9 | Klaus Aehlig | import Ganeti.BasicTypes |
41 | 5f6e9cb9 | Klaus Aehlig | import Ganeti.Common |
42 | 5f6e9cb9 | Klaus Aehlig | import Ganeti.HTools.CLI |
43 | 5f6e9cb9 | Klaus Aehlig | import qualified Ganeti.HTools.Container as Container |
44 | 5f6e9cb9 | Klaus Aehlig | import qualified Ganeti.HTools.Cluster as Cluster |
45 | 5f6e9cb9 | Klaus Aehlig | import Ganeti.HTools.ExtLoader |
46 | 5f6e9cb9 | Klaus Aehlig | import qualified Ganeti.HTools.Instance as Instance |
47 | 5f6e9cb9 | Klaus Aehlig | import Ganeti.HTools.Loader |
48 | 5f6e9cb9 | Klaus Aehlig | import qualified Ganeti.HTools.Node as Node |
49 | 5f6e9cb9 | Klaus Aehlig | import Ganeti.HTools.Types |
50 | 5f6e9cb9 | Klaus Aehlig | import Ganeti.Utils |
51 | 5f6e9cb9 | Klaus Aehlig | |
52 | 5f6e9cb9 | Klaus Aehlig | -- | Options list and functions. |
53 | 5f6e9cb9 | Klaus Aehlig | options :: IO [OptType] |
54 | 5f6e9cb9 | Klaus Aehlig | options = do |
55 | 5f6e9cb9 | Klaus Aehlig | luxi <- oLuxiSocket |
56 | 5f6e9cb9 | Klaus Aehlig | return |
57 | 5f6e9cb9 | Klaus Aehlig | [ luxi |
58 | 5f6e9cb9 | Klaus Aehlig | , oDataFile |
59 | c407510c | Klaus Aehlig | , oMinResources |
60 | 5f6e9cb9 | Klaus Aehlig | , oTargetResources |
61 | 5f6e9cb9 | Klaus Aehlig | , oSaveCluster |
62 | 268fb0bd | Klaus Aehlig | , oPrintCommands |
63 | 5f6e9cb9 | Klaus Aehlig | , oVerbose |
64 | 5f6e9cb9 | Klaus Aehlig | , oNoHeaders |
65 | 5f6e9cb9 | Klaus Aehlig | ] |
66 | 5f6e9cb9 | Klaus Aehlig | |
67 | 5f6e9cb9 | Klaus Aehlig | -- | The list of arguments supported by the program. |
68 | 5f6e9cb9 | Klaus Aehlig | arguments :: [ArgCompletion] |
69 | 5f6e9cb9 | Klaus Aehlig | arguments = [] |
70 | 5f6e9cb9 | Klaus Aehlig | |
71 | c407510c | Klaus Aehlig | -- | The tag-prefix indicating that hsqueeze should consider a node |
72 | c407510c | Klaus Aehlig | -- as being standby. |
73 | c407510c | Klaus Aehlig | standbyPrefix :: String |
74 | c407510c | Klaus Aehlig | standbyPrefix = "htools:standby:" |
75 | c407510c | Klaus Aehlig | |
76 | c407510c | Klaus Aehlig | -- | Predicate of having a standby tag. |
77 | c407510c | Klaus Aehlig | hasStandbyTag :: Node.Node -> Bool |
78 | c407510c | Klaus Aehlig | hasStandbyTag = any (standbyPrefix `isPrefixOf`) . Node.nTags |
79 | c407510c | Klaus Aehlig | |
80 | 5f6e9cb9 | Klaus Aehlig | -- | Within a cluster configuration, decide if the node hosts only |
81 | 5f6e9cb9 | Klaus Aehlig | -- externally-mirrored instances. |
82 | 5f6e9cb9 | Klaus Aehlig | onlyExternal :: (Node.List, Instance.List) -> Node.Node -> Bool |
83 | 5f6e9cb9 | Klaus Aehlig | onlyExternal (_, il) nd = |
84 | 5f6e9cb9 | Klaus Aehlig | not |
85 | 5f6e9cb9 | Klaus Aehlig | . any (Instance.usesLocalStorage . flip Container.find il) |
86 | 5f6e9cb9 | Klaus Aehlig | $ Node.pList nd |
87 | 5f6e9cb9 | Klaus Aehlig | |
88 | 2a58a7b1 | Klaus Aehlig | -- | Predicate of not being secondary node for any instance |
89 | 2a58a7b1 | Klaus Aehlig | noSecondaries :: Node.Node -> Bool |
90 | 2a58a7b1 | Klaus Aehlig | noSecondaries = null . Node.sList |
91 | 2a58a7b1 | Klaus Aehlig | |
92 | 5f6e9cb9 | Klaus Aehlig | -- | Predicate whether, in a configuration, all running instances are on |
93 | 5f6e9cb9 | Klaus Aehlig | -- online nodes. |
94 | 5f6e9cb9 | Klaus Aehlig | allInstancesOnOnlineNodes :: (Node.List, Instance.List) -> Bool |
95 | 5f6e9cb9 | Klaus Aehlig | allInstancesOnOnlineNodes (nl, il) = |
96 | 5f6e9cb9 | Klaus Aehlig | all (not . Node.offline . flip Container.find nl . Instance.pNode) |
97 | 5f6e9cb9 | Klaus Aehlig | . IntMap.elems |
98 | 5f6e9cb9 | Klaus Aehlig | $ il |
99 | 5f6e9cb9 | Klaus Aehlig | |
100 | 5f6e9cb9 | Klaus Aehlig | -- | Predicate whether, in a configuration, each node has enough resources |
101 | 5f6e9cb9 | Klaus Aehlig | -- to additionally host the given instance. |
102 | 5f6e9cb9 | Klaus Aehlig | allNodesCapacityFor :: Instance.Instance -> (Node.List, Instance.List) -> Bool |
103 | 5f6e9cb9 | Klaus Aehlig | allNodesCapacityFor inst (nl, _) = |
104 | 5f6e9cb9 | Klaus Aehlig | all (isOk . flip Node.addPri inst) . IntMap.elems $ nl |
105 | 5f6e9cb9 | Klaus Aehlig | |
106 | 5f6e9cb9 | Klaus Aehlig | -- | Balance a configuration, possible for 0 steps, till no further improvement |
107 | 5f6e9cb9 | Klaus Aehlig | -- is possible. |
108 | bbc6620d | Klaus Aehlig | balance :: (Node.List, Instance.List) |
109 | bbc6620d | Klaus Aehlig | -> ((Node.List, Instance.List), [MoveJob]) |
110 | 5f6e9cb9 | Klaus Aehlig | balance (nl, il) = |
111 | 5f6e9cb9 | Klaus Aehlig | let ini_cv = Cluster.compCV nl |
112 | 5f6e9cb9 | Klaus Aehlig | ini_tbl = Cluster.Table nl il ini_cv [] |
113 | 5f6e9cb9 | Klaus Aehlig | balanceStep tbl = Cluster.tryBalance tbl True True False 0.0 0.0 |
114 | bbc6620d | Klaus Aehlig | bTables = map fromJust . takeWhile isJust |
115 | bbc6620d | Klaus Aehlig | $ iterate (>>= balanceStep) (Just ini_tbl) |
116 | bbc6620d | Klaus Aehlig | (Cluster.Table nl' il' _ _) = last bTables |
117 | bbc6620d | Klaus Aehlig | moves = zip bTables (drop 1 bTables) >>= Cluster.getMoves |
118 | bbc6620d | Klaus Aehlig | in ((nl', il'), reverse moves) |
119 | 5f6e9cb9 | Klaus Aehlig | |
120 | c407510c | Klaus Aehlig | -- | In a configuration, mark a node as online or offline. |
121 | c407510c | Klaus Aehlig | onlineOfflineNode :: Bool -> (Node.List, Instance.List) -> Ndx -> |
122 | c407510c | Klaus Aehlig | (Node.List, Instance.List) |
123 | c407510c | Klaus Aehlig | onlineOfflineNode offline (nl, il) ndx = |
124 | 5f6e9cb9 | Klaus Aehlig | let nd = Container.find ndx nl |
125 | c407510c | Klaus Aehlig | nd' = Node.setOffline nd offline |
126 | 5f6e9cb9 | Klaus Aehlig | nl' = Container.add ndx nd' nl |
127 | 5f6e9cb9 | Klaus Aehlig | in (nl', il) |
128 | 5f6e9cb9 | Klaus Aehlig | |
129 | c407510c | Klaus Aehlig | -- | Offline or online a list nodes, and return the state after a balancing |
130 | bbc6620d | Klaus Aehlig | -- attempt together with the sequence of moves that lead there. |
131 | c407510c | Klaus Aehlig | onlineOfflineNodes :: Bool -> [Ndx] -> (Node.List, Instance.List) |
132 | bbc6620d | Klaus Aehlig | -> ((Node.List, Instance.List), [MoveJob]) |
133 | c407510c | Klaus Aehlig | onlineOfflineNodes offline ndxs conf = |
134 | c407510c | Klaus Aehlig | let conf' = foldl (onlineOfflineNode offline) conf ndxs |
135 | 5f6e9cb9 | Klaus Aehlig | in balance conf' |
136 | 5f6e9cb9 | Klaus Aehlig | |
137 | bbc6620d | Klaus Aehlig | -- | Offline a list of nodes, and return the state after balancing with |
138 | bbc6620d | Klaus Aehlig | -- the sequence of moves that lead there. |
139 | c407510c | Klaus Aehlig | offlineNodes :: [Ndx] -> (Node.List, Instance.List) |
140 | bbc6620d | Klaus Aehlig | -> ((Node.List, Instance.List), [MoveJob]) |
141 | c407510c | Klaus Aehlig | offlineNodes = onlineOfflineNodes True |
142 | c407510c | Klaus Aehlig | |
143 | bbc6620d | Klaus Aehlig | -- | Online a list of nodes, and return the state after balancing with |
144 | bbc6620d | Klaus Aehlig | -- the sequence of moves that lead there. |
145 | c407510c | Klaus Aehlig | onlineNodes :: [Ndx] -> (Node.List, Instance.List) |
146 | bbc6620d | Klaus Aehlig | -> ((Node.List, Instance.List), [MoveJob]) |
147 | c407510c | Klaus Aehlig | onlineNodes = onlineOfflineNodes False |
148 | c407510c | Klaus Aehlig | |
149 | c407510c | Klaus Aehlig | -- | Predicate on whether a list of nodes can be offlined or onlined |
150 | c407510c | Klaus Aehlig | -- simultaneously in a given configuration, while still leaving enough |
151 | c407510c | Klaus Aehlig | -- capacity on every node for the given instance. |
152 | c407510c | Klaus Aehlig | canOnlineOffline :: Bool -> Instance.Instance -> (Node.List, Instance.List) |
153 | c407510c | Klaus Aehlig | -> [Node.Node] ->Bool |
154 | c407510c | Klaus Aehlig | canOnlineOffline offline inst conf nds = |
155 | bbc6620d | Klaus Aehlig | let conf' = fst $ onlineOfflineNodes offline (map Node.idx nds) conf |
156 | 5f6e9cb9 | Klaus Aehlig | in allInstancesOnOnlineNodes conf' && allNodesCapacityFor inst conf' |
157 | 5f6e9cb9 | Klaus Aehlig | |
158 | c407510c | Klaus Aehlig | -- | Predicate on whether a list of nodes can be offlined simultaneously. |
159 | c407510c | Klaus Aehlig | canOffline :: Instance.Instance -> (Node.List, Instance.List) -> |
160 | c407510c | Klaus Aehlig | [Node.Node] -> Bool |
161 | c407510c | Klaus Aehlig | canOffline = canOnlineOffline True |
162 | c407510c | Klaus Aehlig | |
163 | c407510c | Klaus Aehlig | -- | Predicate on whether onlining a list of nodes suffices to get enough |
164 | c407510c | Klaus Aehlig | -- free resources for given instance. |
165 | c407510c | Klaus Aehlig | sufficesOnline :: Instance.Instance -> (Node.List, Instance.List) |
166 | c407510c | Klaus Aehlig | -> [Node.Node] -> Bool |
167 | c407510c | Klaus Aehlig | sufficesOnline = canOnlineOffline False |
168 | c407510c | Klaus Aehlig | |
169 | 5f6e9cb9 | Klaus Aehlig | -- | Greedily offline the nodes, starting from the last element, and return |
170 | 5f6e9cb9 | Klaus Aehlig | -- the list of nodes that could simultaneously be offlined, while keeping |
171 | 5f6e9cb9 | Klaus Aehlig | -- the resources specified by an instance. |
172 | 5f6e9cb9 | Klaus Aehlig | greedyOfflineNodes :: Instance.Instance -> (Node.List, Instance.List) |
173 | 5f6e9cb9 | Klaus Aehlig | -> [Node.Node] -> [Node.Node] |
174 | 5f6e9cb9 | Klaus Aehlig | greedyOfflineNodes _ _ [] = [] |
175 | 5f6e9cb9 | Klaus Aehlig | greedyOfflineNodes inst conf (nd:nds) = |
176 | 5f6e9cb9 | Klaus Aehlig | let nds' = greedyOfflineNodes inst conf nds |
177 | c407510c | Klaus Aehlig | in if canOffline inst conf (nd:nds') then nd:nds' else nds' |
178 | c407510c | Klaus Aehlig | |
179 | c407510c | Klaus Aehlig | -- | Try to provide enough resources by onlining an initial segment of |
180 | c407510c | Klaus Aehlig | -- a list of nodes. Return Nothing, if even onlining all of them is not |
181 | c407510c | Klaus Aehlig | -- enough. |
182 | c407510c | Klaus Aehlig | tryOnline :: Instance.Instance -> (Node.List, Instance.List) -> [Node.Node] |
183 | c407510c | Klaus Aehlig | -> Maybe [Node.Node] |
184 | c407510c | Klaus Aehlig | tryOnline inst conf = listToMaybe . filter (sufficesOnline inst conf) . inits |
185 | 5f6e9cb9 | Klaus Aehlig | |
186 | 5f6e9cb9 | Klaus Aehlig | -- | From a specification, name, and factor create an instance that uses that |
187 | 5f6e9cb9 | Klaus Aehlig | -- factor times the specification, rounded down. |
188 | 5f6e9cb9 | Klaus Aehlig | instanceFromSpecAndFactor :: String -> Double -> ISpec -> Instance.Instance |
189 | 5f6e9cb9 | Klaus Aehlig | instanceFromSpecAndFactor name f spec = |
190 | 5f6e9cb9 | Klaus Aehlig | Instance.create name |
191 | 5f6e9cb9 | Klaus Aehlig | (floor (f * fromIntegral (iSpecMemorySize spec))) |
192 | 5f6e9cb9 | Klaus Aehlig | 0 [] |
193 | 5f6e9cb9 | Klaus Aehlig | (floor (f * fromIntegral (iSpecCpuCount spec))) |
194 | 5f6e9cb9 | Klaus Aehlig | Running [] False Node.noSecondary Node.noSecondary DTExt |
195 | 5f6e9cb9 | Klaus Aehlig | (floor (f * fromIntegral (iSpecSpindleUse spec))) |
196 | 5f6e9cb9 | Klaus Aehlig | [] |
197 | 5f6e9cb9 | Klaus Aehlig | |
198 | 5f6e9cb9 | Klaus Aehlig | -- | Main function. |
199 | 5f6e9cb9 | Klaus Aehlig | main :: Options -> [String] -> IO () |
200 | 5f6e9cb9 | Klaus Aehlig | main opts args = do |
201 | 5f6e9cb9 | Klaus Aehlig | unless (null args) $ exitErr "This program doesn't take any arguments." |
202 | 5f6e9cb9 | Klaus Aehlig | |
203 | 5f6e9cb9 | Klaus Aehlig | let verbose = optVerbose opts |
204 | 5f6e9cb9 | Klaus Aehlig | targetf = optTargetResources opts |
205 | c407510c | Klaus Aehlig | minf = optMinResources opts |
206 | 5f6e9cb9 | Klaus Aehlig | |
207 | 5f6e9cb9 | Klaus Aehlig | ini_cdata@(ClusterData _ nlf ilf _ ipol) <- loadExternalData opts |
208 | 5f6e9cb9 | Klaus Aehlig | |
209 | 5f6e9cb9 | Klaus Aehlig | maybeSaveData (optSaveCluster opts) "original" "before hsqueeze run" ini_cdata |
210 | 5f6e9cb9 | Klaus Aehlig | |
211 | c407510c | Klaus Aehlig | let nodelist = IntMap.elems nlf |
212 | c407510c | Klaus Aehlig | offlineCandidates = |
213 | 5f6e9cb9 | Klaus Aehlig | sortBy (flip compare `on` length . Node.pList) |
214 | 5f6e9cb9 | Klaus Aehlig | . filter (foldl (liftA2 (&&)) (const True) |
215 | 5f6e9cb9 | Klaus Aehlig | [ not . Node.offline |
216 | 5f6e9cb9 | Klaus Aehlig | , not . Node.isMaster |
217 | 2a58a7b1 | Klaus Aehlig | , noSecondaries |
218 | 5f6e9cb9 | Klaus Aehlig | , onlyExternal (nlf, ilf) |
219 | 5f6e9cb9 | Klaus Aehlig | ]) |
220 | c407510c | Klaus Aehlig | $ nodelist |
221 | c407510c | Klaus Aehlig | onlineCandidates = |
222 | c407510c | Klaus Aehlig | filter (liftA2 (&&) Node.offline hasStandbyTag) nodelist |
223 | 5f6e9cb9 | Klaus Aehlig | conf = (nlf, ilf) |
224 | 5f6e9cb9 | Klaus Aehlig | std = iPolicyStdSpec ipol |
225 | 5f6e9cb9 | Klaus Aehlig | targetInstance = instanceFromSpecAndFactor "targetInstance" targetf std |
226 | c407510c | Klaus Aehlig | minInstance = instanceFromSpecAndFactor "targetInstance" minf std |
227 | 5f6e9cb9 | Klaus Aehlig | toOffline = greedyOfflineNodes targetInstance conf offlineCandidates |
228 | 268fb0bd | Klaus Aehlig | ((fin_off_nl, fin_off_il), off_mvs) = |
229 | 268fb0bd | Klaus Aehlig | offlineNodes (map Node.idx toOffline) conf |
230 | c407510c | Klaus Aehlig | final_off_cdata = |
231 | c407510c | Klaus Aehlig | ini_cdata { cdNodes = fin_off_nl, cdInstances = fin_off_il } |
232 | 268fb0bd | Klaus Aehlig | off_jobs = Cluster.splitJobs off_mvs |
233 | 268fb0bd | Klaus Aehlig | off_cmd = |
234 | 268fb0bd | Klaus Aehlig | Cluster.formatCmds off_jobs |
235 | dcd54d32 | Klaus Aehlig | ++ "\necho Tagging Commands\n" |
236 | edd09726 | Klaus Aehlig | ++ (toOffline >>= printf " gnt-node add-tags %s htools:standby:auto\n" |
237 | edd09726 | Klaus Aehlig | . Node.alias) |
238 | 268fb0bd | Klaus Aehlig | ++ "\necho Power Commands\n" |
239 | 81879d92 | Klaus Aehlig | ++ (toOffline >>= printf " gnt-node power -f off %s\n" . Node.alias) |
240 | c407510c | Klaus Aehlig | toOnline = tryOnline minInstance conf onlineCandidates |
241 | c407510c | Klaus Aehlig | nodesToOnline = fromMaybe onlineCandidates toOnline |
242 | 268fb0bd | Klaus Aehlig | ((fin_on_nl, fin_on_il), on_mvs) = |
243 | 268fb0bd | Klaus Aehlig | onlineNodes (map Node.idx nodesToOnline) conf |
244 | c407510c | Klaus Aehlig | final_on_cdata = |
245 | c407510c | Klaus Aehlig | ini_cdata { cdNodes = fin_on_nl, cdInstances = fin_on_il } |
246 | 268fb0bd | Klaus Aehlig | on_jobs = Cluster.splitJobs on_mvs |
247 | 268fb0bd | Klaus Aehlig | on_cmd = |
248 | 268fb0bd | Klaus Aehlig | "echo Power Commands\n" |
249 | 81879d92 | Klaus Aehlig | ++ (nodesToOnline >>= printf " gnt-node power -f on %s\n" . Node.alias) |
250 | 268fb0bd | Klaus Aehlig | ++ Cluster.formatCmds on_jobs |
251 | 5f6e9cb9 | Klaus Aehlig | |
252 | 5f6e9cb9 | Klaus Aehlig | when (verbose > 1) . putStrLn |
253 | 5f6e9cb9 | Klaus Aehlig | $ "Offline candidates: " ++ commaJoin (map Node.name offlineCandidates) |
254 | 5f6e9cb9 | Klaus Aehlig | |
255 | c407510c | Klaus Aehlig | when (verbose > 1) . putStrLn |
256 | c407510c | Klaus Aehlig | $ "Online candidates: " ++ commaJoin (map Node.name onlineCandidates) |
257 | c407510c | Klaus Aehlig | |
258 | c407510c | Klaus Aehlig | if not (allNodesCapacityFor minInstance conf) |
259 | c407510c | Klaus Aehlig | then do |
260 | c407510c | Klaus Aehlig | unless (optNoHeaders opts) $ |
261 | c407510c | Klaus Aehlig | putStrLn "'Nodes to online'" |
262 | c407510c | Klaus Aehlig | mapM_ (putStrLn . Node.name) nodesToOnline |
263 | c407510c | Klaus Aehlig | when (verbose > 1 && isNothing toOnline) . putStrLn $ |
264 | c407510c | Klaus Aehlig | "Onlining all nodes will not yield enough capacity" |
265 | 268fb0bd | Klaus Aehlig | maybeSaveCommands "Commands to run:" opts on_cmd |
266 | c407510c | Klaus Aehlig | maybeSaveData (optSaveCluster opts) |
267 | c407510c | Klaus Aehlig | "squeezed" "after hsqueeze expansion" final_on_cdata |
268 | c407510c | Klaus Aehlig | else |
269 | c407510c | Klaus Aehlig | if null toOffline |
270 | c407510c | Klaus Aehlig | then do |
271 | c407510c | Klaus Aehlig | unless (optNoHeaders opts) $ |
272 | c407510c | Klaus Aehlig | putStrLn "'No action'" |
273 | 268fb0bd | Klaus Aehlig | maybeSaveCommands "Commands to run:" opts "echo Nothing to do" |
274 | c407510c | Klaus Aehlig | maybeSaveData (optSaveCluster opts) |
275 | c407510c | Klaus Aehlig | "squeezed" "after hsqueeze doing nothing" ini_cdata |
276 | c407510c | Klaus Aehlig | else do |
277 | c407510c | Klaus Aehlig | unless (optNoHeaders opts) $ |
278 | c407510c | Klaus Aehlig | putStrLn "'Nodes to offline'" |
279 | c407510c | Klaus Aehlig | mapM_ (putStrLn . Node.name) toOffline |
280 | 268fb0bd | Klaus Aehlig | maybeSaveCommands "Commands to run:" opts off_cmd |
281 | c407510c | Klaus Aehlig | maybeSaveData (optSaveCluster opts) |
282 | c407510c | Klaus Aehlig | "squeezed" "after hsqueeze run" final_off_cdata |