Revision ed41c179

b/Ganeti/HTools/IAlloc.hs
6 6
    (
7 7
      parseData
8 8
    , formatResponse
9
    , RqType(..)
10
    , Request(..)
9 11
    ) where
10 12

  
11 13
import Data.Either ()
......
22 24
import Ganeti.HTools.Types
23 25

  
24 26
data RqType
25
    = Allocate String Instance.Instance
26
    | Relocate Int
27
    = Allocate Instance.Instance Int
28
    | Relocate Int Int [Int]
27 29
    deriving (Show)
28 30

  
29 31
data Request = Request RqType NodeList InstanceList String
......
88 90
  let idata = fromJSObject ilist
89 91
  iobj <- (mapM (\(x,y) -> asJSObject y >>= parseInstance ktn x)) idata
90 92
  let (kti, il) = assignIndices iobj
93
  (map_n, map_i, csf) <- mergeData (nl, il)
94
  req_nodes <- fromObj "required_nodes" request
91 95
  optype <- fromObj "type" request
92 96
  rqtype <-
93 97
      case optype of
94 98
        "allocate" ->
95 99
            do
96 100
              inew <- parseBaseInstance rname request
97
              let (iname, io) = inew
98
              return $ Allocate iname io
101
              let io = snd inew
102
              return $ Allocate io req_nodes
99 103
        "relocate" ->
100 104
            do
101 105
              ridx <- lookupNode kti rname rname
102
              return $ Relocate ridx
106
              ex_nodes <- fromObj "relocate_from" request
107
              let ex_nodes' = map (stripSuffix $ length csf) ex_nodes
108
              ex_idex <- mapM (findByName map_n) ex_nodes'
109
              return $ Relocate ridx req_nodes ex_idex
103 110
        other -> fail $ ("Invalid request type '" ++ other ++ "'")
104
  (map_n, map_i, csf) <- mergeData (nl, il)
105 111
  return $ Request rqtype map_n map_i csf
106 112

  
107 113
formatResponse :: Bool -> String -> [String] -> String
b/Ganeti/HTools/Loader.hs
9 9
    , checkData
10 10
    , assignIndices
11 11
    , lookupNode
12
    , stripSuffix
12 13
    ) where
13 14

  
14 15
import Data.List
b/Ganeti/HTools/Types.hs
68 68
-- | Compute the maximum name length in an Element Container
69 69
cMaxNamelen :: (Element a) => Container.Container a -> Int
70 70
cMaxNamelen = maximum . map (length . name) . Container.elems
71

  
72
-- | Find an element by name in a Container; this is a very slow function
73
findByName :: (Element a, Monad m) =>
74
              Container.Container a -> String -> m Container.Key
75
findByName c n =
76
    let all_elems = Container.elems c
77
        result = filter ((== n) . name) all_elems
78
        nems = length result
79
    in
80
      if nems /= 1 then
81
          fail $ "Wrong number of elems (" ++ (show nems) ++
82
                   ") found with name " ++ n
83
      else
84
          return $ idx $ head result
b/hail.hs
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

Also available in: Unified diff