1 {-| Implementation of the iallocator interface.
5 module Ganeti.HTools.IAlloc
15 import Text.Printf (printf)
16 import Ganeti.HTools.Utils ()
21 {-- Our cheap monad-like stuff.
23 Thi is needed since Either e a is already a monad instance somewhere
24 in the standard libraries (Control.Monad.Error) and we don't need that
28 combine :: (Either String a) -> (a -> Either String b) -> (Either String b)
29 combine (Left s) _ = Left s
30 combine (Right s) f = f s
32 ensureList :: [Either String a] -> Either String [a]
37 (_, Left x) -> Left x -- should never happen
38 (Right e, Right a) -> Right (e:a)
42 listHead :: Either String [a] -> Either String a
46 Right (x:_) -> Right x
47 Right [] -> Left "List empty"
49 loadJSArray :: String -> Either String [JSObject JSValue]
50 loadJSArray s = resultToEither $ decodeStrict s
52 fromObj :: JSON a => String -> JSObject JSValue -> Either String a
54 case lookup k (fromJSObject o) of
55 Nothing -> Left $ printf "key '%s' not found" k
56 Just val -> resultToEither $ readJSON val
58 getStringElement :: String -> JSObject JSValue -> Either String String
59 getStringElement = fromObj
61 getIntElement :: String -> JSObject JSValue -> Either String Int
62 getIntElement = fromObj
64 getListElement :: String -> JSObject JSValue
65 -> Either String [JSValue]
66 getListElement = fromObj
68 readString :: JSValue -> Either String String
71 JSString s -> Right $ fromJSString s
72 _ -> Left "Wrong JSON type"
74 concatElems :: Either String String
75 -> Either String String
76 -> Either String String
77 concatElems = apply2 (\x y -> x ++ "|" ++ y)
79 apply1 :: (a -> b) -> Either String a -> Either String b
83 Right y -> Right $ fn y
85 apply2 :: (a -> b -> c)
91 (Right x, Right y) -> Right $ fn x y
95 parseList :: (JSObject JSValue -> Either String String)
97 ->Either String String
99 let ml = ensureList $ map fn idata
100 in ml `combine` (Right . unlines)
102 parseInstance :: JSObject JSValue -> Either String String
104 let name = getStringElement "name" a
105 disk = case getIntElement "disk_usage" a of
106 Left _ -> let log_sz = apply2 (+)
107 (getIntElement "sda_size" a)
108 (getIntElement "sdb_size" a)
109 in apply2 (+) log_sz (Right $ 128 * 2)
111 bep = fromObj "beparams" a
112 pnode = getStringElement "pnode" a
113 snode = (listHead $ getListElement "snodes" a) `combine` readString
115 Left _ -> getIntElement "admin_ram" a
116 Right o -> getIntElement "memory" o
117 running = getStringElement "status" a
120 concatElems (show `apply1` mem) $
121 concatElems (show `apply1` disk) $
122 concatElems running $
123 concatElems pnode snode
125 parseNode :: JSObject JSValue -> Either String String
127 let name = getStringElement "name" a
128 mtotal = getIntElement "mtotal" a
129 mnode = getIntElement "mnode" a
130 mfree = getIntElement "mfree" a
131 dtotal = getIntElement "dtotal" a
132 dfree = getIntElement "dfree" a
133 in concatElems name $
134 concatElems (show `apply1` mtotal) $
135 concatElems (show `apply1` mnode) $
136 concatElems (show `apply1` mfree) $
137 concatElems (show `apply1` dtotal) (show `apply1` dfree)
139 parseData :: String -> Maybe String
143 formatResponse :: Bool -> String -> [String] -> String
144 formatResponse success info nodes =
146 e_success = ("success", JSBool success)
147 e_info = ("info", JSString . toJSString $ info)
148 e_nodes = ("nodes", JSArray $ map (JSString . toJSString) nodes)
149 in encodeStrict $ makeObj [e_success, e_info, e_nodes]