On Fri, Jan 7, 2011 at 15:02, Iustin Pop <[email protected]> wrote:
> Currently, fromObj/maybeFromObj take first the key, and then the
> object. This is suboptimal, as this form is not easy to use with
> partial functional application.
>
> To make it easier to switch between tryFromObj, fromObj and
> maybeFromObj, we unify the latter two functions to the same order
> (object and then key) like the first one. The code churn in the other
> modules is due to this, but the main change in this patch is in
> Utils.hs.
>
> Furthermore, since we change anyway the calls, we do replace fromObj
> with tryFromObj in IAllocator.hs so that we get better error messages.
> ---
> Ganeti/HTools/IAlloc.hs | 66
> +++++++++++++++++++++++++----------------------
> Ganeti/HTools/Utils.hs | 14 +++++-----
> Ganeti/Luxi.hs | 8 +++---
> Ganeti/OpCodes.hs | 31 +++++++++++----------
> 4 files changed, 62 insertions(+), 57 deletions(-)
>
> diff --git a/Ganeti/HTools/IAlloc.hs b/Ganeti/HTools/IAlloc.hs
> index 903801a..228b408 100644
> --- a/Ganeti/HTools/IAlloc.hs
> +++ b/Ganeti/HTools/IAlloc.hs
> @@ -4,7 +4,7 @@
>
> {-
>
> -Copyright (C) 2009, 2010 Google Inc.
> +Copyright (C) 2009, 2010, 2011 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
> @@ -50,10 +50,11 @@ parseBaseInstance :: String
> -> [(String, JSValue)]
> -> Result (String, Instance.Instance)
> parseBaseInstance n a = do
> - disk <- fromObj "disk_space_total" a
> - mem <- fromObj "memory" a
> - vcpus <- fromObj "vcpus" a
> - tags <- fromObj "tags" a
> + let extract x = tryFromObj ("invalid data for instance '" ++ n ++ "'") a
> x
> + disk <- extract "disk_space_total"
> + mem <- extract "memory"
> + vcpus <- extract "vcpus"
> + tags <- extract "tags"
> let running = "running"
> return (n, Instance.create n mem disk vcpus running tags 0 0)
>
> @@ -64,7 +65,7 @@ parseInstance :: NameAssoc -- ^ The node
> name-to-index association list
> -> Result (String, Instance.Instance)
> parseInstance ktn n a = do
> base <- parseBaseInstance n a
> - nodes <- fromObj "nodes" a
> + nodes <- fromObj a "nodes"
> pnode <- if null nodes
> then Bad $ "empty node list for instance " ++ n
> else readEitherString $ head nodes
> @@ -80,19 +81,20 @@ parseNode :: NameAssoc -- ^ The group
> association
> -> [(String, JSValue)] -- ^ The JSON object
> -> Result (String, Node.Node)
> parseNode ktg n a = do
> - offline <- fromObj "offline" a
> - drained <- fromObj "drained" a
> - guuid <- fromObj "group" a
> + let extract x = tryFromObj ("invalid data for node '" ++ n ++ "'") a x
> + offline <- extract "offline"
> + drained <- extract "drained"
> + guuid <- extract "group"
> gidx <- lookupGroup ktg n guuid
> node <- (if offline || drained
> then return $ Node.create n 0 0 0 0 0 0 True gidx
> else do
> - mtotal <- fromObj "total_memory" a
> - mnode <- fromObj "reserved_memory" a
> - mfree <- fromObj "free_memory" a
> - dtotal <- fromObj "total_disk" a
> - dfree <- fromObj "free_disk" a
> - ctotal <- fromObj "total_cpus" a
> + mtotal <- extract "total_memory"
> + mnode <- extract "reserved_memory"
> + mfree <- extract "free_memory"
> + dtotal <- extract "total_disk"
> + dfree <- extract "free_disk"
> + ctotal <- extract "total_cpus"
> return $ Node.create n mtotal mnode mfree
> dtotal dfree ctotal False gidx)
> return (n, node)
> @@ -102,7 +104,7 @@ parseGroup :: String -- ^ The group UUID
> -> [(String, JSValue)] -- ^ The JSON object
> -> Result (String, Group.Group)
> parseGroup u a = do
> - name <- fromObj "name" a
> + name <- fromObj a "name"
> return (u, Group.create name u AllocPreferred)
>
> -- | Top-level parser.
> @@ -111,48 +113,50 @@ parseData :: String -- ^ The JSON message as
> received from Ganeti
> parseData body = do
> decoded <- fromJResult "Parsing input IAllocator message" (decodeStrict
> body)
> let obj = fromJSObject decoded
> + extrObj x = tryFromObj "invalid iallocator message" obj x
> -- request parser
> - request <- liftM fromJSObject (fromObj "request" obj)
> + request <- liftM fromJSObject (extrObj "request")
> + let extrReq x = tryFromObj "invalid request dict" request x
> -- existing group parsing
> - glist <- liftM fromJSObject (fromObj "nodegroups" obj)
> + glist <- liftM fromJSObject (extrObj "nodegroups")
> gobj <- mapM (\(x, y) -> asJSObject y >>= parseGroup x . fromJSObject)
> glist
> let (ktg, gl) = assignIndices gobj
> -- existing node parsing
> - nlist <- liftM fromJSObject (fromObj "nodes" obj)
> + nlist <- liftM fromJSObject (extrObj "nodes")
> nobj <- mapM (\(x,y) ->
> asJSObject y >>= parseNode ktg x . fromJSObject) nlist
> let (ktn, nl) = assignIndices nobj
> -- existing instance parsing
> - ilist <- fromObj "instances" obj
> + ilist <- extrObj "instances"
> let idata = fromJSObject ilist
> iobj <- mapM (\(x,y) ->
> asJSObject y >>= parseInstance ktn x . fromJSObject)
> idata
> let (kti, il) = assignIndices iobj
> -- cluster tags
> - ctags <- fromObj "cluster_tags" obj
> + ctags <- extrObj "cluster_tags"
> cdata <- mergeData [] [] [] (ClusterData gl nl il ctags)
> let map_n = cdNodes cdata
> - optype <- fromObj "type" request
> + optype <- extrReq "type"
> rqtype <-
> case optype of
> "allocate" ->
> do
> - rname <- fromObj "name" request
> - req_nodes <- fromObj "required_nodes" request
> - inew <- parseBaseInstance rname request
> + rname <- extrReq "name"
> + req_nodes <- extrReq "required_nodes"
> + inew <- parseBaseInstance rname request
> let io = snd inew
> return $ Allocate io req_nodes
> "relocate" ->
> do
> - rname <- fromObj "name" request
> - ridx <- lookupInstance kti rname
> - req_nodes <- fromObj "required_nodes" request
> - ex_nodes <- fromObj "relocate_from" request
> - ex_idex <- mapM (Container.findByName map_n) ex_nodes
> + rname <- extrReq "name"
> + ridx <- lookupInstance kti rname
> + req_nodes <- extrReq "required_nodes"
> + ex_nodes <- extrReq "relocate_from"
> + ex_idex <- mapM (Container.findByName map_n) ex_nodes
> return $ Relocate ridx req_nodes (map Node.idx ex_idex)
> "multi-evacuate" ->
> do
> - ex_names <- fromObj "evac_nodes" request
> + ex_names <- extrReq "evac_nodes"
> ex_nodes <- mapM (Container.findByName map_n) ex_names
> let ex_ndx = map Node.idx ex_nodes
> return $ Evacuate ex_ndx
> diff --git a/Ganeti/HTools/Utils.hs b/Ganeti/HTools/Utils.hs
> index 6091858..1e58bc3 100644
> --- a/Ganeti/HTools/Utils.hs
> +++ b/Ganeti/HTools/Utils.hs
> @@ -2,7 +2,7 @@
>
> {-
>
> -Copyright (C) 2009, 2010 Google Inc.
> +Copyright (C) 2009, 2010, 2011 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
> @@ -127,16 +127,16 @@ loadJSArray :: (Monad m)
> loadJSArray s = fromJResult s . J.decodeStrict
>
> -- | Reads the value of a key in a JSON object.
> -fromObj :: (J.JSON a, Monad m) => String -> [(String, J.JSValue)] -> m a
> -fromObj k o =
> +fromObj :: (J.JSON a, Monad m) => [(String, J.JSValue)] -> String -> m a
> +fromObj o k =
> case lookup k o of
> Nothing -> fail $ printf "key '%s' not found in %s" k (show o)
> Just val -> fromKeyValue k val
>
> -- | Reads the value of an optional key in a JSON object.
> -maybeFromObj :: (J.JSON a, Monad m) => String -> [(String, J.JSValue)]
> - -> m (Maybe a)
> -maybeFromObj k o =
> +maybeFromObj :: (J.JSON a, Monad m) =>
> + [(String, J.JSValue)] -> String -> m (Maybe a)
> +maybeFromObj o k =
> case lookup k o of
> Nothing -> return Nothing
> Just val -> liftM Just (fromKeyValue k val)
> @@ -161,7 +161,7 @@ tryFromObj :: (J.JSON a) =>
> -> [(String, J.JSValue)] -- ^ The object array
> -> String -- ^ The desired key from the object
> -> Result a
> -tryFromObj t o k = annotateResult t (fromObj k o)
> +tryFromObj t o = annotateResult t . fromObj o
>
> -- | Small wrapper over readJSON.
> fromJVal :: (Monad m, J.JSON a) => J.JSValue -> m a
> diff --git a/Ganeti/Luxi.hs b/Ganeti/Luxi.hs
> index 1f65f1e..56024a5 100644
> --- a/Ganeti/Luxi.hs
> +++ b/Ganeti/Luxi.hs
> @@ -4,7 +4,7 @@
>
> {-
>
> -Copyright (C) 2009, 2010 Google Inc.
> +Copyright (C) 2009, 2010, 2011 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
> @@ -201,11 +201,11 @@ validateResult s = do
> oarr <- fromJResult "Parsing LUXI response"
> (decodeStrict s)::Result (JSObject JSValue)
> let arr = J.fromJSObject oarr
> - status <- fromObj (strOfKey Success) arr::Result Bool
> + status <- fromObj arr (strOfKey Success)::Result Bool
> let rkey = strOfKey Result
> (if status
> - then fromObj rkey arr
> - else fromObj rkey arr >>= fail)
> + then fromObj arr rkey
> + else fromObj arr rkey >>= fail)
>
> -- | Generic luxi method call.
> callMethod :: LuxiOp -> Client -> IO (Result JSValue)
> diff --git a/Ganeti/OpCodes.hs b/Ganeti/OpCodes.hs
> index 7b3e434..972a2dc 100644
> --- a/Ganeti/OpCodes.hs
> +++ b/Ganeti/OpCodes.hs
> @@ -4,7 +4,7 @@
>
> {-
>
> -Copyright (C) 2009, 2010 Google Inc.
> +Copyright (C) 2009, 2010, 2011 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
> @@ -72,28 +72,29 @@ opID (OpMigrateInstance _ _ _) = "OP_INSTANCE_MIGRATE"
> loadOpCode :: JSValue -> J.Result OpCode
> loadOpCode v = do
> o <- liftM J.fromJSObject (readJSON v)
> - op_id <- fromObj "OP_ID" o
> + let extract x = fromObj o x
> + op_id <- extract "OP_ID"
> case op_id of
> "OP_TEST_DELAY" -> do
> - on_nodes <- fromObj "on_nodes" o
> - on_master <- fromObj "on_master" o
> - duration <- fromObj "duration" o
> + on_nodes <- extract "on_nodes"
> + on_master <- extract "on_master"
> + duration <- extract "duration"
> return $ OpTestDelay duration on_master on_nodes
> "OP_INSTANCE_REPLACE_DISKS" -> do
> - inst <- fromObj "instance_name" o
> - node <- maybeFromObj "remote_node" o
> - mode <- fromObj "mode" o
> - disks <- fromObj "disks" o
> - ialloc <- maybeFromObj "iallocator" o
> + inst <- extract "instance_name"
> + node <- maybeFromObj o "remote_node"
> + mode <- extract "mode"
> + disks <- extract "disks"
> + ialloc <- maybeFromObj o "iallocator"
> return $ OpReplaceDisks inst node mode disks ialloc
> "OP_INSTANCE_FAILOVER" -> do
> - inst <- fromObj "instance_name" o
> - consist <- fromObj "ignore_consistency" o
> + inst <- extract "instance_name"
> + consist <- extract "ignore_consistency"
> return $ OpFailoverInstance inst consist
> "OP_INSTANCE_MIGRATE" -> do
> - inst <- fromObj "instance_name" o
> - live <- fromObj "live" o
> - cleanup <- fromObj "cleanup" o
> + inst <- extract "instance_name"
> + live <- extract "live"
> + cleanup <- extract "cleanup"
> return $ OpMigrateInstance inst live cleanup
> _ -> J.Error $ "Unknown opcode " ++ op_id
>
> --
> 1.7.3.1
>
>
LGTM++