1 {-| Implementation of the Ganeti Query2 common objects.
7 Copyright (C) 2012, 2013 Google Inc.
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.
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.
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
26 module Ganeti.Query.Common
43 import qualified Data.Map as Map
44 import Data.Maybe (fromMaybe)
45 import Text.JSON (JSON, showJSON)
47 import qualified Ganeti.Constants as C
51 import Ganeti.Query.Language
52 import Ganeti.Query.Types
55 -- * Generic functions
57 -- | Conversion from 'VType' to 'FieldType'.
58 vTypeToQFT :: VType -> FieldType
59 vTypeToQFT VTypeString = QFTOther
60 vTypeToQFT VTypeMaybeString = QFTOther
61 vTypeToQFT VTypeBool = QFTBool
62 vTypeToQFT VTypeSize = QFTUnit
63 vTypeToQFT VTypeInt = QFTNumber
67 -- | Helper for a result with no data.
68 rsNoData :: ResultEntry
69 rsNoData = ResultEntry RSNoData Nothing
71 -- | Helper for result for an entity which supports no such field.
72 rsUnavail :: ResultEntry
73 rsUnavail = ResultEntry RSUnavail Nothing
75 -- | Helper to declare a normal result.
76 rsNormal :: (JSON a) => a -> ResultEntry
77 rsNormal a = ResultEntry RSNormal $ Just (showJSON a)
79 -- | Helper to declare a result from a 'Maybe' (the item might be
80 -- missing, in which case we return no data). Note that there's some
81 -- ambiguity here: in some cases, we mean 'RSNoData', but in other
82 -- 'RSUnavail'; this is easy to solve in simple cases, but not in
83 -- nested dicts. If you want to return 'RSUnavail' in case of 'Nothing'
84 -- use the function 'rsMaybeUnavail'.
85 rsMaybeNoData :: (JSON a) => Maybe a -> ResultEntry
86 rsMaybeNoData = maybe rsNoData rsNormal
88 -- | Helper to declare a result from a 'Maybe'. This version returns
89 -- a 'RSUnavail' in case of 'Nothing'. It should be used for optional
90 -- fields that are not set. For cases where 'Nothing' means that there
91 -- was an error, consider using 'rsMaybe' instead.
92 rsMaybeUnavail :: (JSON a) => Maybe a -> ResultEntry
93 rsMaybeUnavail = maybe rsUnavail rsNormal
95 -- | Helper for unknown field result.
96 rsUnknown :: ResultEntry
97 rsUnknown = ResultEntry RSUnknown Nothing
99 -- | Helper for a missing runtime parameter.
100 missingRuntime :: FieldGetter a b
101 missingRuntime = FieldRuntime (\_ _ -> ResultEntry RSNoData Nothing)
103 -- * Error conversion
105 -- | Convert RpcError to ResultStatus
106 rpcErrorToStatus :: RpcError -> ResultStatus
107 rpcErrorToStatus OfflineNodeError = RSOffline
108 rpcErrorToStatus _ = RSNoData
112 -- | The list of timestamp fields.
113 timeStampFields :: (TimeStampObject a) => FieldList a b
115 [ (FieldDefinition "ctime" "CTime" QFTTimestamp "Creation timestamp",
116 FieldSimple (rsNormal . cTimeOf), QffNormal)
117 , (FieldDefinition "mtime" "MTime" QFTTimestamp "Modification timestamp",
118 FieldSimple (rsNormal . mTimeOf), QffNormal)
121 -- | The list of UUID fields.
122 uuidFields :: (UuidObject a) => String -> FieldList a b
124 [ (FieldDefinition "uuid" "UUID" QFTText (name ++ " UUID"),
125 FieldSimple (rsNormal . uuidOf), QffNormal) ]
127 -- | The list of serial number fields.
128 serialFields :: (SerialNoObject a) => String -> FieldList a b
130 [ (FieldDefinition "serial_no" "SerialNo" QFTNumber
131 (name ++ " object serial number, incremented on each modification"),
132 FieldSimple (rsNormal . serialOf), QffNormal) ]
134 -- | The list of tag fields.
135 tagsFields :: (TagsObject a) => FieldList a b
137 [ (FieldDefinition "tags" "Tags" QFTOther "Tags",
138 FieldSimple (rsNormal . tagsOf), QffNormal) ]
140 -- * Generic parameter functions
142 -- | Returns a field from a (possibly missing) 'DictObject'. This is
143 -- used by parameter dictionaries, usually. Note that we have two
144 -- levels of maybe: the top level dict might be missing, or one key in
145 -- the dictionary might be.
146 dictFieldGetter :: (DictObject a) => String -> Maybe a -> ResultEntry
147 dictFieldGetter k = maybe rsNoData (rsMaybeNoData . lookup k . toDict)
149 -- | Ndparams optimised lookup map.
150 ndParamTypes :: Map.Map String FieldType
151 ndParamTypes = Map.map vTypeToQFT C.ndsParameterTypes
153 -- | Ndparams title map.
154 ndParamTitles :: Map.Map String FieldTitle
155 ndParamTitles = C.ndsParameterTitles
157 -- | Ndparam getter builder: given a field, it returns a FieldConfig
158 -- getter, that is a function that takes the config and the object and
159 -- returns the Ndparam field specified when the getter was built.
160 ndParamGetter :: (NdParamObject a) =>
161 String -- ^ The field we're building the getter for
162 -> ConfigData -> a -> ResultEntry
163 ndParamGetter field config =
164 dictFieldGetter field . getNdParamsOf config
166 -- | Builds the ndparam fields for an object.
167 buildNdParamField :: (NdParamObject a) => String -> FieldData a b
168 buildNdParamField field =
169 let full_name = "ndp/" ++ field
170 title = fromMaybe field $ field `Map.lookup` ndParamTitles
171 qft = fromMaybe QFTOther $ field `Map.lookup` ndParamTypes
172 desc = "The \"" ++ field ++ "\" node parameter"
173 in (FieldDefinition full_name title qft desc,
174 FieldConfig (ndParamGetter field), QffNormal)