Rename htools/ to src/
[ganeti-local] / src / Ganeti / HTools / Types.hs
1 {-# LANGUAGE TemplateHaskell #-}
2
3 {-| Some common types.
4
5 -}
6
7 {-
8
9 Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 02110-1301, USA.
25
26 -}
27
28 module Ganeti.HTools.Types
29   ( Idx
30   , Ndx
31   , Gdx
32   , NameAssoc
33   , Score
34   , Weight
35   , GroupID
36   , defaultGroupID
37   , AllocPolicy(..)
38   , allocPolicyFromRaw
39   , allocPolicyToRaw
40   , InstanceStatus(..)
41   , instanceStatusFromRaw
42   , instanceStatusToRaw
43   , RSpec(..)
44   , AllocInfo(..)
45   , AllocStats
46   , DynUtil(..)
47   , zeroUtil
48   , baseUtil
49   , addUtil
50   , subUtil
51   , defReservedDiskRatio
52   , unitMem
53   , unitCpu
54   , unitDsk
55   , unknownField
56   , Placement
57   , IMove(..)
58   , DiskTemplate(..)
59   , diskTemplateToRaw
60   , diskTemplateFromRaw
61   , MirrorType(..)
62   , templateMirrorType
63   , MoveJob
64   , JobSet
65   , Element(..)
66   , FailMode(..)
67   , FailStats
68   , OpResult
69   , opToResult
70   , EvacMode(..)
71   , ISpec(..)
72   , IPolicy(..)
73   , defIPolicy
74   , rspecFromISpec
75   ) where
76
77 import qualified Data.Map as M
78
79 import qualified Ganeti.Constants as C
80 import qualified Ganeti.THH as THH
81 import Ganeti.BasicTypes
82 import Ganeti.Types
83
84 -- | The instance index type.
85 type Idx = Int
86
87 -- | The node index type.
88 type Ndx = Int
89
90 -- | The group index type.
91 type Gdx = Int
92
93 -- | The type used to hold name-to-idx mappings.
94 type NameAssoc = M.Map String Int
95
96 -- | A separate name for the cluster score type.
97 type Score = Double
98
99 -- | A separate name for a weight metric.
100 type Weight = Double
101
102 -- | The Group UUID type.
103 type GroupID = String
104
105 -- | Default group UUID (just a string, not a real UUID).
106 defaultGroupID :: GroupID
107 defaultGroupID = "00000000-0000-0000-0000-000000000000"
108
109 -- | Mirroring type.
110 data MirrorType = MirrorNone     -- ^ No mirroring/movability
111                 | MirrorInternal -- ^ DRBD-type mirroring
112                 | MirrorExternal -- ^ Shared-storage type mirroring
113                   deriving (Eq, Show)
114
115 -- | Correspondence between disk template and mirror type.
116 templateMirrorType :: DiskTemplate -> MirrorType
117 templateMirrorType DTDiskless   = MirrorExternal
118 templateMirrorType DTFile       = MirrorNone
119 templateMirrorType DTSharedFile = MirrorExternal
120 templateMirrorType DTPlain      = MirrorNone
121 templateMirrorType DTBlock      = MirrorExternal
122 templateMirrorType DTDrbd8      = MirrorInternal
123 templateMirrorType DTRbd        = MirrorExternal
124 templateMirrorType DTExt        = MirrorExternal
125
126 -- | The resource spec type.
127 data RSpec = RSpec
128   { rspecCpu  :: Int  -- ^ Requested VCPUs
129   , rspecMem  :: Int  -- ^ Requested memory
130   , rspecDsk  :: Int  -- ^ Requested disk
131   } deriving (Show, Eq)
132
133 -- | Allocation stats type. This is used instead of 'RSpec' (which was
134 -- used at first), because we need to track more stats. The actual
135 -- data can refer either to allocated, or available, etc. values
136 -- depending on the context. See also
137 -- 'Cluster.computeAllocationDelta'.
138 data AllocInfo = AllocInfo
139   { allocInfoVCpus :: Int    -- ^ VCPUs
140   , allocInfoNCpus :: Double -- ^ Normalised CPUs
141   , allocInfoMem   :: Int    -- ^ Memory
142   , allocInfoDisk  :: Int    -- ^ Disk
143   } deriving (Show, Eq)
144
145 -- | Currently used, possibly to allocate, unallocable.
146 type AllocStats = (AllocInfo, AllocInfo, AllocInfo)
147
148 -- | Instance specification type.
149 $(THH.buildObject "ISpec" "iSpec"
150   [ THH.renameField "MemorySize" $ THH.simpleField C.ispecMemSize    [t| Int |]
151   , THH.renameField "CpuCount"   $ THH.simpleField C.ispecCpuCount   [t| Int |]
152   , THH.renameField "DiskSize"   $ THH.simpleField C.ispecDiskSize   [t| Int |]
153   , THH.renameField "DiskCount"  $ THH.simpleField C.ispecDiskCount  [t| Int |]
154   , THH.renameField "NicCount"   $ THH.simpleField C.ispecNicCount   [t| Int |]
155   , THH.renameField "SpindleUse" $ THH.simpleField C.ispecSpindleUse [t| Int |]
156   ])
157
158 -- | The default minimum ispec.
159 defMinISpec :: ISpec
160 defMinISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsMinMemorySize
161                     , iSpecCpuCount   = C.ipolicyDefaultsMinCpuCount
162                     , iSpecDiskSize   = C.ipolicyDefaultsMinDiskSize
163                     , iSpecDiskCount  = C.ipolicyDefaultsMinDiskCount
164                     , iSpecNicCount   = C.ipolicyDefaultsMinNicCount
165                     , iSpecSpindleUse = C.ipolicyDefaultsMinSpindleUse
166                     }
167
168 -- | The default standard ispec.
169 defStdISpec :: ISpec
170 defStdISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsStdMemorySize
171                     , iSpecCpuCount   = C.ipolicyDefaultsStdCpuCount
172                     , iSpecDiskSize   = C.ipolicyDefaultsStdDiskSize
173                     , iSpecDiskCount  = C.ipolicyDefaultsStdDiskCount
174                     , iSpecNicCount   = C.ipolicyDefaultsStdNicCount
175                     , iSpecSpindleUse = C.ipolicyDefaultsStdSpindleUse
176                     }
177
178 -- | The default max ispec.
179 defMaxISpec :: ISpec
180 defMaxISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsMaxMemorySize
181                     , iSpecCpuCount   = C.ipolicyDefaultsMaxCpuCount
182                     , iSpecDiskSize   = C.ipolicyDefaultsMaxDiskSize
183                     , iSpecDiskCount  = C.ipolicyDefaultsMaxDiskCount
184                     , iSpecNicCount   = C.ipolicyDefaultsMaxNicCount
185                     , iSpecSpindleUse = C.ipolicyDefaultsMaxSpindleUse
186                     }
187
188 -- | Instance policy type.
189 $(THH.buildObject "IPolicy" "iPolicy"
190   [ THH.renameField "StdSpec" $ THH.simpleField C.ispecsStd [t| ISpec |]
191   , THH.renameField "MinSpec" $ THH.simpleField C.ispecsMin [t| ISpec |]
192   , THH.renameField "MaxSpec" $ THH.simpleField C.ispecsMax [t| ISpec |]
193   , THH.renameField "DiskTemplates" $
194       THH.simpleField C.ipolicyDts [t| [DiskTemplate] |]
195   , THH.renameField "VcpuRatio" $
196       THH.simpleField C.ipolicyVcpuRatio [t| Double |]
197   , THH.renameField "SpindleRatio" $
198       THH.simpleField C.ipolicySpindleRatio [t| Double |]
199   ])
200
201 -- | Converts an ISpec type to a RSpec one.
202 rspecFromISpec :: ISpec -> RSpec
203 rspecFromISpec ispec = RSpec { rspecCpu = iSpecCpuCount ispec
204                              , rspecMem = iSpecMemorySize ispec
205                              , rspecDsk = iSpecDiskSize ispec
206                              }
207
208 -- | The default instance policy.
209 defIPolicy :: IPolicy
210 defIPolicy = IPolicy { iPolicyStdSpec = defStdISpec
211                      , iPolicyMinSpec = defMinISpec
212                      , iPolicyMaxSpec = defMaxISpec
213                      -- hardcoding here since Constants.hs exports the
214                      -- string values, not the actual type; and in
215                      -- htools, we are mostly looking at DRBD
216                      , iPolicyDiskTemplates = [minBound..maxBound]
217                      , iPolicyVcpuRatio = C.ipolicyDefaultsVcpuRatio
218                      , iPolicySpindleRatio = C.ipolicyDefaultsSpindleRatio
219                      }
220
221 -- | The dynamic resource specs of a machine (i.e. load or load
222 -- capacity, as opposed to size).
223 data DynUtil = DynUtil
224   { cpuWeight :: Weight -- ^ Standardised CPU usage
225   , memWeight :: Weight -- ^ Standardised memory load
226   , dskWeight :: Weight -- ^ Standardised disk I\/O usage
227   , netWeight :: Weight -- ^ Standardised network usage
228   } deriving (Show, Eq)
229
230 -- | Initial empty utilisation.
231 zeroUtil :: DynUtil
232 zeroUtil = DynUtil { cpuWeight = 0, memWeight = 0
233                    , dskWeight = 0, netWeight = 0 }
234
235 -- | Base utilisation (used when no actual utilisation data is
236 -- supplied).
237 baseUtil :: DynUtil
238 baseUtil = DynUtil { cpuWeight = 1, memWeight = 1
239                    , dskWeight = 1, netWeight = 1 }
240
241 -- | Sum two utilisation records.
242 addUtil :: DynUtil -> DynUtil -> DynUtil
243 addUtil (DynUtil a1 a2 a3 a4) (DynUtil b1 b2 b3 b4) =
244   DynUtil (a1+b1) (a2+b2) (a3+b3) (a4+b4)
245
246 -- | Substracts one utilisation record from another.
247 subUtil :: DynUtil -> DynUtil -> DynUtil
248 subUtil (DynUtil a1 a2 a3 a4) (DynUtil b1 b2 b3 b4) =
249   DynUtil (a1-b1) (a2-b2) (a3-b3) (a4-b4)
250
251 -- | The description of an instance placement. It contains the
252 -- instance index, the new primary and secondary node, the move being
253 -- performed and the score of the cluster after the move.
254 type Placement = (Idx, Ndx, Ndx, IMove, Score)
255
256 -- | An instance move definition.
257 data IMove = Failover                -- ^ Failover the instance (f)
258            | FailoverToAny Ndx       -- ^ Failover to a random node
259                                      -- (fa:np), for shared storage
260            | ReplacePrimary Ndx      -- ^ Replace primary (f, r:np, f)
261            | ReplaceSecondary Ndx    -- ^ Replace secondary (r:ns)
262            | ReplaceAndFailover Ndx  -- ^ Replace secondary, failover (r:np, f)
263            | FailoverAndReplace Ndx  -- ^ Failover, replace secondary (f, r:ns)
264              deriving (Show)
265
266 -- | Formatted solution output for one move (involved nodes and
267 -- commands.
268 type MoveJob = ([Ndx], Idx, IMove, [String])
269
270 -- | Unknown field in table output.
271 unknownField :: String
272 unknownField = "<unknown field>"
273
274 -- | A list of command elements.
275 type JobSet = [MoveJob]
276
277 -- | Default max disk usage ratio.
278 defReservedDiskRatio :: Double
279 defReservedDiskRatio = 0
280
281 -- | Base memory unit.
282 unitMem :: Int
283 unitMem = 64
284
285 -- | Base disk unit.
286 unitDsk :: Int
287 unitDsk = 256
288
289 -- | Base vcpus unit.
290 unitCpu :: Int
291 unitCpu = 1
292
293 -- | Reason for an operation's falure.
294 data FailMode = FailMem  -- ^ Failed due to not enough RAM
295               | FailDisk -- ^ Failed due to not enough disk
296               | FailCPU  -- ^ Failed due to not enough CPU capacity
297               | FailN1   -- ^ Failed due to not passing N1 checks
298               | FailTags -- ^ Failed due to tag exclusion
299                 deriving (Eq, Enum, Bounded, Show)
300
301 -- | List with failure statistics.
302 type FailStats = [(FailMode, Int)]
303
304 -- | Either-like data-type customized for our failure modes.
305 --
306 -- The failure values for this monad track the specific allocation
307 -- failures, so this is not a general error-monad (compare with the
308 -- 'Result' data type). One downside is that this type cannot encode a
309 -- generic failure mode, hence our way to build a FailMode from string
310 -- will instead raise an exception.
311 type OpResult = GenericResult FailMode
312
313 -- | 'FromString' instance for 'FailMode' designed to catch unintended
314 -- use as a general monad.
315 instance FromString FailMode where
316   mkFromString v = error $ "Programming error: OpResult used as generic monad"
317                            ++ v
318
319 -- | Conversion from 'OpResult' to 'Result'.
320 opToResult :: OpResult a -> Result a
321 opToResult (Bad f) = Bad $ show f
322 opToResult (Ok v) = Ok v
323
324 -- | A generic class for items that have updateable names and indices.
325 class Element a where
326   -- | Returns the name of the element
327   nameOf  :: a -> String
328   -- | Returns all the known names of the element
329   allNames :: a -> [String]
330   -- | Returns the index of the element
331   idxOf   :: a -> Int
332   -- | Updates the alias of the element
333   setAlias :: a -> String -> a
334   -- | Compute the alias by stripping a given suffix (domain) from
335   -- the name
336   computeAlias :: String -> a -> a
337   computeAlias dom e = setAlias e alias
338     where alias = take (length name - length dom) name
339           name = nameOf e
340   -- | Updates the index of the element
341   setIdx  :: a -> Int -> a
342
343 -- | The iallocator node-evacuate evac_mode type.
344 $(THH.declareSADT "EvacMode"
345        [ ("ChangePrimary",   'C.iallocatorNevacPri)
346        , ("ChangeSecondary", 'C.iallocatorNevacSec)
347        , ("ChangeAll",       'C.iallocatorNevacAll)
348        ])
349 $(THH.makeJSONInstance ''EvacMode)