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
77 import qualified Data.Map as M
79 import qualified Ganeti.Constants as C
80 import qualified Ganeti.THH as THH
81 import Ganeti.BasicTypes
84 -- | The instance index type.
87 -- | The node index type.
90 -- | The group index type.
93 -- | The type used to hold name-to-idx mappings.
94 type NameAssoc = M.Map String Int
96 -- | A separate name for the cluster score type.
99 -- | A separate name for a weight metric.
102 -- | The Group UUID type.
103 type GroupID = String
105 -- | Default group UUID (just a string, not a real UUID).
106 defaultGroupID :: GroupID
107 defaultGroupID = "00000000-0000-0000-0000-000000000000"
110 data MirrorType = MirrorNone -- ^ No mirroring/movability
111 | MirrorInternal -- ^ DRBD-type mirroring
112 | MirrorExternal -- ^ Shared-storage type mirroring
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
125 -- | The resource spec type.
127 { rspecCpu :: Int -- ^ Requested VCPUs
128 , rspecMem :: Int -- ^ Requested memory
129 , rspecDsk :: Int -- ^ Requested disk
130 } deriving (Show, Eq)
132 -- | Allocation stats type. This is used instead of 'RSpec' (which was
133 -- used at first), because we need to track more stats. The actual
134 -- data can refer either to allocated, or available, etc. values
135 -- depending on the context. See also
136 -- 'Cluster.computeAllocationDelta'.
137 data AllocInfo = AllocInfo
138 { allocInfoVCpus :: Int -- ^ VCPUs
139 , allocInfoNCpus :: Double -- ^ Normalised CPUs
140 , allocInfoMem :: Int -- ^ Memory
141 , allocInfoDisk :: Int -- ^ Disk
142 } deriving (Show, Eq)
144 -- | Currently used, possibly to allocate, unallocable.
145 type AllocStats = (AllocInfo, AllocInfo, AllocInfo)
147 -- | Instance specification type.
148 $(THH.buildObject "ISpec" "iSpec"
149 [ THH.renameField "MemorySize" $ THH.simpleField C.ispecMemSize [t| Int |]
150 , THH.renameField "CpuCount" $ THH.simpleField C.ispecCpuCount [t| Int |]
151 , THH.renameField "DiskSize" $ THH.simpleField C.ispecDiskSize [t| Int |]
152 , THH.renameField "DiskCount" $ THH.simpleField C.ispecDiskCount [t| Int |]
153 , THH.renameField "NicCount" $ THH.simpleField C.ispecNicCount [t| Int |]
154 , THH.renameField "SpindleUse" $ THH.simpleField C.ispecSpindleUse [t| Int |]
157 -- | The default minimum ispec.
159 defMinISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsMinMemorySize
160 , iSpecCpuCount = C.ipolicyDefaultsMinCpuCount
161 , iSpecDiskSize = C.ipolicyDefaultsMinDiskSize
162 , iSpecDiskCount = C.ipolicyDefaultsMinDiskCount
163 , iSpecNicCount = C.ipolicyDefaultsMinNicCount
164 , iSpecSpindleUse = C.ipolicyDefaultsMinSpindleUse
167 -- | The default standard ispec.
169 defStdISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsStdMemorySize
170 , iSpecCpuCount = C.ipolicyDefaultsStdCpuCount
171 , iSpecDiskSize = C.ipolicyDefaultsStdDiskSize
172 , iSpecDiskCount = C.ipolicyDefaultsStdDiskCount
173 , iSpecNicCount = C.ipolicyDefaultsStdNicCount
174 , iSpecSpindleUse = C.ipolicyDefaultsStdSpindleUse
177 -- | The default max ispec.
179 defMaxISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsMaxMemorySize
180 , iSpecCpuCount = C.ipolicyDefaultsMaxCpuCount
181 , iSpecDiskSize = C.ipolicyDefaultsMaxDiskSize
182 , iSpecDiskCount = C.ipolicyDefaultsMaxDiskCount
183 , iSpecNicCount = C.ipolicyDefaultsMaxNicCount
184 , iSpecSpindleUse = C.ipolicyDefaultsMaxSpindleUse
187 -- | Instance policy type.
188 $(THH.buildObject "IPolicy" "iPolicy"
189 [ THH.renameField "StdSpec" $ THH.simpleField C.ispecsStd [t| ISpec |]
190 , THH.renameField "MinSpec" $ THH.simpleField C.ispecsMin [t| ISpec |]
191 , THH.renameField "MaxSpec" $ THH.simpleField C.ispecsMax [t| ISpec |]
192 , THH.renameField "DiskTemplates" $
193 THH.simpleField C.ipolicyDts [t| [DiskTemplate] |]
194 , THH.renameField "VcpuRatio" $
195 THH.simpleField C.ipolicyVcpuRatio [t| Double |]
196 , THH.renameField "SpindleRatio" $
197 THH.simpleField C.ipolicySpindleRatio [t| Double |]
200 -- | Converts an ISpec type to a RSpec one.
201 rspecFromISpec :: ISpec -> RSpec
202 rspecFromISpec ispec = RSpec { rspecCpu = iSpecCpuCount ispec
203 , rspecMem = iSpecMemorySize ispec
204 , rspecDsk = iSpecDiskSize ispec
207 -- | The default instance policy.
208 defIPolicy :: IPolicy
209 defIPolicy = IPolicy { iPolicyStdSpec = defStdISpec
210 , iPolicyMinSpec = defMinISpec
211 , iPolicyMaxSpec = defMaxISpec
212 -- hardcoding here since Constants.hs exports the
213 -- string values, not the actual type; and in
214 -- htools, we are mostly looking at DRBD
215 , iPolicyDiskTemplates = [minBound..maxBound]
216 , iPolicyVcpuRatio = C.ipolicyDefaultsVcpuRatio
217 , iPolicySpindleRatio = C.ipolicyDefaultsSpindleRatio
220 -- | The dynamic resource specs of a machine (i.e. load or load
221 -- capacity, as opposed to size).
222 data DynUtil = DynUtil
223 { cpuWeight :: Weight -- ^ Standardised CPU usage
224 , memWeight :: Weight -- ^ Standardised memory load
225 , dskWeight :: Weight -- ^ Standardised disk I\/O usage
226 , netWeight :: Weight -- ^ Standardised network usage
227 } deriving (Show, Eq)
229 -- | Initial empty utilisation.
231 zeroUtil = DynUtil { cpuWeight = 0, memWeight = 0
232 , dskWeight = 0, netWeight = 0 }
234 -- | Base utilisation (used when no actual utilisation data is
237 baseUtil = DynUtil { cpuWeight = 1, memWeight = 1
238 , dskWeight = 1, netWeight = 1 }
240 -- | Sum two utilisation records.
241 addUtil :: DynUtil -> DynUtil -> DynUtil
242 addUtil (DynUtil a1 a2 a3 a4) (DynUtil b1 b2 b3 b4) =
243 DynUtil (a1+b1) (a2+b2) (a3+b3) (a4+b4)
245 -- | Substracts one utilisation record from another.
246 subUtil :: DynUtil -> DynUtil -> DynUtil
247 subUtil (DynUtil a1 a2 a3 a4) (DynUtil b1 b2 b3 b4) =
248 DynUtil (a1-b1) (a2-b2) (a3-b3) (a4-b4)
250 -- | The description of an instance placement. It contains the
251 -- instance index, the new primary and secondary node, the move being
252 -- performed and the score of the cluster after the move.
253 type Placement = (Idx, Ndx, Ndx, IMove, Score)
255 -- | An instance move definition.
256 data IMove = Failover -- ^ Failover the instance (f)
257 | FailoverToAny Ndx -- ^ Failover to a random node
258 -- (fa:np), for shared storage
259 | ReplacePrimary Ndx -- ^ Replace primary (f, r:np, f)
260 | ReplaceSecondary Ndx -- ^ Replace secondary (r:ns)
261 | ReplaceAndFailover Ndx -- ^ Replace secondary, failover (r:np, f)
262 | FailoverAndReplace Ndx -- ^ Failover, replace secondary (f, r:ns)
265 -- | Formatted solution output for one move (involved nodes and
267 type MoveJob = ([Ndx], Idx, IMove, [String])
269 -- | Unknown field in table output.
270 unknownField :: String
271 unknownField = "<unknown field>"
273 -- | A list of command elements.
274 type JobSet = [MoveJob]
276 -- | Default max disk usage ratio.
277 defReservedDiskRatio :: Double
278 defReservedDiskRatio = 0
280 -- | Base memory unit.
288 -- | Base vcpus unit.
292 -- | Reason for an operation's falure.
293 data FailMode = FailMem -- ^ Failed due to not enough RAM
294 | FailDisk -- ^ Failed due to not enough disk
295 | FailCPU -- ^ Failed due to not enough CPU capacity
296 | FailN1 -- ^ Failed due to not passing N1 checks
297 | FailTags -- ^ Failed due to tag exclusion
298 deriving (Eq, Enum, Bounded, Show)
300 -- | List with failure statistics.
301 type FailStats = [(FailMode, Int)]
303 -- | Either-like data-type customized for our failure modes.
305 -- The failure values for this monad track the specific allocation
306 -- failures, so this is not a general error-monad (compare with the
307 -- 'Result' data type). One downside is that this type cannot encode a
308 -- generic failure mode, hence our way to build a FailMode from string
309 -- will instead raise an exception.
310 type OpResult = GenericResult FailMode
312 -- | 'FromString' instance for 'FailMode' designed to catch unintended
313 -- use as a general monad.
314 instance FromString FailMode where
315 mkFromString v = error $ "Programming error: OpResult used as generic monad"
318 -- | Conversion from 'OpResult' to 'Result'.
319 opToResult :: OpResult a -> Result a
320 opToResult (Bad f) = Bad $ show f
321 opToResult (Ok v) = Ok v
323 -- | A generic class for items that have updateable names and indices.
324 class Element a where
325 -- | Returns the name of the element
326 nameOf :: a -> String
327 -- | Returns all the known names of the element
328 allNames :: a -> [String]
329 -- | Returns the index of the element
331 -- | Updates the alias of the element
332 setAlias :: a -> String -> a
333 -- | Compute the alias by stripping a given suffix (domain) from
335 computeAlias :: String -> a -> a
336 computeAlias dom e = setAlias e alias
337 where alias = take (length name - length dom) name
339 -- | Updates the index of the element
340 setIdx :: a -> Int -> a
342 -- | The iallocator node-evacuate evac_mode type.
343 $(THH.declareSADT "EvacMode"
344 [ ("ChangePrimary", 'C.iallocatorNevacPri)
345 , ("ChangeSecondary", 'C.iallocatorNevacSec)
346 , ("ChangeAll", 'C.iallocatorNevacAll)
348 $(THH.makeJSONInstance ''EvacMode)