Statistics
| Branch: | Tag: | Revision:

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

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

    
64
-- | A simple name for the int, node association list
65
type AssocList = [(Int, Node)]
66

    
67
-- | Constant node index for a non-moveable instance
68
noSecondary :: Int
69
noSecondary = -1
70

    
71
{- | Create a new node.
72

    
73
The index and the peers maps are empty, and will be need to be update
74
later via the 'setIdx' and 'buildPeers' functions.
75

    
76
-}
77
create :: String -> Double -> Int -> Int -> Double -> Int -> Bool -> Node
78
create name_init mem_t_init mem_n_init mem_f_init
79
       dsk_t_init dsk_f_init offline_init =
80
    Node
81
    {
82
      name  = name_init,
83
      t_mem = mem_t_init,
84
      n_mem = mem_n_init,
85
      f_mem = mem_f_init,
86
      t_dsk = dsk_t_init,
87
      f_dsk = dsk_f_init,
88
      plist = [],
89
      slist = [],
90
      failN1 = True,
91
      idx = -1,
92
      peers = PeerMap.empty,
93
      r_mem = 0,
94
      p_mem = (fromIntegral mem_f_init) / mem_t_init,
95
      p_dsk = (fromIntegral dsk_f_init) / dsk_t_init,
96
      p_rem = 0,
97
      offline = offline_init,
98
      x_mem = 0
99
    }
100

    
101
-- | Changes the index.
102
-- This is used only during the building of the data structures.
103
setIdx :: Node -> Int -> Node
104
setIdx t i = t {idx = i}
105

    
106
-- | Changes the name
107
-- This is used only during the building of the data structures.
108
setName t s = t {name = s}
109

    
110
-- | Sets the offline attribute
111
setOffline :: Node -> Bool -> Node
112
setOffline t val = t { offline = val }
113

    
114
-- | Sets the unnaccounted memory
115
setXmem :: Node -> Int -> Node
116
setXmem t val = t { x_mem = val }
117

    
118
-- | Sets the free memory
119
setFmem :: Node -> Int -> Node
120
setFmem t new_mem =
121
    let new_n1 = computeFailN1 (r_mem t) new_mem (f_dsk t)
122
        new_mp = (fromIntegral new_mem) / (t_mem t)
123
    in
124
      t { f_mem = new_mem, failN1 = new_n1, p_mem = new_mp }
125

    
126
-- | Given the rmem, free memory and disk, computes the failn1 status.
127
computeFailN1 :: Int -> Int -> Int -> Bool
128
computeFailN1 new_rmem new_mem new_dsk =
129
    new_mem <= new_rmem || new_dsk <= 0
130

    
131
-- | Given the new free memory and disk, fail if any of them is below zero.
132
failHealth :: Int -> Int -> Bool
133
failHealth new_mem new_dsk = new_mem <= 0 || new_dsk <= 0
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 -> Container.Container Instance.Instance -> Int -> Node
141
buildPeers t il num_nodes =
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 (+) 0 (0, num_nodes - 1) 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
-- | Removes a primary instance.
153
removePri :: Node -> Instance.Instance -> Node
154
removePri t inst =
155
    let iname = Instance.idx inst
156
        new_plist = delete iname (plist t)
157
        new_mem = f_mem t + Instance.mem inst
158
        new_dsk = f_dsk t + Instance.dsk inst
159
        new_mp = (fromIntegral new_mem) / (t_mem t)
160
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
161
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk
162
    in t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
163
          failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
164

    
165
-- | Removes a secondary instance.
166
removeSec :: Node -> Instance.Instance -> Node
167
removeSec t inst =
168
    let iname = Instance.idx inst
169
        pnode = Instance.pnode inst
170
        new_slist = delete iname (slist t)
171
        new_dsk = f_dsk t + Instance.dsk inst
172
        old_peers = peers t
173
        old_peem = PeerMap.find pnode old_peers
174
        new_peem =  old_peem - (Instance.mem inst)
175
        new_peers = PeerMap.add pnode new_peem old_peers
176
        old_rmem = r_mem t
177
        new_rmem = if old_peem < old_rmem then
178
                       old_rmem
179
                   else
180
                       computeMaxRes new_peers
181
        new_prem = (fromIntegral new_rmem) / (t_mem t)
182
        new_failn1 = computeFailN1 new_rmem (f_mem t) new_dsk
183
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
184
    in t {slist = new_slist, f_dsk = new_dsk, peers = new_peers,
185
          failN1 = new_failn1, r_mem = new_rmem, p_dsk = new_dp,
186
          p_rem = new_prem}
187

    
188
-- | Adds a primary instance.
189
addPri :: Node -> Instance.Instance -> Maybe Node
190
addPri t inst =
191
    let iname = Instance.idx inst
192
        new_mem = f_mem t - Instance.mem inst
193
        new_dsk = f_dsk t - Instance.dsk inst
194
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk in
195
      if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) then
196
        Nothing
197
      else
198
        let new_plist = iname:(plist t)
199
            new_mp = (fromIntegral new_mem) / (t_mem t)
200
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
201
        in
202
        Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
203
                failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
204

    
205
-- | Adds a secondary instance.
206
addSec :: Node -> Instance.Instance -> Int -> Maybe Node
207
addSec t inst pdx =
208
    let iname = Instance.idx inst
209
        old_peers = peers t
210
        old_mem = f_mem t
211
        new_dsk = f_dsk t - Instance.dsk inst
212
        new_peem = PeerMap.find pdx old_peers + Instance.mem inst
213
        new_peers = PeerMap.add pdx new_peem old_peers
214
        new_rmem = max (r_mem t) new_peem
215
        new_prem = (fromIntegral new_rmem) / (t_mem t)
216
        new_failn1 = computeFailN1 new_rmem old_mem new_dsk in
217
    if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) then
218
        Nothing
219
    else
220
        let new_slist = iname:(slist t)
221
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
222
        in
223
        Just t {slist = new_slist, f_dsk = new_dsk,
224
                peers = new_peers, failN1 = new_failn1,
225
                r_mem = new_rmem, p_dsk = new_dp,
226
                p_rem = new_prem}
227

    
228
-- | Add a primary instance to a node without other updates
229
setPri :: Node -> Int -> Node
230
setPri t idx = t { plist = idx:(plist t) }
231

    
232
-- | Add a secondary instance to a node without other updates
233
setSec :: Node -> Int -> Node
234
setSec t idx = t { slist = idx:(slist t) }
235

    
236
-- | String converter for the node list functionality.
237
list :: Int -> String -> Node -> String
238
list mname n t =
239
    let pl = plist t
240
        sl = slist t
241
        mp = p_mem t
242
        dp = p_dsk t
243
        off = offline t
244
        fn = failN1 t
245
        tmem = t_mem t
246
        nmem = n_mem t
247
        xmem = x_mem t
248
        fmem = f_mem t
249
        imem = (truncate tmem) - nmem - xmem - fmem
250
    in
251
      printf " %c %-*s %5.0f %5d %5d %5d %5d %5d %5.0f %5d %3d %3d %.5f %.5f"
252
                 (if off then '-' else if fn then '*' else ' ')
253
                 mname n tmem nmem imem xmem fmem (r_mem t)
254
                 ((t_dsk t) / 1024) ((f_dsk t) `div` 1024)
255
                 (length pl) (length sl)
256
                 mp dp