On Tue, Oct 25, 2011 at 04:54:06PM +0200, Agata Murawska wrote:
> The status field in response to a generic query is now supported, with
> error status used to provide user with more information.
> 
> Note:
> The code in THH.hs is temporary, as generalization of declareIADT and
> declareSADT is in the next patch.
> 
> Signed-off-by: Agata Murawska <[email protected]>
> ---
>  htools/Ganeti/HTools/Luxi.hs |   51 +++++++++++++++-----------
>  htools/Ganeti/Luxi.hs        |   19 ++++++++++
>  htools/Ganeti/THH.hs         |   81 
> ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 130 insertions(+), 21 deletions(-)
> 
> diff --git a/htools/Ganeti/HTools/Luxi.hs b/htools/Ganeti/HTools/Luxi.hs
> index 1249e22..8ed4761 100644
> --- a/htools/Ganeti/HTools/Luxi.hs
> +++ b/htools/Ganeti/HTools/Luxi.hs
> @@ -69,22 +69,28 @@ parseQueryResult o =
>      fail $ "Invalid query result, expected array but got " ++ show o
>  
>  -- | Prepare resulting output as parsers expect it.
> -extractArray :: (Monad m) => JSValue -> m [JSValue]
> +extractArray :: (Monad m) => JSValue -> m [[(JSValue, JSValue)]]
>  extractArray v =
> -  getData v >>= parseQueryResult >>= (return . map (JSArray . map snd))
> +  getData v >>= parseQueryResult
> +
> +-- | Testing responce status for more verbose error message.
typo responce → response

> +fromJValWithStatus :: (Text.JSON.JSON a, Monad m) => JSValue -> JSValue -> m 
> a
> +fromJValWithStatus st v = do
> +    st' <- fromJVal st
> +    L.checkRS st' v >>= fromJVal

It seems that later on you're always calling from JValWithStatus via
uncurry. Maybe define it directly curried?

>  -- | Annotate errors when converting values with owner/attribute for
>  -- better debugging.
>  genericConvert :: (Text.JSON.JSON a) =>
> -                  String     -- ^ The object type
> -               -> String     -- ^ The object name
> -               -> String     -- ^ The attribute we're trying to convert
> -               -> JSValue    -- ^ The value we try to convert
> -               -> Result a   -- ^ The annotated result
> +                  String             -- ^ The object type
> +               -> String             -- ^ The object name
> +               -> String             -- ^ The attribute we're trying to 
> convert
> +               -> (JSValue, JSValue) -- ^ The value we're trying to convert
> +               -> Result a           -- ^ The annotated result
>  genericConvert otype oname oattr =
>      annotateResult (otype ++ " '" ++ oname ++
>                      "', error while reading attribute '" ++
> -                    oattr ++ "'") . fromJVal
> +                    oattr ++ "'") . uncurry fromJValWithStatus
>  
>  -- * Data querying functionality
>  
> @@ -135,16 +141,17 @@ getInstances ktn arr = extractArray arr >>= mapM 
> (parseInstance ktn)
>  
>  -- | Construct an instance from a JSON object.
>  parseInstance :: NameAssoc
> -              -> JSValue
> +              -> [(JSValue, JSValue)]
>                -> Result (String, Instance.Instance)

Side-note: I wonder how will this fail if we don't get an JSArray…

> -parseInstance ktn (JSArray [ name, disk, mem, vcpus
> -                           , status, pnode, snodes, tags, oram
> -                           , auto_balance, disk_template ]) = do
> -  xname <- annotateResult "Parsing new instance" (fromJVal name)
> +parseInstance ktn [ name, disk, mem, vcpus
> +                  , status, pnode, snodes, tags, oram
> +                  , auto_balance, disk_template ] = do
> +  xname <- annotateResult "Parsing new instance"
> +           (uncurry fromJValWithStatus name)
>    let convert a = genericConvert "Instance" xname a
>    xdisk <- convert "disk_usage" disk
>    xmem <- (case oram of
> -             JSRational _ _ -> convert "oper_ram" oram
> +             (_, JSRational _ _) -> convert "oper_ram" oram

Hmm, this will need to be fixed: the case above was checking if we got a
rational or a null, but now we know if we have data or not based on
whether the status field is RS_OK or RS_NODATA (or UNAVAIL, etc.). Could
you add a fixme to remove the "guessing"?

>               _ -> convert "be/memory" mem)
>    xvcpus <- convert "be/vcpus" vcpus
>    xpnode <- convert "pnode" pnode >>= lookupNode ktn xname
> @@ -166,11 +173,12 @@ getNodes :: NameAssoc -> JSValue -> Result [(String, 
> Node.Node)]
>  getNodes ktg arr = extractArray arr >>= mapM (parseNode ktg)
>  
>  -- | Construct a node from a JSON object.
> -parseNode :: NameAssoc -> JSValue -> Result (String, Node.Node)
> -parseNode ktg (JSArray [ name, mtotal, mnode, mfree, dtotal, dfree
> -                       , ctotal, offline, drained, vm_capable, g_uuid ])
> +parseNode :: NameAssoc -> [(JSValue, JSValue)] -> Result (String, Node.Node)
> +parseNode ktg [ name, mtotal, mnode, mfree, dtotal, dfree
> +              , ctotal, offline, drained, vm_capable, g_uuid ]
>      = do
> -  xname <- annotateResult "Parsing new node" (fromJVal name)
> +  xname <- annotateResult "Parsing new node"
> +           (uncurry fromJValWithStatus name)
>    let convert a = genericConvert "Node" xname a
>    xoffline <- convert "offline" offline
>    xdrained <- convert "drained" drained
> @@ -203,9 +211,10 @@ getGroups :: JSValue -> Result [(String, Group.Group)]
>  getGroups jsv = extractArray jsv >>= mapM parseGroup
>  
>  -- | Parses a given group information.
> -parseGroup :: JSValue -> Result (String, Group.Group)
> -parseGroup (JSArray [uuid, name, apol]) = do
> -  xname <- annotateResult "Parsing new group" (fromJVal name)
> +parseGroup :: [(JSValue, JSValue)] -> Result (String, Group.Group)
> +parseGroup [uuid, name, apol] = do
> +  xname <- annotateResult "Parsing new group"
> +           (uncurry fromJValWithStatus name)
>    let convert a = genericConvert "Group" xname a
>    xuuid <- convert "uuid" uuid
>    xapol <- convert "alloc_policy" apol
> diff --git a/htools/Ganeti/Luxi.hs b/htools/Ganeti/Luxi.hs
> index 20c0b14..7456a35 100644
> --- a/htools/Ganeti/Luxi.hs
> +++ b/htools/Ganeti/Luxi.hs
> @@ -28,7 +28,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
> MA
>  module Ganeti.Luxi
>      ( LuxiOp(..)
>      , QrViaLuxi(..)
> +    , ResponseStatus(..)
>      , Client
> +    , checkRS
>      , getClient
>      , closeClient
>      , callMethod
> @@ -145,6 +147,23 @@ $(genLuxiOp "LuxiOp"
>  -- | The serialisation of LuxiOps into strings in messages.
>  $(genStrOfOp ''LuxiOp "strOfOp")
>  
> +$(declareIADT "ResponseStatus"

FYI, this is in Python "result status", not "response status".

> +     [ ("RSNormal", 'rsNormal)
> +     , ("RSUnknown", 'rsUnknown)
> +     , ("RSNoData", 'rsNodata)
> +     , ("RSUnavailable", 'rsUnavail)
> +     , ("RSOffline", 'rsOffline)
> +     ])
> +$(makeJSONInstanceInt ''ResponseStatus)
> +
> +-- | Check that ResponseStatus is success or fail with descriptive message.
> +checkRS :: (Monad m) => ResponseStatus -> a -> m a
> +checkRS RSNormal val    = return val
> +checkRS RSUnknown _     = fail "Unknown field"
> +checkRS RSNoData _      = fail "No data for a field"
> +checkRS RSUnavailable _ = fail "Ganeti reports unavailable data"
> +checkRS RSOffline _     = fail "Ganeti reports resource as offline"
> +
>  -- | The end-of-message separator.
>  eOM :: Char
>  eOM = '\3'
> diff --git a/htools/Ganeti/THH.hs b/htools/Ganeti/THH.hs
> index 6bb377e..e3c1110 100644
> --- a/htools/Ganeti/THH.hs
> +++ b/htools/Ganeti/THH.hs
> @@ -30,7 +30,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
> MA
>  -}

All the changes to THH.hs could have been a separate patch (Introduce
declareIADT), by the way, since they are not functionally related to the
result status parsing. Just FYI.

LGTM, thanks.

iustin

Reply via email to