Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Node.hs @ 9188aeef

History | View | Annotate | Download (9.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
    ( 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
    , setPri
22
    , setSec
23
    -- * Instance (re)location
24
    , removePri
25
    , removeSec
26
    , addPri
27
    , addSec
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
-- * Type declarations
45

    
46
-- | The node type.
47
data Node = Node { name  :: String -- ^ The node name
48
                 , t_mem :: Double -- ^ Total memory (MiB)
49
                 , n_mem :: Int    -- ^ Node memory (MiB)
50
                 , f_mem :: Int    -- ^ Free memory (MiB)
51
                 , x_mem :: Int    -- ^ Unaccounted memory (MiB)
52
                 , t_dsk :: Double -- ^ Total disk space (MiB)
53
                 , f_dsk :: Int    -- ^ Free disk space (MiB)
54
                 , plist :: [T.Idx]-- ^ List of primary instance indices
55
                 , slist :: [T.Idx]-- ^ List of secondary instance indices
56
                 , idx :: T.Ndx    -- ^ Internal index for book-keeping
57
                 , peers :: PeerMap.PeerMap -- ^ Pnode to instance mapping
58
                 , failN1:: Bool   -- ^ Whether the node has failed n1
59
                 , r_mem :: Int    -- ^ Maximum memory needed for
60
                                   -- failover by primaries of this node
61
                 , p_mem :: Double -- ^ Percent of free memory
62
                 , p_dsk :: Double -- ^ Percent of free disk
63
                 , p_rem :: Double -- ^ Percent of reserved memory
64
                 , offline :: Bool -- ^ Whether the node should not be used
65
                                   -- for allocations and skipped from
66
                                   -- score computations
67
  } deriving (Show)
68

    
69
instance T.Element Node where
70
    nameOf = name
71
    idxOf = idx
72
    setName = setName
73
    setIdx = setIdx
74

    
75
-- | A simple name for the int, node association list.
76
type AssocList = [(T.Ndx, Node)]
77

    
78
-- | A simple name for a node map.
79
type List = Container.Container Node
80

    
81
-- | Constant node index for a non-moveable instance.
82
noSecondary :: T.Ndx
83
noSecondary = -1
84

    
85
-- * Initialization functions
86

    
87
-- | Create a new node.
88
--
89
-- The index and the peers maps are empty, and will be need to be
90
-- update later via the 'setIdx' and 'buildPeers' functions.
91
create :: String -> Double -> Int -> Int -> Double -> Int -> Bool -> Node
92
create name_init mem_t_init mem_n_init mem_f_init
93
       dsk_t_init dsk_f_init offline_init =
94
    Node
95
    {
96
      name  = name_init,
97
      t_mem = mem_t_init,
98
      n_mem = mem_n_init,
99
      f_mem = mem_f_init,
100
      t_dsk = dsk_t_init,
101
      f_dsk = dsk_f_init,
102
      plist = [],
103
      slist = [],
104
      failN1 = True,
105
      idx = -1,
106
      peers = PeerMap.empty,
107
      r_mem = 0,
108
      p_mem = (fromIntegral mem_f_init) / mem_t_init,
109
      p_dsk = (fromIntegral dsk_f_init) / dsk_t_init,
110
      p_rem = 0,
111
      offline = offline_init,
112
      x_mem = 0
113
    }
114

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

    
121
-- | Changes the name.
122
--
123
-- This is used only during the building of the data structures.
124
setName :: Node -> String -> Node
125
setName t s = t {name = s}
126

    
127
-- | Sets the offline attribute.
128
setOffline :: Node -> Bool -> Node
129
setOffline t val = t { offline = val }
130

    
131
-- | Sets the unnaccounted memory.
132
setXmem :: Node -> Int -> Node
133
setXmem t val = t { x_mem = val }
134

    
135
-- | Computes the maximum reserved memory for peers from a peer map.
136
computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
137
computeMaxRes new_peers = PeerMap.maxElem new_peers
138

    
139
-- | Builds the peer map for a given node.
140
buildPeers :: Node -> Instance.List -> Node
141
buildPeers t il =
142
    let mdata = map
143
                (\i_idx -> let inst = Container.find i_idx il
144
                           in (Instance.pnode inst, Instance.mem inst))
145
                (slist t)
146
        pmap = PeerMap.accumArray (+) mdata
147
        new_rmem = computeMaxRes pmap
148
        new_failN1 = computeFailN1 new_rmem (f_mem t) (f_dsk t)
149
        new_prem = (fromIntegral new_rmem) / (t_mem t)
150
    in t {peers=pmap, failN1 = new_failN1, r_mem = new_rmem, p_rem = new_prem}
151

    
152
-- | Assigns an instance to a node as primary without other updates.
153
setPri :: Node -> T.Idx -> Node
154
setPri t idx = t { plist = idx:(plist t) }
155

    
156
-- | Assigns an instance to a node as secondary without other updates.
157
setSec :: Node -> T.Idx -> Node
158
setSec t idx = t { slist = idx:(slist t) }
159

    
160
-- * Update functions
161

    
162
-- | Sets the free memory.
163
setFmem :: Node -> Int -> Node
164
setFmem t new_mem =
165
    let new_n1 = computeFailN1 (r_mem t) new_mem (f_dsk t)
166
        new_mp = (fromIntegral new_mem) / (t_mem t)
167
    in
168
      t { f_mem = new_mem, failN1 = new_n1, p_mem = new_mp }
169

    
170
-- | Given the rmem, free memory and disk, computes the failn1 status.
171
computeFailN1 :: Int -> Int -> Int -> Bool
172
computeFailN1 new_rmem new_mem new_dsk =
173
    new_mem <= new_rmem || new_dsk <= 0
174

    
175
-- | Given the new free memory and disk, fail if any of them is below zero.
176
failHealth :: Int -> Int -> Bool
177
failHealth new_mem new_dsk = new_mem <= 0 || new_dsk <= 0
178

    
179
-- | Removes a primary instance.
180
removePri :: Node -> Instance.Instance -> Node
181
removePri t inst =
182
    let iname = Instance.idx inst
183
        new_plist = delete iname (plist t)
184
        new_mem = f_mem t + Instance.mem inst
185
        new_dsk = f_dsk t + Instance.dsk inst
186
        new_mp = (fromIntegral new_mem) / (t_mem t)
187
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
188
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk
189
    in t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
190
          failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
191

    
192
-- | Removes a secondary instance.
193
removeSec :: Node -> Instance.Instance -> Node
194
removeSec t inst =
195
    let iname = Instance.idx inst
196
        pnode = Instance.pnode inst
197
        new_slist = delete iname (slist t)
198
        new_dsk = f_dsk t + Instance.dsk inst
199
        old_peers = peers t
200
        old_peem = PeerMap.find pnode old_peers
201
        new_peem =  old_peem - (Instance.mem inst)
202
        new_peers = PeerMap.add pnode new_peem old_peers
203
        old_rmem = r_mem t
204
        new_rmem = if old_peem < old_rmem then
205
                       old_rmem
206
                   else
207
                       computeMaxRes new_peers
208
        new_prem = (fromIntegral new_rmem) / (t_mem t)
209
        new_failn1 = computeFailN1 new_rmem (f_mem t) new_dsk
210
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
211
    in t {slist = new_slist, f_dsk = new_dsk, peers = new_peers,
212
          failN1 = new_failn1, r_mem = new_rmem, p_dsk = new_dp,
213
          p_rem = new_prem}
214

    
215
-- | Adds a primary instance.
216
addPri :: Node -> Instance.Instance -> Maybe Node
217
addPri t inst =
218
    let iname = Instance.idx inst
219
        new_mem = f_mem t - Instance.mem inst
220
        new_dsk = f_dsk t - Instance.dsk inst
221
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk in
222
      if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) then
223
        Nothing
224
      else
225
        let new_plist = iname:(plist t)
226
            new_mp = (fromIntegral new_mem) / (t_mem t)
227
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
228
        in
229
        Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
230
                failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
231

    
232
-- | Adds a secondary instance.
233
addSec :: Node -> Instance.Instance -> T.Ndx -> Maybe Node
234
addSec t inst pdx =
235
    let iname = Instance.idx inst
236
        old_peers = peers t
237
        old_mem = f_mem t
238
        new_dsk = f_dsk t - Instance.dsk inst
239
        new_peem = PeerMap.find pdx old_peers + Instance.mem inst
240
        new_peers = PeerMap.add pdx new_peem old_peers
241
        new_rmem = max (r_mem t) new_peem
242
        new_prem = (fromIntegral new_rmem) / (t_mem t)
243
        new_failn1 = computeFailN1 new_rmem old_mem new_dsk in
244
    if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) then
245
        Nothing
246
    else
247
        let new_slist = iname:(slist t)
248
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
249
        in
250
        Just t {slist = new_slist, f_dsk = new_dsk,
251
                peers = new_peers, failN1 = new_failn1,
252
                r_mem = new_rmem, p_dsk = new_dp,
253
                p_rem = new_prem}
254

    
255
-- * Display functions
256

    
257
-- | String converter for the node list functionality.
258
list :: Int -> Node -> String
259
list mname t =
260
    let pl = plist t
261
        sl = slist t
262
        mp = p_mem t
263
        dp = p_dsk t
264
        off = offline t
265
        fn = failN1 t
266
        tmem = t_mem t
267
        nmem = n_mem t
268
        xmem = x_mem t
269
        fmem = f_mem t
270
        imem = (truncate tmem) - nmem - xmem - fmem
271
    in
272
      printf " %c %-*s %5.0f %5d %5d %5d %5d %5d %5.0f %5d %3d %3d %.5f %.5f"
273
                 (if off then '-' else if fn then '*' else ' ')
274
                 mname (name t) tmem nmem imem xmem fmem (r_mem t)
275
                 ((t_dsk t) / 1024) ((f_dsk t) `div` 1024)
276
                 (length pl) (length sl)
277
                 mp dp