Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Node.hs @ 53f00b20

History | View | Annotate | Download (8.3 kB)

1
{-| Module describing a node.
2

    
3
    All updates are functional (copy-based) and return a new node with
4
    updated value.
5
-}
6

    
7
module Ganeti.HTools.Node
8
    (
9
      Node(failN1, idx, t_mem, n_mem, f_mem, t_dsk, f_dsk,
10
           p_mem, p_dsk, p_rem,
11
           plist, slist, offline)
12
    -- * Constructor
13
    , create
14
    -- ** Finalization after data loading
15
    , buildPeers
16
    , setIdx
17
    , setOffline
18
    , setXmem
19
    , setFmem
20
    -- * Instance (re)location
21
    , removePri
22
    , removeSec
23
    , addPri
24
    , addSec
25
    , setPri
26
    , setSec
27
    -- * Formatting
28
    , list
29
    ) where
30

    
31
import Data.List
32
import Text.Printf (printf)
33

    
34
import qualified Ganeti.HTools.Container as Container
35
import qualified Ganeti.HTools.Instance as Instance
36
import qualified Ganeti.HTools.PeerMap as PeerMap
37

    
38
import Ganeti.HTools.Utils
39

    
40
data Node = Node { t_mem :: Double -- ^ total memory (MiB)
41
                 , n_mem :: Int    -- ^ node memory (MiB)
42
                 , f_mem :: Int    -- ^ free memory (MiB)
43
                 , x_mem :: Int    -- ^ unaccounted memory (MiB)
44
                 , t_dsk :: Double -- ^ total disk space (MiB)
45
                 , f_dsk :: Int    -- ^ free disk space (MiB)
46
                 , plist :: [Int]  -- ^ list of primary instance indices
47
                 , slist :: [Int]  -- ^ list of secondary instance indices
48
                 , idx :: Int      -- ^ internal index for book-keeping
49
                 , peers :: PeerMap.PeerMap -- ^ pnode to instance mapping
50
                 , failN1:: Bool   -- ^ whether the node has failed n1
51
                 , r_mem :: Int    -- ^ maximum memory needed for
52
                                   -- failover by primaries of this node
53
                 , p_mem :: Double -- ^ percent of free memory
54
                 , p_dsk :: Double -- ^ percent of free disk
55
                 , p_rem :: Double -- ^ percent of reserved memory
56
                 , offline :: Bool -- ^ whether the node should not be used
57
                                   -- for allocations and skipped from
58
                                   -- score computations
59
  } deriving (Show)
60

    
61
{- | Create a new node.
62

    
63
The index and the peers maps are empty, and will be need to be update
64
later via the 'setIdx' and 'buildPeers' functions.
65

    
66
-}
67
create :: Double -> Int -> Int -> Double -> Int -> Node
68
create mem_t_init mem_n_init mem_f_init dsk_t_init dsk_f_init =
69
    Node
70
    {
71
      t_mem = mem_t_init,
72
      n_mem = mem_n_init,
73
      f_mem = mem_f_init,
74
      t_dsk = dsk_t_init,
75
      f_dsk = dsk_f_init,
76
      plist = [],
77
      slist = [],
78
      failN1 = True,
79
      idx = -1,
80
      peers = PeerMap.empty,
81
      r_mem = 0,
82
      p_mem = (fromIntegral mem_f_init) / mem_t_init,
83
      p_dsk = (fromIntegral dsk_f_init) / dsk_t_init,
84
      p_rem = 0,
85
      offline = False,
86
      x_mem = 0
87
    }
88

    
89
-- | Changes the index.
90
-- This is used only during the building of the data structures.
91
setIdx :: Node -> Int -> Node
92
setIdx t i = t {idx = i}
93

    
94
-- | Sets the offline attribute
95
setOffline :: Node -> Bool -> Node
96
setOffline t val = t { offline = val }
97

    
98
-- | Sets the unnaccounted memory
99
setXmem :: Node -> Int -> Node
100
setXmem t val = t { x_mem = val }
101

    
102
-- | Sets the free memory
103
setFmem :: Node -> Int -> Node
104
setFmem t val = t { f_mem = val }
105

    
106
-- | Given the rmem, free memory and disk, computes the failn1 status.
107
computeFailN1 :: Int -> Int -> Int -> Bool
108
computeFailN1 new_rmem new_mem new_dsk =
109
    new_mem <= new_rmem || new_dsk <= 0
110

    
111
-- | Given the new free memory and disk, fail if any of them is below zero.
112
failHealth :: Int -> Int -> Bool
113
failHealth new_mem new_dsk = new_mem <= 0 || new_dsk <= 0
114

    
115
-- | Computes the maximum reserved memory for peers from a peer map.
116
computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
117
computeMaxRes new_peers = PeerMap.maxElem new_peers
118

    
119
-- | Builds the peer map for a given node.
120
buildPeers :: Node -> Container.Container Instance.Instance -> Int -> Node
121
buildPeers t il num_nodes =
122
    let mdata = map
123
                (\i_idx -> let inst = Container.find i_idx il
124
                           in (Instance.pnode inst, Instance.mem inst))
125
                (slist t)
126
        pmap = PeerMap.accumArray (+) 0 (0, num_nodes - 1) mdata
127
        new_rmem = computeMaxRes pmap
128
        new_failN1 = computeFailN1 new_rmem (f_mem t) (f_dsk t)
129
        new_prem = (fromIntegral new_rmem) / (t_mem t)
130
    in t {peers=pmap, failN1 = new_failN1, r_mem = new_rmem, p_rem = new_prem}
131

    
132
-- | Removes a primary instance.
133
removePri :: Node -> Instance.Instance -> Node
134
removePri t inst =
135
    let iname = Instance.idx inst
136
        new_plist = delete iname (plist t)
137
        new_mem = f_mem t + Instance.mem inst
138
        new_dsk = f_dsk t + Instance.dsk inst
139
        new_mp = (fromIntegral new_mem) / (t_mem t)
140
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
141
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk
142
    in t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
143
          failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
144

    
145
-- | Removes a secondary instance.
146
removeSec :: Node -> Instance.Instance -> Node
147
removeSec t inst =
148
    let iname = Instance.idx inst
149
        pnode = Instance.pnode inst
150
        new_slist = delete iname (slist t)
151
        new_dsk = f_dsk t + Instance.dsk inst
152
        old_peers = peers t
153
        old_peem = PeerMap.find pnode old_peers
154
        new_peem =  old_peem - (Instance.mem inst)
155
        new_peers = PeerMap.add pnode new_peem old_peers
156
        old_rmem = r_mem t
157
        new_rmem = if old_peem < old_rmem then
158
                       old_rmem
159
                   else
160
                       computeMaxRes new_peers
161
        new_prem = (fromIntegral new_rmem) / (t_mem t)
162
        new_failn1 = computeFailN1 new_rmem (f_mem t) new_dsk
163
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
164
    in t {slist = new_slist, f_dsk = new_dsk, peers = new_peers,
165
          failN1 = new_failn1, r_mem = new_rmem, p_dsk = new_dp,
166
          p_rem = new_prem}
167

    
168
-- | Adds a primary instance.
169
addPri :: Node -> Instance.Instance -> Maybe Node
170
addPri t inst =
171
    let iname = Instance.idx inst
172
        new_mem = f_mem t - Instance.mem inst
173
        new_dsk = f_dsk t - Instance.dsk inst
174
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk in
175
      if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) then
176
        Nothing
177
      else
178
        let new_plist = iname:(plist t)
179
            new_mp = (fromIntegral new_mem) / (t_mem t)
180
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
181
        in
182
        Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
183
                failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
184

    
185
-- | Adds a secondary instance.
186
addSec :: Node -> Instance.Instance -> Int -> Maybe Node
187
addSec t inst pdx =
188
    let iname = Instance.idx inst
189
        old_peers = peers t
190
        old_mem = f_mem t
191
        new_dsk = f_dsk t - Instance.dsk inst
192
        new_peem = PeerMap.find pdx old_peers + Instance.mem inst
193
        new_peers = PeerMap.add pdx new_peem old_peers
194
        new_rmem = max (r_mem t) new_peem
195
        new_prem = (fromIntegral new_rmem) / (t_mem t)
196
        new_failn1 = computeFailN1 new_rmem old_mem new_dsk in
197
    if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) then
198
        Nothing
199
    else
200
        let new_slist = iname:(slist t)
201
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
202
        in
203
        Just t {slist = new_slist, f_dsk = new_dsk,
204
                peers = new_peers, failN1 = new_failn1,
205
                r_mem = new_rmem, p_dsk = new_dp,
206
                p_rem = new_prem}
207

    
208
-- | Add a primary instance to a node without other updates
209
setPri :: Node -> Int -> Node
210
setPri t idx = t { plist = idx:(plist t) }
211

    
212
-- | Add a secondary instance to a node without other updates
213
setSec :: Node -> Int -> Node
214
setSec t idx = t { slist = idx:(slist t) }
215

    
216
-- | String converter for the node list functionality.
217
list :: Int -> String -> Node -> String
218
list mname n t =
219
    let pl = plist t
220
        sl = slist t
221
        mp = p_mem t
222
        dp = p_dsk t
223
        off = offline t
224
        fn = failN1 t
225
        tmem = t_mem t
226
        nmem = n_mem t
227
        xmem = x_mem t
228
        fmem = f_mem t
229
        imem = (truncate tmem) - nmem - xmem - fmem
230
    in
231
      printf " %c %-*s %5.0f %5d %5d %5d %5d %5d %5.0f %5d %3d %3d %.5f %.5f"
232
                 (if off then '-' else if fn then '*' else ' ')
233
                 mname n tmem nmem imem xmem fmem (r_mem t)
234
                 ((t_dsk t) / 1024) ((f_dsk t) `div` 1024)
235
                 (length pl) (length sl)
236
                 mp dp