18 |
18 |
import qualified Ganeti.HTools.Container as Container
|
19 |
19 |
import qualified Ganeti.HTools.Cluster as Cluster
|
20 |
20 |
import qualified Ganeti.HTools.Node as Node
|
|
21 |
import qualified Ganeti.HTools.Instance as Instance
|
21 |
22 |
import qualified Ganeti.HTools.CLI as CLI
|
22 |
23 |
import Ganeti.HTools.IAlloc
|
23 |
24 |
import Ganeti.HTools.Utils
|
... | ... | |
112 |
113 |
"show help"
|
113 |
114 |
]
|
114 |
115 |
|
115 |
|
-- | Formats the solution for the oneline display
|
116 |
|
formatOneline :: Double -> Int -> Double -> String
|
117 |
|
formatOneline ini_cv plc_len fin_cv =
|
118 |
|
printf "%.8f %d %.8f %8.3f" ini_cv plc_len fin_cv
|
119 |
|
(if fin_cv == 0 then 1 else (ini_cv / fin_cv))
|
|
116 |
-- | Try to allocate an instance on the cluster
|
|
117 |
tryAlloc :: NodeList
|
|
118 |
-> InstanceList
|
|
119 |
-> Instance.Instance
|
|
120 |
-> Int
|
|
121 |
-> Result [Node.Node]
|
|
122 |
tryAlloc nl il xi _ = Bad "alloc not implemented"
|
|
123 |
|
|
124 |
-- | Try to allocate an instance on the cluster
|
|
125 |
tryReloc :: NodeList
|
|
126 |
-> InstanceList
|
|
127 |
-> Int
|
|
128 |
-> Int
|
|
129 |
-> [Int]
|
|
130 |
-> Result [Node.Node]
|
|
131 |
tryReloc nl il xid reqn ex_idx =
|
|
132 |
let all_nodes = Container.elems nl
|
|
133 |
valid_nodes = filter (not . flip elem ex_idx . idx) all_nodes
|
|
134 |
in Ok (take reqn valid_nodes)
|
120 |
135 |
|
121 |
136 |
-- | Main function.
|
122 |
137 |
main :: IO ()
|
... | ... | |
138 |
153 |
exitWith $ ExitFailure 1
|
139 |
154 |
Ok rq -> return rq
|
140 |
155 |
|
141 |
|
putStrLn $ show request
|
142 |
|
exitWith ExitSuccess
|
143 |
|
{-
|
144 |
|
(loaded_nl, il, csf, ktn, kti) <- liftM2 Cluster.loadData node_data inst_data
|
145 |
|
let (fix_msgs, fixed_nl) = Cluster.checkData loaded_nl il ktn kti
|
146 |
|
|
147 |
|
unless (null fix_msgs || verbose == 0) $ do
|
148 |
|
putStrLn "Warning: cluster has inconsistent data:"
|
149 |
|
putStrLn . unlines . map (\s -> printf " - %s" s) $ fix_msgs
|
150 |
|
|
151 |
|
let offline_names = optOffline opts
|
152 |
|
all_names = snd . unzip $ ktn
|
153 |
|
offline_wrong = filter (\n -> not $ elem n all_names) offline_names
|
154 |
|
offline_indices = fst . unzip .
|
155 |
|
filter (\(_, n) -> elem n offline_names) $ ktn
|
156 |
|
|
157 |
|
when (length offline_wrong > 0) $ do
|
158 |
|
printf "Wrong node name(s) set as offline: %s\n"
|
159 |
|
(commaJoin offline_wrong)
|
160 |
|
exitWith $ ExitFailure 1
|
161 |
|
|
162 |
|
let nl = Container.map (\n -> if elem (Node.idx n) offline_indices
|
163 |
|
then Node.setOffline n True
|
164 |
|
else n) fixed_nl
|
165 |
|
|
166 |
|
when (Container.size il == 0) $ do
|
167 |
|
(if oneline then
|
168 |
|
putStrLn $ formatOneline 0 0 0
|
169 |
|
else
|
170 |
|
printf "Cluster is empty, exiting.\n")
|
171 |
|
exitWith ExitSuccess
|
172 |
|
|
173 |
|
|
174 |
|
unless oneline $ printf "Loaded %d nodes, %d instances\n"
|
175 |
|
(Container.size nl)
|
176 |
|
(Container.size il)
|
177 |
|
|
178 |
|
when (length csf > 0 && not oneline && verbose > 1) $ do
|
179 |
|
printf "Note: Stripping common suffix of '%s' from names\n" csf
|
180 |
|
|
181 |
|
let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
|
182 |
|
unless (oneline || verbose == 0) $ printf
|
183 |
|
"Initial check done: %d bad nodes, %d bad instances.\n"
|
184 |
|
(length bad_nodes) (length bad_instances)
|
185 |
|
|
186 |
|
when (length bad_nodes > 0) $ do
|
187 |
|
putStrLn "Cluster is not N+1 happy, continuing but no guarantee \
|
188 |
|
\that the cluster will end N+1 happy."
|
189 |
|
|
190 |
|
when (optShowNodes opts) $
|
191 |
|
do
|
192 |
|
putStrLn "Initial cluster status:"
|
193 |
|
putStrLn $ Cluster.printNodes ktn nl
|
194 |
|
|
195 |
|
let ini_cv = Cluster.compCV nl
|
196 |
|
ini_tbl = Cluster.Table nl il ini_cv []
|
197 |
|
min_cv = optMinScore opts
|
198 |
|
|
199 |
|
when (ini_cv < min_cv) $ do
|
200 |
|
(if oneline then
|
201 |
|
putStrLn $ formatOneline ini_cv 0 ini_cv
|
202 |
|
else printf "Cluster is already well balanced (initial score %.6g,\n\
|
203 |
|
\minimum score %.6g).\nNothing to do, exiting\n"
|
204 |
|
ini_cv min_cv)
|
205 |
|
exitWith ExitSuccess
|
206 |
|
|
207 |
|
unless oneline (if verbose > 2 then
|
208 |
|
printf "Initial coefficients: overall %.8f, %s\n"
|
209 |
|
ini_cv (Cluster.printStats nl)
|
210 |
|
else
|
211 |
|
printf "Initial score: %.8f\n" ini_cv)
|
212 |
|
|
213 |
|
unless oneline $ putStrLn "Trying to minimize the CV..."
|
214 |
|
let mlen_fn = maximum . (map length) . snd . unzip
|
215 |
|
imlen = mlen_fn kti
|
216 |
|
nmlen = mlen_fn ktn
|
217 |
|
|
218 |
|
(fin_tbl, cmd_strs) <- iterateDepth ini_tbl (optMaxLength opts)
|
219 |
|
ktn kti nmlen imlen [] oneline min_cv
|
220 |
|
let (Cluster.Table fin_nl _ fin_cv fin_plc) = fin_tbl
|
221 |
|
ord_plc = reverse fin_plc
|
222 |
|
sol_msg = if null fin_plc
|
223 |
|
then printf "No solution found\n"
|
224 |
|
else (if verbose > 2
|
225 |
|
then printf "Final coefficients: overall %.8f, %s\n"
|
226 |
|
fin_cv (Cluster.printStats fin_nl)
|
227 |
|
else printf "Cluster score improved from %.8f to %.8f\n"
|
228 |
|
ini_cv fin_cv
|
229 |
|
)
|
230 |
|
|
231 |
|
unless oneline $ putStr sol_msg
|
232 |
|
|
233 |
|
unless (oneline || verbose == 0) $
|
234 |
|
printf "Solution length=%d\n" (length ord_plc)
|
235 |
|
|
236 |
|
let cmd_data = Cluster.formatCmds . reverse $ cmd_strs
|
237 |
|
|
238 |
|
when (isJust $ optShowCmds opts) $
|
239 |
|
do
|
240 |
|
let out_path = fromJust $ optShowCmds opts
|
241 |
|
putStrLn ""
|
242 |
|
(if out_path == "-" then
|
243 |
|
printf "Commands to run to reach the above solution:\n%s"
|
244 |
|
(unlines . map (" " ++) .
|
245 |
|
filter (/= "check") .
|
246 |
|
lines $ cmd_data)
|
247 |
|
else do
|
248 |
|
writeFile out_path (CLI.shTemplate ++ cmd_data)
|
249 |
|
printf "The commands have been written to file '%s'\n" out_path)
|
250 |
|
|
251 |
|
when (optShowNodes opts) $
|
252 |
|
do
|
253 |
|
let (orig_mem, orig_disk) = Cluster.totalResources nl
|
254 |
|
(final_mem, final_disk) = Cluster.totalResources fin_nl
|
255 |
|
putStrLn ""
|
256 |
|
putStrLn "Final cluster status:"
|
257 |
|
putStrLn $ Cluster.printNodes ktn fin_nl
|
258 |
|
when (verbose > 3) $
|
259 |
|
do
|
260 |
|
printf "Original: mem=%d disk=%d\n" orig_mem orig_disk
|
261 |
|
printf "Final: mem=%d disk=%d\n" final_mem final_disk
|
262 |
|
when oneline $
|
263 |
|
putStrLn $ formatOneline ini_cv (length ord_plc) fin_cv
|
264 |
|
-}
|
|
156 |
let Request rqtype nl il csf = request
|
|
157 |
new_nodes = case rqtype of
|
|
158 |
Allocate xi reqn -> tryAlloc nl il xi reqn
|
|
159 |
Relocate idx reqn exnodes ->
|
|
160 |
tryReloc nl il idx reqn exnodes
|
|
161 |
let (ok, info, rn) = case new_nodes of
|
|
162 |
Ok sn -> (True, "Request successfull", map name sn)
|
|
163 |
Bad s -> (False, "Request failed: " ++ s, [])
|
|
164 |
resp = formatResponse ok info rn
|
|
165 |
putStrLn resp
|