1 {-| Implementation of the RAPI client interface.
9 import Network.Curl.Types ()
10 import Network.Curl.Code
15 import Text.Printf (printf)
19 {-- Our cheap monad-like stuff.
21 Thi is needed since Either e a is already a monad instance somewhere
22 in the standard libraries (Control.Monad.Error) and we don't need that
26 combine :: (Either String a) -> (a -> Either String b) -> (Either String b)
27 combine (Left s) _ = Left s
28 combine (Right s) f = f s
30 ensureList :: [Either String a] -> Either String [a]
35 (_, Left x) -> Left x -- should never happen
36 (Right e, Right a) -> Right (e:a)
40 listHead :: Either String [a] -> Either String a
44 Right (x:_) -> Right x
45 Right [] -> Left "List empty"
47 loadJSArray :: String -> Either String [JSObject JSValue]
48 loadJSArray s = resultToEither $ decodeStrict s
50 fromObj :: JSON a => String -> JSObject JSValue -> Either String a
52 case lookup k (fromJSObject o) of
53 Nothing -> Left $ printf "key '%s' not found" k
54 Just val -> resultToEither $ readJSON val
56 getStringElement :: String -> JSObject JSValue -> Either String String
57 getStringElement key o = fromObj key o
59 getIntElement :: String -> JSObject JSValue -> Either String String
61 let tmp = (fromObj key o)::Either String Int
64 Right x -> Right $ show x
66 getListElement :: String -> JSObject JSValue
67 -> Either String [JSValue]
68 getListElement key o = fromObj key o
70 readString :: JSValue -> Either String String
73 JSString s -> Right $ fromJSString s
74 _ -> Left "Wrong JSON type"
76 concatElems :: Either String String
77 -> Either String String
78 -> Either String String
79 concatElems = apply2 (\x y -> x ++ "|" ++ y)
81 apply2 :: (a -> b -> c)
87 (Right x, Right y) -> Right $ fn x y
91 getUrl :: String -> IO (Either String String)
93 (code, body) <- curlGetString url [CurlSSLVerifyPeer False,
97 _ -> Left $ printf "Curl error for '%s', error %s"
100 tryRapi :: String -> String -> IO (Either String String)
105 return (case body1 of
109 getInstances :: String -> IO (Either String String)
110 getInstances master =
112 url2 = printf "https://%s:5080/2/instances?bulk=1" master
113 url1 = printf "http://%s:5080/instances?bulk=1" master
115 body <- tryRapi url1 url2
116 let inst = body `combine` loadJSArray `combine` (parseList parseInstance)
119 getNodes :: String -> IO (Either String String)
122 url2 = printf "https://%s:5080/2/nodes?bulk=1" master
123 url1 = printf "http://%s:5080/nodes?bulk=1" master
125 body <- tryRapi url1 url2
126 let inst = body `combine` loadJSArray `combine` (parseList parseNode)
129 parseList :: (JSObject JSValue -> Either String String)
130 -> [JSObject JSValue]
131 ->Either String String
133 let ml = ensureList $ map fn idata
134 in ml `combine` (Right . unlines)
136 parseInstance :: JSObject JSValue -> Either String String
138 let name = getStringElement "name" a
139 disk = case getIntElement "disk_usage" a of
140 Left _ -> apply2 (\x y -> show $ ((read x)::Int) + ((read y)::Int))
141 (getIntElement "sda_size" a)
142 (getIntElement "sdb_size" a)
144 bep = fromObj "beparams" a
145 pnode = getStringElement "pnode" a
146 snode = (listHead $ getListElement "snodes" a) `combine` readString
148 Left _ -> getIntElement "admin_ram" a
151 concatElems name $ concatElems mem $
152 concatElems disk $ concatElems pnode snode
154 parseNode :: JSObject JSValue -> Either String String
156 let name = getStringElement "name" a
157 mtotal = getIntElement "mtotal" a
158 mfree = getIntElement "mfree" a
159 dtotal = getIntElement "dtotal" a
160 dfree = getIntElement "dfree" a
161 in concatElems name $ concatElems mtotal $ concatElems mfree $
162 concatElems dtotal dfree