Add support for 'offline' nodes
[ganeti-local] / Ganeti / HTools / Rapi.hs
1 {-| Implementation of the RAPI client interface.
2
3 -}
4
5 module Ganeti.HTools.Rapi
6     (
7       getNodes
8     , getInstances
9     ) where
10
11 import Network.Curl
12 import Network.Curl.Types ()
13 import Network.Curl.Code
14 import Data.Either ()
15 import Data.Maybe
16 import Control.Monad
17 import Text.JSON
18 import Text.Printf (printf)
19 import Ganeti.HTools.Utils
20
21
22 -- Some constants
23
24 -- | The fixed drbd overhead per disk (only used with 1.2's sdx_size)
25 drbdOverhead = 128
26
27 getUrl :: String -> IO (Either String String)
28 getUrl url = do
29   (code, body) <- curlGetString url [CurlSSLVerifyPeer False,
30                                      CurlSSLVerifyHost 0]
31   return (case code of
32             CurlOK -> Right body
33             _ -> Left $ printf "Curl error for '%s', error %s"
34                  url (show code))
35
36 tryRapi :: String -> String -> IO (Either String String)
37 tryRapi url1 url2 =
38     do
39       body1 <- getUrl url1
40       (case body1 of
41          Left _ -> getUrl url2
42          Right _ -> return body1)
43
44 getInstances :: String -> IO (Either String String)
45 getInstances master =
46     let
47         url2 = printf "https://%s:5080/2/instances?bulk=1" master
48         url1 = printf "http://%s:5080/instances?bulk=1" master
49     in do
50       body <- tryRapi url1 url2
51       let inst = body `combineEithers`
52                  loadJSArray `combineEithers`
53                  (parseEitherList parseInstance)
54       return inst
55
56 getNodes :: String -> IO (Either String String)
57 getNodes master =
58     let
59         url2 = printf "https://%s:5080/2/nodes?bulk=1" master
60         url1 = printf "http://%s:5080/nodes?bulk=1" master
61     in do
62       body <- tryRapi url1 url2
63       let inst = body `combineEithers`
64                  loadJSArray `combineEithers`
65                  (parseEitherList parseNode)
66       return inst
67
68 parseInstance :: JSObject JSValue -> Either String String
69 parseInstance a =
70     let name = getStringElement "name" a
71         disk = case getIntElement "disk_usage" a of
72                  Left _ -> let log_sz = applyEither2 (+)
73                                         (getIntElement "sda_size" a)
74                                         (getIntElement "sdb_size" a)
75                            in applyEither2 (+) log_sz
76                                   (Right $ drbdOverhead * 2)
77                  Right x -> Right x
78         bep = fromObj "beparams" a
79         pnode = getStringElement "pnode" a
80         snode = (eitherListHead $ getListElement "snodes" a)
81                 `combineEithers` readEitherString
82         mem = case bep of
83                 Left _ -> getIntElement "admin_ram" a
84                 Right o -> getIntElement "memory" o
85         running = getStringElement "status" a
86     in
87       concatEitherElems name $
88                   concatEitherElems (show `applyEither1` mem) $
89                   concatEitherElems (show `applyEither1` disk) $
90                   concatEitherElems running $
91                   concatEitherElems pnode snode
92
93 boolToYN :: Bool -> Either String String
94 boolToYN True = Right "Y"
95 boolToYN _ = Right "N"
96
97 parseNode :: JSObject JSValue -> Either String String
98 parseNode a =
99     let name = getStringElement "name" a
100         offline = getBoolElement "offline" a
101         drained = getBoolElement "drained" a
102         mtotal = getIntElement "mtotal" a
103         mnode = getIntElement "mnode" a
104         mfree = getIntElement "mfree" a
105         dtotal = getIntElement "dtotal" a
106         dfree = getIntElement "dfree" a
107     in concatEitherElems name $
108        (case offline of
109           Right True -> Right "0|0|0|0|0|Y"
110           _ ->
111               concatEitherElems (show `applyEither1` mtotal) $
112               concatEitherElems (show `applyEither1` mnode) $
113               concatEitherElems (show `applyEither1` mfree) $
114               concatEitherElems (show `applyEither1` dtotal) $
115               concatEitherElems (show `applyEither1` dfree)
116               ((applyEither2 (||) offline drained) `combineEithers` boolToYN)
117        )