Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Query / Common.hs @ 9491766c

History | View | Annotate | Download (6.9 kB)

1
{-| Implementation of the Ganeti Query2 common objects.
2

    
3
 -}
4

    
5
{-
6

    
7
Copyright (C) 2012, 2013 Google Inc.
8

    
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 2 of the License, or
12
(at your option) any later version.
13

    
14
This program is distributed in the hope that it will be useful, but
15
WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
General Public License for more details.
18

    
19
You should have received a copy of the GNU General Public License
20
along with this program; if not, write to the Free Software
21
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22
02110-1301, USA.
23

    
24
-}
25

    
26
module Ganeti.Query.Common
27
  ( NoDataRuntime(..)
28
  , rsNoData
29
  , rsUnavail
30
  , rsNormal
31
  , rsMaybeNoData
32
  , rsMaybeUnavail
33
  , rsErrorNoData
34
  , rsUnknown
35
  , missingRuntime
36
  , rpcErrorToStatus
37
  , timeStampFields
38
  , uuidFields
39
  , serialFields
40
  , tagsFields
41
  , dictFieldGetter
42
  , buildNdParamField
43
  , getDefaultHypervisorSpec
44
  , getHvParamsFromCluster
45
  ) where
46

    
47
import qualified Data.Map as Map
48
import Data.Maybe (fromMaybe)
49
import Text.JSON (JSON, showJSON)
50

    
51
import Ganeti.BasicTypes
52
import qualified Ganeti.Constants as C
53
import Ganeti.Config
54
import Ganeti.Errors
55
import Ganeti.JSON
56
import Ganeti.Objects
57
import Ganeti.Rpc
58
import Ganeti.Query.Language
59
import Ganeti.Query.Types
60
import Ganeti.Types
61

    
62
-- | The runtime used by queries which retrieve no live data.
63
data NoDataRuntime = NoDataRuntime
64

    
65
-- * Generic functions
66

    
67
-- | Conversion from 'VType' to 'FieldType'.
68
vTypeToQFT :: VType -> FieldType
69
vTypeToQFT VTypeString      = QFTOther
70
vTypeToQFT VTypeMaybeString = QFTOther
71
vTypeToQFT VTypeBool        = QFTBool
72
vTypeToQFT VTypeSize        = QFTUnit
73
vTypeToQFT VTypeInt         = QFTNumber
74

    
75
-- * Result helpers
76

    
77
-- | Helper for a result with no data.
78
rsNoData :: ResultEntry
79
rsNoData = ResultEntry RSNoData Nothing
80

    
81
-- | Helper for result for an entity which supports no such field.
82
rsUnavail :: ResultEntry
83
rsUnavail = ResultEntry RSUnavail Nothing
84

    
85
-- | Helper to declare a normal result.
86
rsNormal :: (JSON a) => a -> ResultEntry
87
rsNormal a = ResultEntry RSNormal $ Just (showJSON a)
88

    
89
-- | Helper to declare a result from a 'Maybe' (the item might be
90
-- missing, in which case we return no data). Note that there's some
91
-- ambiguity here: in some cases, we mean 'RSNoData', but in other
92
-- 'RSUnavail'; this is easy to solve in simple cases, but not in
93
-- nested dicts. If you want to return 'RSUnavail' in case of 'Nothing'
94
-- use the function 'rsMaybeUnavail'.
95
rsMaybeNoData :: (JSON a) => Maybe a -> ResultEntry
96
rsMaybeNoData = maybe rsNoData rsNormal
97

    
98
-- | Helper to declare a result from a 'ErrorResult' (an error happened
99
-- while retrieving the data from a config, or there was no data).
100
-- This function should be used if an error signals there was no data.
101
rsErrorNoData :: (JSON a) => ErrorResult a -> ResultEntry
102
rsErrorNoData res = case res of
103
  Ok  x -> rsNormal x
104
  Bad _ -> rsNoData
105

    
106
-- | Helper to declare a result from a 'Maybe'. This version returns
107
-- a 'RSUnavail' in case of 'Nothing'. It should be used for optional
108
-- fields that are not set. For cases where 'Nothing' means that there
109
-- was an error, consider using 'rsMaybe' instead.
110
rsMaybeUnavail :: (JSON a) => Maybe a -> ResultEntry
111
rsMaybeUnavail = maybe rsUnavail rsNormal
112

    
113
-- | Helper for unknown field result.
114
rsUnknown :: ResultEntry
115
rsUnknown = ResultEntry RSUnknown Nothing
116

    
117
-- | Helper for a missing runtime parameter.
118
missingRuntime :: FieldGetter a b
119
missingRuntime = FieldRuntime (\_ _ -> ResultEntry RSNoData Nothing)
120

    
121
-- * Error conversion
122

    
123
-- | Convert RpcError to ResultStatus
124
rpcErrorToStatus :: RpcError -> ResultStatus
125
rpcErrorToStatus OfflineNodeError = RSOffline
126
rpcErrorToStatus _ = RSNoData
127

    
128
-- * Common fields
129

    
130
-- | The list of timestamp fields.
131
timeStampFields :: (TimeStampObject a) => FieldList a b
132
timeStampFields =
133
  [ (FieldDefinition "ctime" "CTime" QFTTimestamp "Creation timestamp",
134
     FieldSimple (rsNormal . cTimeOf), QffNormal)
135
  , (FieldDefinition "mtime" "MTime" QFTTimestamp "Modification timestamp",
136
     FieldSimple (rsNormal . mTimeOf), QffNormal)
137
  ]
138

    
139
-- | The list of UUID fields.
140
uuidFields :: (UuidObject a) => String -> FieldList a b
141
uuidFields name =
142
  [ (FieldDefinition "uuid" "UUID" QFTText  (name ++ " UUID"),
143
     FieldSimple (rsNormal . uuidOf), QffNormal) ]
144

    
145
-- | The list of serial number fields.
146
serialFields :: (SerialNoObject a) => String -> FieldList a b
147
serialFields name =
148
  [ (FieldDefinition "serial_no" "SerialNo" QFTNumber
149
     (name ++ " object serial number, incremented on each modification"),
150
     FieldSimple (rsNormal . serialOf), QffNormal) ]
151

    
152
-- | The list of tag fields.
153
tagsFields :: (TagsObject a) => FieldList a b
154
tagsFields =
155
  [ (FieldDefinition "tags" "Tags" QFTOther "Tags",
156
     FieldSimple (rsNormal . tagsOf), QffNormal) ]
157

    
158
-- * Generic parameter functions
159

    
160
-- | Returns a field from a (possibly missing) 'DictObject'. This is
161
-- used by parameter dictionaries, usually. Note that we have two
162
-- levels of maybe: the top level dict might be missing, or one key in
163
-- the dictionary might be.
164
dictFieldGetter :: (DictObject a) => String -> Maybe a -> ResultEntry
165
dictFieldGetter k = maybe rsNoData (rsMaybeNoData . lookup k . toDict)
166

    
167
-- | Ndparams optimised lookup map.
168
ndParamTypes :: Map.Map String FieldType
169
ndParamTypes = Map.map vTypeToQFT C.ndsParameterTypes
170

    
171
-- | Ndparams title map.
172
ndParamTitles :: Map.Map String FieldTitle
173
ndParamTitles = C.ndsParameterTitles
174

    
175
-- | Ndparam getter builder: given a field, it returns a FieldConfig
176
-- getter, that is a function that takes the config and the object and
177
-- returns the Ndparam field specified when the getter was built.
178
ndParamGetter :: (NdParamObject a) =>
179
                 String -- ^ The field we're building the getter for
180
              -> ConfigData -> a -> ResultEntry
181
ndParamGetter field config =
182
  dictFieldGetter field . getNdParamsOf config
183

    
184
-- | Builds the ndparam fields for an object.
185
buildNdParamField :: (NdParamObject a) => String -> FieldData a b
186
buildNdParamField field =
187
  let full_name = "ndp/" ++ field
188
      title = fromMaybe field $ field `Map.lookup` ndParamTitles
189
      qft = fromMaybe QFTOther $ field `Map.lookup` ndParamTypes
190
      desc = "The \"" ++ field ++ "\" node parameter"
191
  in (FieldDefinition full_name title qft desc,
192
      FieldConfig (ndParamGetter field), QffNormal)
193

    
194
-- | Looks up the default hypervisor and its hvparams
195
getDefaultHypervisorSpec :: ConfigData -> (Hypervisor, HvParams)
196
getDefaultHypervisorSpec cfg = (hv, getHvParamsFromCluster cfg hv)
197
  where hv = getDefaultHypervisor cfg
198

    
199
-- | Looks up the cluster's hvparams of the given hypervisor
200
getHvParamsFromCluster :: ConfigData -> Hypervisor -> HvParams
201
getHvParamsFromCluster cfg hv =
202
  fromMaybe (GenericContainer Map.empty) .
203
    Map.lookup (hypervisorToRaw hv) .
204
      fromContainer . clusterHvparams $ configCluster cfg