Revision 525bfb36 htools/Ganeti/HTools/Cluster.hs

b/htools/Ganeti/HTools/Cluster.hs
1 1
{-| Implementation of cluster-wide logic.
2 2

  
3 3
This module holds all pure cluster-logic; I\/O related functionality
4
goes into the "Main" module for the individual binaries.
4
goes into the /Main/ module for the individual binaries.
5 5

  
6 6
-}
7 7

  
......
106 106

  
107 107

  
108 108
-- | A type denoting the valid allocation mode/pairs.
109
--
109 110
-- For a one-node allocation, this will be a @Left ['Node.Node']@,
110 111
-- whereas for a two-node allocation, this will be a @Right
111 112
-- [('Node.Node', 'Node.Node')]@.
112 113
type AllocNodes = Either [Ndx] [(Ndx, Ndx)]
113 114

  
114
-- | The empty solution we start with when computing allocations
115
-- | The empty solution we start with when computing allocations.
115 116
emptySolution :: AllocSolution
116 117
emptySolution = AllocSolution { asFailures = [], asAllocs = 0
117 118
                              , asSolutions = [], asLog = [] }
118 119

  
119
-- | The complete state for the balancing solution
120
-- | The complete state for the balancing solution.
120 121
data Table = Table Node.List Instance.List Score [Placement]
121 122
             deriving (Show, Read)
122 123

  
......
144 145
                     }
145 146
            deriving (Show, Read)
146 147

  
147
-- | Currently used, possibly to allocate, unallocable
148
-- | Currently used, possibly to allocate, unallocable.
148 149
type AllocStats = (RSpec, RSpec, RSpec)
149 150

  
150 151
-- * Utility functions
......
170 171
  in
171 172
    (bad_nodes, bad_instances)
172 173

  
173
-- | Zero-initializer for the CStats type
174
-- | Zero-initializer for the CStats type.
174 175
emptyCStats :: CStats
175 176
emptyCStats = CStats 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
176 177

  
177
-- | Update stats with data from a new node
178
-- | Update stats with data from a new node.
178 179
updateCStats :: CStats -> Node.Node -> CStats
179 180
updateCStats cs node =
180 181
    let CStats { csFmem = x_fmem, csFdsk = x_fdsk,
......
243 244
               (truncate t_dsk - fromIntegral f_idsk)
244 245
    in (rini, rfin, runa)
245 246

  
246
-- | The names and weights of the individual elements in the CV list
247
-- | The names and weights of the individual elements in the CV list.
247 248
detailedCVInfo :: [(Double, String)]
248 249
detailedCVInfo = [ (1,  "free_mem_cv")
249 250
                 , (1,  "free_disk_cv")
......
311 312
compCV :: Node.List -> Double
312 313
compCV = sum . zipWith (*) detailedCVWeights . compDetailedCV
313 314

  
314
-- | Compute online nodes from a Node.List
315
-- | Compute online nodes from a 'Node.List'.
315 316
getOnline :: Node.List -> [Node.Node]
316 317
getOnline = filter (not . Node.offline) . Container.elems
317 318

  
318
-- * hbal functions
319
-- * Balancing functions
319 320

  
320 321
-- | Compute best table. Note that the ordering of the arguments is important.
321 322
compareTables :: Table -> Table -> Table
......
534 535
       then ini_tbl -- no advancement
535 536
       else best_tbl
536 537

  
537
-- | Check if we are allowed to go deeper in the balancing
538
-- | Check if we are allowed to go deeper in the balancing.
538 539
doNextBalance :: Table     -- ^ The starting table
539 540
              -> Int       -- ^ Remaining length
540 541
              -> Score     -- ^ Score at which to stop
......
544 545
        ini_plc_len = length ini_plc
545 546
    in (max_rounds < 0 || ini_plc_len < max_rounds) && ini_cv > min_score
546 547

  
547
-- | Run a balance move
548
-- | Run a balance move.
548 549
tryBalance :: Table       -- ^ The starting table
549 550
           -> Bool        -- ^ Allow disk moves
550 551
           -> Bool        -- ^ Allow instance moves
......
574 575

  
575 576
-- * Allocation functions
576 577

  
577
-- | Build failure stats out of a list of failures
578
-- | Build failure stats out of a list of failures.
578 579
collapseFailures :: [FailMode] -> FailStats
579 580
collapseFailures flst =
580 581
    map (\k -> (k, length $ filter (k ==) flst)) [minBound..maxBound]
581 582

  
582 583
-- | Update current Allocation solution and failure stats with new
583
-- elements
584
-- elements.
584 585
concatAllocs :: AllocSolution -> OpResult Node.AllocElement -> AllocSolution
585 586
concatAllocs as (OpFail reason) = as { asFailures = reason : asFailures as }
586 587

  
......
611 612
sumAllocs (AllocSolution af aa as al) (AllocSolution bf ba bs bl) =
612 613
    AllocSolution (af ++ bf) (aa + ba) (as ++ bs) (al ++ bl)
613 614

  
614
-- | Given a solution, generates a reasonable description for it
615
-- | Given a solution, generates a reasonable description for it.
615 616
describeSolution :: AllocSolution -> String
616 617
describeSolution as =
617 618
  let fcnt = asFailures as
......
629 630
                     " for node(s) %s") cv (asAllocs as) (length fcnt) freasons
630 631
             (intercalate "/" . map Node.name $ nodes)
631 632

  
632
-- | Annotates a solution with the appropriate string
633
-- | Annotates a solution with the appropriate string.
633 634
annotateSolution :: AllocSolution -> AllocSolution
634 635
annotateSolution as = as { asLog = describeSolution as : asLog as }
635 636

  
......
678 679
       then fail "No online nodes"
679 680
       else return $ annotateSolution sols
680 681

  
681
-- | Given a group/result, describe it as a nice (list of) messages
682
-- | Given a group/result, describe it as a nice (list of) messages.
682 683
solutionDescription :: Group.List -> (Gdx, Result AllocSolution) -> [String]
683 684
solutionDescription gl (groupId, result) =
684 685
  case result of
......
690 691

  
691 692
-- | From a list of possibly bad and possibly empty solutions, filter
692 693
-- only the groups with a valid result. Note that the result will be
693
-- reversed compared to the original list
694
-- reversed compared to the original list.
694 695
filterMGResults :: Group.List
695 696
                -> [(Gdx, Result AllocSolution)]
696 697
                -> [(Gdx, AllocSolution)]
......
703 704
                       | unallocable gdx -> accu
704 705
                       | otherwise -> (gdx, sol):accu
705 706

  
706
-- | Sort multigroup results based on policy and score
707
-- | Sort multigroup results based on policy and score.
707 708
sortMGResults :: Group.List
708 709
             -> [(Gdx, AllocSolution)]
709 710
             -> [(Gdx, AllocSolution)]
......
782 783
                Just v -> return v
783 784
  tryReloc nl il xid ncount ex_ndx
784 785

  
785
-- | Change an instance's secondary node
786
-- | Change an instance's secondary node.
786 787
evacInstance :: (Monad m) =>
787 788
                [Ndx]                      -- ^ Excluded nodes
788 789
             -> Instance.List              -- ^ The current instance list
......
854 855
      let sol = foldl' sumAllocs emptySolution results
855 856
      return $ annotateSolution sol
856 857

  
857
-- | Recursively place instances on the cluster until we're out of space
858
-- | Recursively place instances on the cluster until we're out of space.
858 859
iterateAlloc :: Node.List
859 860
             -> Instance.List
860 861
             -> Instance.Instance
......
879 880
                 _ -> Bad "Internal error: multiple solutions for single\
880 881
                          \ allocation"
881 882

  
882
-- | The core of the tiered allocation mode
883
-- | The core of the tiered allocation mode.
883 884
tieredAlloc :: Node.List
884 885
            -> Instance.List
885 886
            -> Instance.Instance
......
1072 1073

  
1073 1074
-- * Node group functions
1074 1075

  
1075
-- | Computes the group of an instance
1076
-- | Computes the group of an instance.
1076 1077
instanceGroup :: Node.List -> Instance.Instance -> Result Gdx
1077 1078
instanceGroup nl i =
1078 1079
  let sidx = Instance.sNode i
......
1087 1088
                show pgroup ++ ", secondary " ++ show sgroup)
1088 1089
     else return pgroup
1089 1090

  
1090
-- | Computes the group of an instance per the primary node
1091
-- | Computes the group of an instance per the primary node.
1091 1092
instancePriGroup :: Node.List -> Instance.Instance -> Gdx
1092 1093
instancePriGroup nl i =
1093 1094
  let pnode = Container.find (Instance.pNode i) nl
1094 1095
  in  Node.group pnode
1095 1096

  
1096 1097
-- | Compute the list of badly allocated instances (split across node
1097
-- groups)
1098
-- groups).
1098 1099
findSplitInstances :: Node.List -> Instance.List -> [Instance.Instance]
1099 1100
findSplitInstances nl =
1100 1101
  filter (not . isOk . instanceGroup nl) . Container.elems
1101 1102

  
1102
-- | Splits a cluster into the component node groups
1103
-- | Splits a cluster into the component node groups.
1103 1104
splitCluster :: Node.List -> Instance.List ->
1104 1105
                [(Gdx, (Node.List, Instance.List))]
1105 1106
splitCluster nl il =

Also available in: Unified diff