Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Node.hs @ b0517d61

History | View | Annotate | Download (8.5 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 new_mem =
105
    let new_n1 = computeFailN1 (r_mem t) new_mem (f_dsk t)
106
        new_mp = (fromIntegral new_mem) / (t_mem t)
107
    in
108
      t { f_mem = new_mem, failN1 = new_n1, p_mem = new_mp }
109

    
110
-- | Given the rmem, free memory and disk, computes the failn1 status.
111
computeFailN1 :: Int -> Int -> Int -> Bool
112
computeFailN1 new_rmem new_mem new_dsk =
113
    new_mem <= new_rmem || new_dsk <= 0
114

    
115
-- | Given the new free memory and disk, fail if any of them is below zero.
116
failHealth :: Int -> Int -> Bool
117
failHealth new_mem new_dsk = new_mem <= 0 || new_dsk <= 0
118

    
119
-- | Computes the maximum reserved memory for peers from a peer map.
120
computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
121
computeMaxRes new_peers = PeerMap.maxElem new_peers
122

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

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

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

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

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

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

    
216
-- | Add a secondary instance to a node without other updates
217
setSec :: Node -> Int -> Node
218
setSec t idx = t { slist = idx:(slist t) }
219

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