Revision 040afc35 Ganeti/HTools/Rapi.hs

b/Ganeti/HTools/Rapi.hs
4 4

  
5 5
module Ganeti.HTools.Rapi
6 6
    (
7
      getNodes
8
    , getInstances
7
      loadData
9 8
    ) where
10 9

  
11 10
import Network.Curl
12 11
import Network.Curl.Types ()
13 12
import Network.Curl.Code
14
import Data.Either ()
15
import Data.Maybe
16 13
import Data.List
17 14
import Control.Monad
18 15
import Text.JSON (JSObject, JSValue)
19 16
import Text.Printf (printf)
17

  
20 18
import Ganeti.HTools.Utils
19
import Ganeti.HTools.Loader
20
import qualified Ganeti.HTools.Node as Node
21
import qualified Ganeti.HTools.Instance as Instance
21 22

  
22 23
-- | Read an URL via curl and return the body if successful
23 24
getUrl :: (Monad m) => String -> IO (m String)
......
35 36
    if elem ':' master then  master
36 37
    else "https://" ++ master ++ ":5080"
37 38

  
38
getInstances :: String -> IO (Result String)
39
getInstances master = do
40
  let url2 = printf "%s/2/instances?bulk=1" (formatHost master)
41
  body <- getUrl url2
42
  return $ (do x <- body
43
               arr <- loadJSArray x
44
               ilist <- mapM parseInstance arr
45
               return $ unlines ilist)
39
getInstances :: NameAssoc
40
             -> String
41
             -> Result [(String, Instance.Instance)]
42
getInstances ktn body = do
43
  arr <- loadJSArray body
44
  ilist <- mapM (parseInstance ktn) arr
45
  return ilist
46 46

  
47
getNodes :: String -> IO (Result String)
48
getNodes master = do
49
  let url2 = printf "%s/2/nodes?bulk=1" (formatHost master)
50
  body <- getUrl url2
51
  return $ (do x <- body
52
               arr <- loadJSArray x
53
               nlist <- mapM parseNode arr
54
               return $ unlines nlist)
47
getNodes :: String -> Result [(String, Node.Node)]
48
getNodes body = do
49
  arr <- loadJSArray body
50
  nlist <- mapM parseNode arr
51
  return nlist
55 52

  
56
parseInstance :: JSObject JSValue -> Result String
57
parseInstance a =
58
    let name = getStringElement "name" a
59
        disk = getIntElement "disk_usage" a
60
        mem = getObjectElement "beparams" a >>= getIntElement "memory"
61
        pnode = getStringElement "pnode" a
62
        snode = (liftM head $ getListElement "snodes" a) >>= readEitherString
63
        running = getStringElement "status" a
64
    in
65
      name |+ (show `liftM` mem) |+
66
              (show `liftM` disk) |+
67
              running |+ pnode |+ snode
53
parseInstance :: [(String, Int)]
54
              -> JSObject JSValue
55
              -> Result (String, Instance.Instance)
56
parseInstance ktn a = do
57
  name <- fromObj "name" a
58
  disk <- fromObj "disk_usage" a
59
  mem <- fromObj "beparams" a >>= fromObj "memory"
60
  pnode <- fromObj "pnode" a >>= lookupNode ktn name
61
  snodes <- getListElement "snodes" a
62
  snode <- (if null snodes then return Node.noSecondary
63
            else readEitherString (head snodes) >>= lookupNode ktn name)
64
  running <- fromObj "status" a
65
  let inst = Instance.create mem disk running pnode snode
66
  return (name, inst)
68 67

  
69
boolToYN :: (Monad m) => Bool -> m String
70
boolToYN True = return "Y"
71
boolToYN _ = return "N"
68
parseNode :: JSObject JSValue -> Result (String, Node.Node)
69
parseNode a = do
70
    name <- fromObj "name" a
71
    offline <- fromObj "offline" a
72
    node <- (case offline of
73
               True -> return $ Node.create 0 0 0 0 0 True
74
               _ -> do
75
                 drained <- fromObj "drained" a
76
                 mtotal <- fromObj "mtotal" a
77
                 mnode <- fromObj "mnode" a
78
                 mfree <- fromObj "mfree" a
79
                 dtotal <- fromObj "dtotal" a
80
                 dfree <- fromObj "dfree" a
81
                 return $ Node.create mtotal mnode mfree
82
                        dtotal dfree (offline || drained))
83
    return (name, node)
72 84

  
73
parseNode :: JSObject JSValue -> Result String
74
parseNode a =
75
    let name = getStringElement "name" a
76
        offline = getBoolElement "offline" a
77
        drained = getBoolElement "drained" a
78
        mtotal = getIntElement "mtotal" a
79
        mnode = getIntElement "mnode" a
80
        mfree = getIntElement "mfree" a
81
        dtotal = getIntElement "dtotal" a
82
        dfree = getIntElement "dfree" a
83
    in name |+
84
       (case offline of
85
          Ok True -> Ok "0|0|0|0|0|Y"
86
          _ ->
87
              (show `liftM` mtotal) |+ (show `liftM` mnode) |+
88
              (show `liftM` mfree) |+ (show `liftM` dtotal) |+
89
              (show `liftM` dfree) |+
90
              ((liftM2 (||) offline drained) >>= boolToYN)
91
       )
85
loadData :: String -- ^ Cluster/URL to use as source
86
         -> IO (Result (NameAssoc, Node.AssocList,
87
                        NameAssoc, Instance.AssocList))
88
loadData master = do -- IO monad
89
  let url = formatHost master
90
  node_body <- getUrl $ printf "%s/2/nodes?bulk=1" url
91
  inst_body <- getUrl $ printf "%s/2/instances?bulk=1" url
92
  return $ do -- Result monad
93
    node_data <- node_body >>= getNodes
94
    let (node_names, node_idx) = assignIndices Node.setIdx node_data
95
    inst_data <- inst_body >>= getInstances node_names
96
    let (inst_names, inst_idx) = assignIndices Instance.setIdx inst_data
97
    return (node_names, node_idx, inst_names, inst_idx)

Also available in: Unified diff