Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Rapi.hs @ 9188aeef

History | View | Annotate | Download (3.3 kB)

1
{-| Implementation of the RAPI client interface.
2

    
3
-}
4

    
5
module Ganeti.HTools.Rapi
6
    (
7
      loadData
8
    ) where
9

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

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

    
24
-- | Read an URL via curl and return the body if successful.
25
getUrl :: (Monad m) => String -> IO (m String)
26
getUrl url = do
27
  (code, body) <- curlGetString url [CurlSSLVerifyPeer False,
28
                                     CurlSSLVerifyHost 0]
29
  return (case code of
30
            CurlOK -> return body
31
            _ -> fail $ printf "Curl error for '%s', error %s"
32
                 url (show code))
33

    
34
-- | Append the default port if not passed in.
35
formatHost :: String -> String
36
formatHost master =
37
    if elem ':' master then  master
38
    else "https://" ++ master ++ ":5080"
39

    
40
-- | Parse a instance list in JSON format.
41
getInstances :: NameAssoc
42
             -> String
43
             -> Result [(String, Instance.Instance)]
44
getInstances ktn body = do
45
  arr <- loadJSArray body
46
  ilist <- mapM (parseInstance ktn) arr
47
  return ilist
48

    
49
-- | Parse a node list in JSON format.
50
getNodes :: String -> Result [(String, Node.Node)]
51
getNodes body = do
52
  arr <- loadJSArray body
53
  nlist <- mapM parseNode arr
54
  return nlist
55

    
56
-- | Construct an instance from a JSON object.
57
parseInstance :: [(String, Ndx)]
58
              -> JSObject JSValue
59
              -> Result (String, Instance.Instance)
60
parseInstance ktn a = do
61
  name <- fromObj "name" a
62
  disk <- fromObj "disk_usage" a
63
  mem <- fromObj "beparams" a >>= fromObj "memory"
64
  pnode <- fromObj "pnode" a >>= lookupNode ktn name
65
  snodes <- fromObj "snodes" a
66
  snode <- (if null snodes then return Node.noSecondary
67
            else readEitherString (head snodes) >>= lookupNode ktn name)
68
  running <- fromObj "status" a
69
  let inst = Instance.create name mem disk running pnode snode
70
  return (name, inst)
71

    
72
-- | Construct a node from a JSON object.
73
parseNode :: JSObject JSValue -> Result (String, Node.Node)
74
parseNode a = do
75
    name <- fromObj "name" a
76
    offline <- fromObj "offline" a
77
    node <- (case offline of
78
               True -> return $ Node.create name 0 0 0 0 0 True
79
               _ -> do
80
                 drained <- fromObj "drained" a
81
                 mtotal <- fromObj "mtotal" a
82
                 mnode <- fromObj "mnode" a
83
                 mfree <- fromObj "mfree" a
84
                 dtotal <- fromObj "dtotal" a
85
                 dfree <- fromObj "dfree" a
86
                 return $ Node.create name mtotal mnode mfree
87
                        dtotal dfree (offline || drained))
88
    return (name, node)
89

    
90
-- | Builds the cluster data from an URL.
91
loadData :: String -- ^ Cluster or URL to use as source
92
         -> IO (Result (Node.AssocList, Instance.AssocList))
93
loadData master = do -- IO monad
94
  let url = formatHost master
95
  node_body <- getUrl $ printf "%s/2/nodes?bulk=1" url
96
  inst_body <- getUrl $ printf "%s/2/instances?bulk=1" url
97
  return $ do -- Result monad
98
    node_data <- node_body >>= getNodes
99
    let (node_names, node_idx) = assignIndices node_data
100
    inst_data <- inst_body >>= getInstances node_names
101
    let (_, inst_idx) = assignIndices inst_data
102
    return (node_idx, inst_idx)