On Tue, Sep 25, 2012 at 06:43:47PM +0200, Agata Murawska wrote:
> Implementation of nodegroup queries in Haskell. This is not yet
> complete as we are missing merged disk parameters and option
> want_diskparams is not implemented.
> 
> Signed-off-by: Agata Murawska <[email protected]>
> ---
>  Makefile.am                  |    1 +
>  htools/Ganeti/Query/Group.hs |   89 
> ++++++++++++++++++++++++++++++++++++++++++
>  htools/Ganeti/Query/Query.hs |   22 ++++++++++
>  3 files changed, 112 insertions(+), 0 deletions(-)
>  create mode 100644 htools/Ganeti/Query/Group.hs
> 
> diff --git a/Makefile.am b/Makefile.am
> index 7ae24ef..1e13fdb 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -434,6 +434,7 @@ HS_LIB_SRCS = \
>       htools/Ganeti/Path.hs \
>       htools/Ganeti/Query/Common.hs \
>       htools/Ganeti/Query/Filter.hs \
> +     htools/Ganeti/Query/Group.hs \
>       htools/Ganeti/Query/Language.hs \
>       htools/Ganeti/Query/Node.hs \
>       htools/Ganeti/Query/Query.hs \
> diff --git a/htools/Ganeti/Query/Group.hs b/htools/Ganeti/Query/Group.hs
> new file mode 100644
> index 0000000..b4fc758
> --- /dev/null
> +++ b/htools/Ganeti/Query/Group.hs
> @@ -0,0 +1,89 @@
> +{-| Implementation of the Ganeti Query2 node group queries.
> +
> + -}
> +
> +{-
> +
> +Copyright (C) 2012 Google Inc.
> +
> +This program is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 2 of the License, or
> +(at your option) any later version.
> +
> +This program is distributed in the hope that it will be useful, but
> +WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with this program; if not, write to the Free Software
> +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> +02110-1301, USA.
> +
> +-}
> +
> +module Ganeti.Query.Group
> +  ( GroupRuntime(..)
> +  , groupFieldsMap
> +  ) where
> +
> +import qualified Data.Map as Map
> +
> +import Ganeti.Config
> +import Ganeti.Objects
> +import Ganeti.Query.Language
> +import Ganeti.Query.Common
> +import Ganeti.Query.Types
> +
> +-- | There is no runtime.
> +data GroupRuntime = GroupRuntime
> +
> +groupFields :: FieldList NodeGroup GroupRuntime
> +groupFields =
> +  [ (FieldDefinition "alloc_policy" "AllocPolicy" QFTText
> +       "Allocation policy for group",
> +     FieldSimple (rsNormal . groupAllocPolicy))
> +  , (FieldDefinition "custom_diskparams" "CustomDiskParameters" QFTOther
> +       "Custom disk parameters",
> +     FieldSimple (rsNormal . groupDiskparams))
> +  , (FieldDefinition "custom_ipolicy" "CustomInstancePolicy" QFTOther
> +       "Custom instance policy limitations",
> +     FieldSimple (rsNormal . groupIpolicy))
> +  , (FieldDefinition "custom_ndparams" "CustomNDParams" QFTOther
> +       "Custom node parameters",
> +     FieldSimple (rsNormal . groupNdparams))
> +  -- This is deliberate - I do not think we want to have RSUnknown here

Indeed, but I fear rsNormal is not good - this would fail unittests, I
think. You need rsNoData.

> +  , (FieldDefinition "diskparams" "DiskParameters" QFTOther
> +       "Disk parameters (merged)",
> +     FieldSimple (\ _ -> rsNormal (Nothing:: Maybe DiskParams)))
> +  , (FieldDefinition "ipolicy" "InstancePolicy" QFTOther
> +       "Instance policy limitations (merged)",
> +     FieldConfig (\cfg ng -> rsNormal (getGroupIpolicy cfg ng)))
> +  , (FieldDefinition "name" "Group" QFTText "Group name",
> +     FieldSimple (rsNormal . groupName))
> +  , (FieldDefinition "ndparams" "NDParams" QFTOther "Node parameters",
> +     FieldConfig (\cfg ng -> rsNormal (getGroupNdParams cfg ng)))
> +  , (FieldDefinition "node_cnt" "Nodes" QFTNumber "Number of nodes",
> +     FieldConfig (\cfg -> rsNormal . length . getGroupNodes cfg . groupName))
> +  , (FieldDefinition "node_list" "NodeList" QFTOther "List of nodes",
> +     FieldConfig (\cfg -> rsNormal . map nodeName .
> +                          getGroupNodes cfg . groupName))
> +  , (FieldDefinition "pinst_cnt" "Instances" QFTNumber
> +       "Number of primary instances",
> +     FieldConfig
> +       (\cfg -> rsNormal . length . fst . getGroupInstances cfg . groupName))
> +  , (FieldDefinition "pinst_list" "InstanceList" QFTOther
> +       "List of primary instances",
> +     FieldConfig (\cfg -> rsNormal . map instName . fst .
> +                          getGroupInstances cfg . groupName))
> +  ] ++
> +  map buildNdParamField allNDParamFields ++
> +  timeStampFields ++
> +  uuidFields "Group" ++
> +  serialFields "Group" ++
> +  tagsFields
> +
> +-- | The group fields map.
> +groupFieldsMap :: FieldMap NodeGroup GroupRuntime
> +groupFieldsMap = Map.fromList $ map (\v -> (fdefName (fst v), v)) groupFields
> diff --git a/htools/Ganeti/Query/Query.hs b/htools/Ganeti/Query/Query.hs
> index 5b09c63..8fc4b4a 100644
> --- a/htools/Ganeti/Query/Query.hs
> +++ b/htools/Ganeti/Query/Query.hs
> @@ -61,6 +61,7 @@ import Ganeti.Query.Common
>  import Ganeti.Query.Filter
>  import Ganeti.Query.Types
>  import Ganeti.Query.Node
> +import Ganeti.Query.Group
>  import Ganeti.Objects
>  
>  -- * Helper functions
> @@ -109,6 +110,20 @@ query cfg (Query QRNode fields qfilter) = return $ do
>                fnodes
>    return QueryResult { qresFields = fdefs, qresData = fdata }
>  
> +query cfg (Query QRGroup fields qfilter) = return $ do
> +  -- FIXME: want_diskparams is defaulted to false and not taken as parameter
> +  -- This is because the type for DiskParams is right now too generic for 
> merges
> +  -- (or else I cannot see how to do this with curent implementation)

This should be doable already with Ganeti/Objects/fillDict, which was
added for this purpose. It's not yet used, so I don't know how well it
works. Please commit as is for now and we'll see later about migrating
to that.

> +  cfilter <- compileFilter groupFieldsMap qfilter
> +  let selected = getSelectedFields groupFieldsMap fields
> +      (fdefs, fgetters) = unzip selected
> +      groups = Map.elems . fromContainer $ configNodegroups cfg
> +  -- there is no live data for groups, so filtering is much simpler
> +  fgroups <- filterM (\n -> evaluateFilter cfg Nothing n cfilter) groups
> +  let fdata = map (\node ->
> +                       map (execGetter cfg GroupRuntime node) fgetters) 
> fgroups
> +  return QueryResult {qresFields = fdefs, qresData = fdata }
> +
>  query _ (Query qkind _ _) =
>    return . Bad $ "Query '" ++ show qkind ++ "' not supported"
>  
> @@ -120,5 +135,12 @@ queryFields (QueryFields QRNode fields) =
>                     else getSelectedFields nodeFieldsMap fields
>    in Ok $ QueryFieldsResult (map fst selected)
>  
> +queryFields (QueryFields QRGroup fields) =
> +  let selected = if null fields
> +                   then map snd $ Map.toAscList groupFieldsMap
> +                   else getSelectedFields groupFieldsMap fields
> +  in Ok $ QueryFieldsResult (map fst selected)

Hmm, this being identical to the QueryField QRNode one, it smells like a
type class. Please add a FIXME, this should be generalisable easily.

LGTM after fixing rsNormal/rsNoData above.

thanks!
iustin

Reply via email to