Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Node.hs @ 15f4c8ca

History | View | Annotate | Download (9.1 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
    ( Node(failN1, name, idx, t_mem, n_mem, f_mem, r_mem, t_dsk, f_dsk,
9
           p_mem, p_dsk, p_rem,
10
           plist, slist, offline)
11
    , List
12
    -- * Constructor
13
    , create
14
    -- ** Finalization after data loading
15
    , buildPeers
16
    , setIdx
17
    , setName
18
    , setOffline
19
    , setXmem
20
    , setFmem
21
    -- * Instance (re)location
22
    , removePri
23
    , removeSec
24
    , addPri
25
    , addSec
26
    , setPri
27
    , setSec
28
    -- * Formatting
29
    , list
30
    -- * Misc stuff
31
    , AssocList
32
    , noSecondary
33
    ) where
34

    
35
import Data.List
36
import Text.Printf (printf)
37

    
38
import qualified Ganeti.HTools.Container as Container
39
import qualified Ganeti.HTools.Instance as Instance
40
import qualified Ganeti.HTools.PeerMap as PeerMap
41

    
42
import qualified Ganeti.HTools.Types as T
43

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

    
66
instance T.Element Node where
67
    nameOf = name
68
    idxOf = idx
69
    setName = setName
70
    setIdx = setIdx
71

    
72
-- | A simple name for the int, node association list
73
type AssocList = [(T.Ndx, Node)]
74

    
75
-- | A simple name for a node map
76
type List = Container.Container Node
77

    
78
-- | Constant node index for a non-moveable instance
79
noSecondary :: T.Ndx
80
noSecondary = -1
81

    
82
{- | Create a new node.
83

    
84
The index and the peers maps are empty, and will be need to be update
85
later via the 'setIdx' and 'buildPeers' functions.
86

    
87
-}
88
create :: String -> Double -> Int -> Int -> Double -> Int -> Bool -> Node
89
create name_init mem_t_init mem_n_init mem_f_init
90
       dsk_t_init dsk_f_init offline_init =
91
    Node
92
    {
93
      name  = name_init,
94
      t_mem = mem_t_init,
95
      n_mem = mem_n_init,
96
      f_mem = mem_f_init,
97
      t_dsk = dsk_t_init,
98
      f_dsk = dsk_f_init,
99
      plist = [],
100
      slist = [],
101
      failN1 = True,
102
      idx = -1,
103
      peers = PeerMap.empty,
104
      r_mem = 0,
105
      p_mem = (fromIntegral mem_f_init) / mem_t_init,
106
      p_dsk = (fromIntegral dsk_f_init) / dsk_t_init,
107
      p_rem = 0,
108
      offline = offline_init,
109
      x_mem = 0
110
    }
111

    
112
-- | Changes the index.
113
-- This is used only during the building of the data structures.
114
setIdx :: Node -> T.Ndx -> Node
115
setIdx t i = t {idx = i}
116

    
117
-- | Changes the name
118
-- This is used only during the building of the data structures.
119
setName t s = t {name = s}
120

    
121
-- | Sets the offline attribute
122
setOffline :: Node -> Bool -> Node
123
setOffline t val = t { offline = val }
124

    
125
-- | Sets the unnaccounted memory
126
setXmem :: Node -> Int -> Node
127
setXmem t val = t { x_mem = val }
128

    
129
-- | Sets the free memory
130
setFmem :: Node -> Int -> Node
131
setFmem t new_mem =
132
    let new_n1 = computeFailN1 (r_mem t) new_mem (f_dsk t)
133
        new_mp = (fromIntegral new_mem) / (t_mem t)
134
    in
135
      t { f_mem = new_mem, failN1 = new_n1, p_mem = new_mp }
136

    
137
-- | Given the rmem, free memory and disk, computes the failn1 status.
138
computeFailN1 :: Int -> Int -> Int -> Bool
139
computeFailN1 new_rmem new_mem new_dsk =
140
    new_mem <= new_rmem || new_dsk <= 0
141

    
142
-- | Given the new free memory and disk, fail if any of them is below zero.
143
failHealth :: Int -> Int -> Bool
144
failHealth new_mem new_dsk = new_mem <= 0 || new_dsk <= 0
145

    
146
-- | Computes the maximum reserved memory for peers from a peer map.
147
computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
148
computeMaxRes new_peers = PeerMap.maxElem new_peers
149

    
150
-- | Builds the peer map for a given node.
151
buildPeers :: Node -> Instance.List -> Int -> Node
152
buildPeers t il num_nodes =
153
    let mdata = map
154
                (\i_idx -> let inst = Container.find i_idx il
155
                           in (Instance.pnode inst, Instance.mem inst))
156
                (slist t)
157
        pmap = PeerMap.accumArray (+) mdata
158
        new_rmem = computeMaxRes pmap
159
        new_failN1 = computeFailN1 new_rmem (f_mem t) (f_dsk t)
160
        new_prem = (fromIntegral new_rmem) / (t_mem t)
161
    in t {peers=pmap, failN1 = new_failN1, r_mem = new_rmem, p_rem = new_prem}
162

    
163
-- | Removes a primary instance.
164
removePri :: Node -> Instance.Instance -> Node
165
removePri t inst =
166
    let iname = Instance.idx inst
167
        new_plist = delete iname (plist t)
168
        new_mem = f_mem t + Instance.mem inst
169
        new_dsk = f_dsk t + Instance.dsk inst
170
        new_mp = (fromIntegral new_mem) / (t_mem t)
171
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
172
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk
173
    in t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
174
          failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
175

    
176
-- | Removes a secondary instance.
177
removeSec :: Node -> Instance.Instance -> Node
178
removeSec t inst =
179
    let iname = Instance.idx inst
180
        pnode = Instance.pnode inst
181
        new_slist = delete iname (slist t)
182
        new_dsk = f_dsk t + Instance.dsk inst
183
        old_peers = peers t
184
        old_peem = PeerMap.find pnode old_peers
185
        new_peem =  old_peem - (Instance.mem inst)
186
        new_peers = PeerMap.add pnode new_peem old_peers
187
        old_rmem = r_mem t
188
        new_rmem = if old_peem < old_rmem then
189
                       old_rmem
190
                   else
191
                       computeMaxRes new_peers
192
        new_prem = (fromIntegral new_rmem) / (t_mem t)
193
        new_failn1 = computeFailN1 new_rmem (f_mem t) new_dsk
194
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
195
    in t {slist = new_slist, f_dsk = new_dsk, peers = new_peers,
196
          failN1 = new_failn1, r_mem = new_rmem, p_dsk = new_dp,
197
          p_rem = new_prem}
198

    
199
-- | Adds a primary instance.
200
addPri :: Node -> Instance.Instance -> Maybe Node
201
addPri t inst =
202
    let iname = Instance.idx inst
203
        new_mem = f_mem t - Instance.mem inst
204
        new_dsk = f_dsk t - Instance.dsk inst
205
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk in
206
      if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) then
207
        Nothing
208
      else
209
        let new_plist = iname:(plist t)
210
            new_mp = (fromIntegral new_mem) / (t_mem t)
211
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
212
        in
213
        Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
214
                failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
215

    
216
-- | Adds a secondary instance.
217
addSec :: Node -> Instance.Instance -> T.Ndx -> Maybe Node
218
addSec t inst pdx =
219
    let iname = Instance.idx inst
220
        old_peers = peers t
221
        old_mem = f_mem t
222
        new_dsk = f_dsk t - Instance.dsk inst
223
        new_peem = PeerMap.find pdx old_peers + Instance.mem inst
224
        new_peers = PeerMap.add pdx new_peem old_peers
225
        new_rmem = max (r_mem t) new_peem
226
        new_prem = (fromIntegral new_rmem) / (t_mem t)
227
        new_failn1 = computeFailN1 new_rmem old_mem new_dsk in
228
    if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) then
229
        Nothing
230
    else
231
        let new_slist = iname:(slist t)
232
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
233
        in
234
        Just t {slist = new_slist, f_dsk = new_dsk,
235
                peers = new_peers, failN1 = new_failn1,
236
                r_mem = new_rmem, p_dsk = new_dp,
237
                p_rem = new_prem}
238

    
239
-- | Add a primary instance to a node without other updates
240
setPri :: Node -> T.Idx -> Node
241
setPri t idx = t { plist = idx:(plist t) }
242

    
243
-- | Add a secondary instance to a node without other updates
244
setSec :: Node -> T.Idx -> Node
245
setSec t idx = t { slist = idx:(slist t) }
246

    
247
-- | String converter for the node list functionality.
248
list :: Int -> Node -> String
249
list mname t =
250
    let pl = plist t
251
        sl = slist t
252
        mp = p_mem t
253
        dp = p_dsk t
254
        off = offline t
255
        fn = failN1 t
256
        tmem = t_mem t
257
        nmem = n_mem t
258
        xmem = x_mem t
259
        fmem = f_mem t
260
        imem = (truncate tmem) - nmem - xmem - fmem
261
    in
262
      printf " %c %-*s %5.0f %5d %5d %5d %5d %5d %5.0f %5d %3d %3d %.5f %.5f"
263
                 (if off then '-' else if fn then '*' else ' ')
264
                 mname (name t) tmem nmem imem xmem fmem (r_mem t)
265
                 ((t_dsk t) / 1024) ((f_dsk t) `div` 1024)
266
                 (length pl) (length sl)
267
                 mp dp