1 {-# LANGUAGE TemplateHaskell #-}
9 Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
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.
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.
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
28 module Ganeti.HTools.Types
41 , instanceStatusFromRaw
51 , defReservedDiskRatio
82 import qualified Data.Map as M
83 import Text.JSON (makeObj, readJSON, showJSON)
85 import qualified Ganeti.Constants as C
86 import qualified Ganeti.THH as THH
87 import Ganeti.BasicTypes
88 import Ganeti.HTools.JSON
90 -- | The instance index type.
93 -- | The node index type.
96 -- | The group index type.
99 -- | The type used to hold name-to-idx mappings.
100 type NameAssoc = M.Map String Int
102 -- | A separate name for the cluster score type.
105 -- | A separate name for a weight metric.
108 -- | The Group UUID type.
109 type GroupID = String
111 -- | Default group UUID (just a string, not a real UUID).
112 defaultGroupID :: GroupID
113 defaultGroupID = "00000000-0000-0000-0000-000000000000"
115 -- | Instance disk template type.
116 $(THH.declareSADT "DiskTemplate"
117 [ ("DTDiskless", 'C.dtDiskless)
118 , ("DTFile", 'C.dtFile)
119 , ("DTSharedFile", 'C.dtSharedFile)
120 , ("DTPlain", 'C.dtPlain)
121 , ("DTBlock", 'C.dtBlock)
122 , ("DTDrbd8", 'C.dtDrbd8)
124 $(THH.makeJSONInstance ''DiskTemplate)
126 -- | The Group allocation policy type.
128 -- Note that the order of constructors is important as the automatic
129 -- Ord instance will order them in the order they are defined, so when
130 -- changing this data type be careful about the interaction with the
131 -- desired sorting order.
132 $(THH.declareSADT "AllocPolicy"
133 [ ("AllocPreferred", 'C.allocPolicyPreferred)
134 , ("AllocLastResort", 'C.allocPolicyLastResort)
135 , ("AllocUnallocable", 'C.allocPolicyUnallocable)
137 $(THH.makeJSONInstance ''AllocPolicy)
139 -- | The Instance real state type.
140 $(THH.declareSADT "InstanceStatus"
141 [ ("AdminDown", 'C.inststAdmindown)
142 , ("AdminOffline", 'C.inststAdminoffline)
143 , ("ErrorDown", 'C.inststErrordown)
144 , ("ErrorUp", 'C.inststErrorup)
145 , ("NodeDown", 'C.inststNodedown)
146 , ("NodeOffline", 'C.inststNodeoffline)
147 , ("Running", 'C.inststRunning)
148 , ("WrongNode", 'C.inststWrongnode)
150 $(THH.makeJSONInstance ''InstanceStatus)
152 -- | The resource spec type.
154 { rspecCpu :: Int -- ^ Requested VCPUs
155 , rspecMem :: Int -- ^ Requested memory
156 , rspecDsk :: Int -- ^ Requested disk
157 } deriving (Show, Read, Eq)
159 -- | Allocation stats type. This is used instead of 'RSpec' (which was
160 -- used at first), because we need to track more stats. The actual
161 -- data can refer either to allocated, or available, etc. values
162 -- depending on the context. See also
163 -- 'Cluster.computeAllocationDelta'.
164 data AllocInfo = AllocInfo
165 { allocInfoVCpus :: Int -- ^ VCPUs
166 , allocInfoNCpus :: Double -- ^ Normalised CPUs
167 , allocInfoMem :: Int -- ^ Memory
168 , allocInfoDisk :: Int -- ^ Disk
169 } deriving (Show, Read, Eq)
171 -- | Currently used, possibly to allocate, unallocable.
172 type AllocStats = (AllocInfo, AllocInfo, AllocInfo)
174 -- | Instance specification type.
175 $(THH.buildObject "ISpec" "iSpec"
176 [ THH.renameField "MemorySize" $ THH.simpleField "memory-size" [t| Int |]
177 , THH.renameField "CpuCount" $ THH.simpleField "cpu-count" [t| Int |]
178 , THH.renameField "DiskSize" $ THH.simpleField "disk-size" [t| Int |]
179 , THH.renameField "DiskCount" $ THH.simpleField "disk-count" [t| Int |]
180 , THH.renameField "NicCount" $ THH.simpleField "nic-count" [t| Int |]
183 -- | The default minimum ispec.
185 defMinISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsMinMemorySize
186 , iSpecCpuCount = C.ipolicyDefaultsMinCpuCount
187 , iSpecDiskSize = C.ipolicyDefaultsMinDiskSize
188 , iSpecDiskCount = C.ipolicyDefaultsMinDiskCount
189 , iSpecNicCount = C.ipolicyDefaultsMinNicCount
192 -- | The default standard ispec.
194 defStdISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsStdMemorySize
195 , iSpecCpuCount = C.ipolicyDefaultsStdCpuCount
196 , iSpecDiskSize = C.ipolicyDefaultsStdDiskSize
197 , iSpecDiskCount = C.ipolicyDefaultsStdDiskCount
198 , iSpecNicCount = C.ipolicyDefaultsStdNicCount
201 -- | The default max ispec.
203 defMaxISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsMaxMemorySize
204 , iSpecCpuCount = C.ipolicyDefaultsMaxCpuCount
205 , iSpecDiskSize = C.ipolicyDefaultsMaxDiskSize
206 , iSpecDiskCount = C.ipolicyDefaultsMaxDiskCount
207 , iSpecNicCount = C.ipolicyDefaultsMaxNicCount
210 -- | Instance policy type.
211 $(THH.buildObject "IPolicy" "iPolicy"
212 [ THH.renameField "StdSpec" $ THH.simpleField "std" [t| ISpec |]
213 , THH.renameField "MinSpec" $ THH.simpleField "min" [t| ISpec |]
214 , THH.renameField "MaxSpec" $ THH.simpleField "max" [t| ISpec |]
215 , THH.renameField "DiskTemplates" $
216 THH.simpleField "disk_templates" [t| [DiskTemplate] |]
217 , THH.renameField "VcpuRatio" $
218 THH.simpleField "vcpu_ratio" [t| Double |]
221 -- | Converts an ISpec type to a RSpec one.
222 rspecFromISpec :: ISpec -> RSpec
223 rspecFromISpec ispec = RSpec { rspecCpu = iSpecCpuCount ispec
224 , rspecMem = iSpecMemorySize ispec
225 , rspecDsk = iSpecDiskSize ispec
228 -- | The default instance policy.
229 defIPolicy :: IPolicy
230 defIPolicy = IPolicy { iPolicyStdSpec = defStdISpec
231 , iPolicyMinSpec = defMinISpec
232 , iPolicyMaxSpec = defMaxISpec
233 -- hardcoding here since Constants.hs exports the
234 -- string values, not the actual type; and in
235 -- htools, we are mostly looking at DRBD
236 , iPolicyDiskTemplates = [DTDrbd8, DTPlain]
237 , iPolicyVcpuRatio = C.ipolicyDefaultsVcpuRatio
240 -- | The dynamic resource specs of a machine (i.e. load or load
241 -- capacity, as opposed to size).
242 data DynUtil = DynUtil
243 { cpuWeight :: Weight -- ^ Standardised CPU usage
244 , memWeight :: Weight -- ^ Standardised memory load
245 , dskWeight :: Weight -- ^ Standardised disk I\/O usage
246 , netWeight :: Weight -- ^ Standardised network usage
247 } deriving (Show, Read, Eq)
249 -- | Initial empty utilisation.
251 zeroUtil = DynUtil { cpuWeight = 0, memWeight = 0
252 , dskWeight = 0, netWeight = 0 }
254 -- | Base utilisation (used when no actual utilisation data is
257 baseUtil = DynUtil { cpuWeight = 1, memWeight = 1
258 , dskWeight = 1, netWeight = 1 }
260 -- | Sum two utilisation records.
261 addUtil :: DynUtil -> DynUtil -> DynUtil
262 addUtil (DynUtil a1 a2 a3 a4) (DynUtil b1 b2 b3 b4) =
263 DynUtil (a1+b1) (a2+b2) (a3+b3) (a4+b4)
265 -- | Substracts one utilisation record from another.
266 subUtil :: DynUtil -> DynUtil -> DynUtil
267 subUtil (DynUtil a1 a2 a3 a4) (DynUtil b1 b2 b3 b4) =
268 DynUtil (a1-b1) (a2-b2) (a3-b3) (a4-b4)
270 -- | The description of an instance placement. It contains the
271 -- instance index, the new primary and secondary node, the move being
272 -- performed and the score of the cluster after the move.
273 type Placement = (Idx, Ndx, Ndx, IMove, Score)
275 -- | An instance move definition.
276 data IMove = Failover -- ^ Failover the instance (f)
277 | ReplacePrimary Ndx -- ^ Replace primary (f, r:np, f)
278 | ReplaceSecondary Ndx -- ^ Replace secondary (r:ns)
279 | ReplaceAndFailover Ndx -- ^ Replace secondary, failover (r:np, f)
280 | FailoverAndReplace Ndx -- ^ Failover, replace secondary (f, r:ns)
281 deriving (Show, Read)
283 -- | Formatted solution output for one move (involved nodes and
285 type MoveJob = ([Ndx], Idx, IMove, [String])
287 -- | Unknown field in table output.
288 unknownField :: String
289 unknownField = "<unknown field>"
291 -- | A list of command elements.
292 type JobSet = [MoveJob]
294 -- | Connection timeout (when using non-file methods).
298 -- | The default timeout for queries (when using non-file methods).
302 -- | Default max disk usage ratio.
303 defReservedDiskRatio :: Double
304 defReservedDiskRatio = 0
306 -- | Base memory unit.
314 -- | Base vcpus unit.
318 -- | Reason for an operation's falure.
319 data FailMode = FailMem -- ^ Failed due to not enough RAM
320 | FailDisk -- ^ Failed due to not enough disk
321 | FailCPU -- ^ Failed due to not enough CPU capacity
322 | FailN1 -- ^ Failed due to not passing N1 checks
323 | FailTags -- ^ Failed due to tag exclusion
324 deriving (Eq, Enum, Bounded, Show, Read)
326 -- | List with failure statistics.
327 type FailStats = [(FailMode, Int)]
329 -- | Either-like data-type customized for our failure modes.
331 -- The failure values for this monad track the specific allocation
332 -- failures, so this is not a general error-monad (compare with the
333 -- 'Result' data type). One downside is that this type cannot encode a
334 -- generic failure mode, hence 'fail' for this monad is not defined
335 -- and will cause an exception.
336 data OpResult a = OpFail FailMode -- ^ Failed operation
337 | OpGood a -- ^ Success operation
338 deriving (Show, Read)
340 instance Monad OpResult where
341 (OpGood x) >>= fn = fn x
342 (OpFail y) >>= _ = OpFail y
345 -- | Conversion from 'OpResult' to 'Result'.
346 opToResult :: OpResult a -> Result a
347 opToResult (OpFail f) = Bad $ show f
348 opToResult (OpGood v) = Ok v
350 -- | A generic class for items that have updateable names and indices.
351 class Element a where
352 -- | Returns the name of the element
353 nameOf :: a -> String
354 -- | Returns all the known names of the element
355 allNames :: a -> [String]
356 -- | Returns the index of the element
358 -- | Updates the alias of the element
359 setAlias :: a -> String -> a
360 -- | Compute the alias by stripping a given suffix (domain) from
362 computeAlias :: String -> a -> a
363 computeAlias dom e = setAlias e alias
364 where alias = take (length name - length dom) name
366 -- | Updates the index of the element
367 setIdx :: a -> Int -> a
369 -- | The iallocator node-evacuate evac_mode type.
370 $(THH.declareSADT "EvacMode"
371 [ ("ChangePrimary", 'C.iallocatorNevacPri)
372 , ("ChangeSecondary", 'C.iallocatorNevacSec)
373 , ("ChangeAll", 'C.iallocatorNevacAll)
375 $(THH.makeJSONInstance ''EvacMode)