Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Loader.hs @ 497e30a1

History | View | Annotate | Download (3.5 kB)

1
{-| Loading data from external sources
2

    
3
This module holds the common code for loading the cluster state from external sources.
4

    
5
-}
6

    
7
module Ganeti.HTools.Loader
8
    where
9

    
10
import Data.List
11
import Data.Maybe (isNothing, fromJust)
12

    
13
import qualified Ganeti.HTools.Container as Container
14
import qualified Ganeti.HTools.Instance as Instance
15
import qualified Ganeti.HTools.Node as Node
16

    
17
import Ganeti.HTools.Types
18

    
19

    
20
-- | Swap a list of @(a, b)@ into @(b, a)@
21
swapPairs :: [(a, b)] -> [(b, a)]
22
swapPairs = map (\ (a, b) -> (b, a))
23

    
24
-- | Lookups a node into an assoc list
25
lookupNode :: (Monad m) => NameAssoc -> String -> String -> m Int
26
lookupNode ktn inst node =
27
    case lookup node ktn of
28
      Nothing -> fail $ "Unknown node '" ++ node ++ "' for instance " ++ inst
29
      Just idx -> return idx
30

    
31
assignIndices :: (Element a) =>
32
                 [(String, a)]
33
              -> (NameAssoc, [(Int, a)])
34
assignIndices =
35
    unzip . map (\ (idx, (k, v)) -> ((k, idx), (idx, setIdx v idx)))
36
          . zip [0..]
37

    
38
-- | For each instance, add its index to its primary and secondary nodes
39
fixNodes :: [(Int, Node.Node)]
40
         -> [(Int, Instance.Instance)]
41
         -> [(Int, Node.Node)]
42
fixNodes nl il =
43
    foldl' (\accu (idx, inst) ->
44
                let
45
                    assocEqual = (\ (i, _) (j, _) -> i == j)
46
                    pdx = Instance.pnode inst
47
                    sdx = Instance.snode inst
48
                    pold = fromJust $ lookup pdx accu
49
                    pnew = Node.setPri pold idx
50
                    ac1 = deleteBy assocEqual (pdx, pold) accu
51
                    ac2 = (pdx, pnew):ac1
52
                in
53
                  if sdx /= Node.noSecondary then
54
                      let
55
                          sold = fromJust $ lookup sdx accu
56
                          snew = Node.setSec sold idx
57
                          ac3 = deleteBy assocEqual (sdx, sold) ac2
58
                          ac4 = (sdx, snew):ac3
59
                      in ac4
60
                  else
61
                      ac2
62
           ) nl il
63

    
64
-- | Compute the longest common suffix of a NameList list that
65
-- | starts with a dot
66
longestDomain :: NameList -> String
67
longestDomain [] = ""
68
longestDomain ((_,x):xs) =
69
    let
70
        onlyStrings = snd $ unzip xs
71
    in
72
      foldr (\ suffix accu -> if all (isSuffixOf suffix) onlyStrings
73
                              then suffix
74
                              else accu)
75
      "" $ filter (isPrefixOf ".") (tails x)
76

    
77
-- | Remove tails from the (Int, String) lists
78
stripSuffix :: String -> NameList -> NameList
79
stripSuffix suffix lst =
80
    let sflen = length suffix in
81
    map (\ (key, name) -> (key, take ((length name) - sflen) name)) lst
82

    
83
{-| Initializer function that loads the data from a node and list file
84
    and massages it into the correct format. -}
85
mergeData :: ([(String, Int)], Node.AssocList,
86
              [(String, Int)], Instance.AssocList) -- ^ Data from either
87
                                                   -- Text.loadData
88
                                                   -- or Rapi.loadData
89
          -> Result (NodeList, InstanceList, String, NameList, NameList)
90
mergeData (ktn, nl, kti, il) = do
91
  let
92
      nl2 = fixNodes nl il
93
      il3 = Container.fromAssocList il
94
      nl3 = Container.fromAssocList
95
            (map (\ (k, v) -> (k, Node.buildPeers v il3 (length nl2))) nl2)
96
      xtn = swapPairs ktn
97
      xti = swapPairs kti
98
      common_suffix = longestDomain (xti ++ xtn)
99
      stn = stripSuffix common_suffix xtn
100
      sti = stripSuffix common_suffix xti
101
  return (nl3, il3, common_suffix, stn, sti)