Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / IAlloc.hs @ e7724ccc

History | View | Annotate | Download (5.3 kB)

1
{-| Implementation of the iallocator interface.
2

    
3
-}
4

    
5
{-
6

    
7
Copyright (C) 2009 Google Inc.
8

    
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 2 of the License, or
12
(at your option) any later version.
13

    
14
This program is distributed in the hope that it will be useful, but
15
WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
General Public License for more details.
18

    
19
You should have received a copy of the GNU General Public License
20
along with this program; if not, write to the Free Software
21
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22
02110-1301, USA.
23

    
24
-}
25

    
26
module Ganeti.HTools.IAlloc
27
    ( parseData
28
    , formatResponse
29
    ) where
30

    
31
import Data.Either ()
32
import Control.Monad
33
import Text.JSON (JSObject, JSValue(JSBool, JSString, JSArray),
34
                  makeObj, encodeStrict, decodeStrict,
35
                  fromJSObject, toJSString)
36
import qualified Ganeti.HTools.Container as Container
37
import qualified Ganeti.HTools.Node as Node
38
import qualified Ganeti.HTools.Instance as Instance
39
import Ganeti.HTools.Loader
40
import Ganeti.HTools.Utils
41
import Ganeti.HTools.Types
42

    
43
-- | Parse the basic specifications of an instance.
44
--
45
-- Instances in the cluster instance list and the instance in an
46
-- 'Allocate' request share some common properties, which are read by
47
-- this function.
48
parseBaseInstance :: String
49
                  -> JSObject JSValue
50
                  -> Result (String, Instance.Instance)
51
parseBaseInstance n a = do
52
  disk <- fromObj "disk_space_total" a
53
  mem <- fromObj "memory" a
54
  vcpus <- fromObj "vcpus" a
55
  let running = "running"
56
  return (n, Instance.create n mem disk vcpus running 0 0)
57

    
58
-- | Parses an instance as found in the cluster instance list.
59
parseInstance :: NameAssoc        -- ^ The node name-to-index association list
60
              -> String           -- ^ The name of the instance
61
              -> JSObject JSValue -- ^ The JSON object
62
              -> Result (String, Instance.Instance)
63
parseInstance ktn n a = do
64
    base <- parseBaseInstance n a
65
    nodes <- fromObj "nodes" a
66
    pnode <- readEitherString $ head nodes
67
    pidx <- lookupNode ktn n pnode
68
    let snodes = tail nodes
69
    sidx <- (if null snodes then return Node.noSecondary
70
             else readEitherString (head snodes) >>= lookupNode ktn n)
71
    return (n, Instance.setBoth (snd base) pidx sidx)
72

    
73
-- | Parses a node as found in the cluster node list.
74
parseNode :: String           -- ^ The node's name
75
          -> JSObject JSValue -- ^ The JSON object
76
          -> Result (String, Node.Node)
77
parseNode n a = do
78
    let name = n
79
    offline <- fromObj "offline" a
80
    drained <- fromObj "drained" a
81
    node <- (if offline || drained
82
             then return $ Node.create name 0 0 0 0 0 0 True
83
             else do
84
               mtotal <- fromObj "total_memory" a
85
               mnode  <- fromObj "reserved_memory" a
86
               mfree  <- fromObj "free_memory"  a
87
               dtotal <- fromObj "total_disk"   a
88
               dfree  <- fromObj "free_disk"    a
89
               ctotal <- fromObj "total_cpus"   a
90
               return $ Node.create n mtotal mnode mfree
91
                      dtotal dfree ctotal False)
92
    return (name, node)
93

    
94
-- | Top-level parser.
95
parseData :: String         -- ^ The JSON message as received from Ganeti
96
          -> Result Request -- ^ A (possible valid) request
97
parseData body = do
98
  decoded <- fromJResult $ decodeStrict body
99
  let obj = decoded
100
  -- request parser
101
  request <- fromObj "request" obj
102
  rname <- fromObj "name" request
103
  -- existing node parsing
104
  nlist <- fromObj "nodes" obj
105
  let ndata = fromJSObject nlist
106
  nobj <- mapM (\(x,y) -> asJSObject y >>= parseNode x) ndata
107
  let (ktn, nl) = assignIndices nobj
108
  -- existing instance parsing
109
  ilist <- fromObj "instances" obj
110
  let idata = fromJSObject ilist
111
  iobj <- mapM (\(x,y) -> asJSObject y >>= parseInstance ktn x) idata
112
  let (kti, il) = assignIndices iobj
113
  (map_n, map_i, csf) <- mergeData [] (nl, il)
114
  req_nodes <- fromObj "required_nodes" request
115
  optype <- fromObj "type" request
116
  rqtype <-
117
      case optype of
118
        "allocate" ->
119
            do
120
              inew <- parseBaseInstance rname request
121
              let io = snd inew
122
              return $ Allocate io req_nodes
123
        "relocate" ->
124
            do
125
              ridx <- lookupInstance kti rname
126
              ex_nodes <- fromObj "relocate_from" request
127
              let ex_nodes' = map (stripSuffix $ length csf) ex_nodes
128
              ex_idex <- mapM (Container.findByName map_n) ex_nodes'
129
              return $ Relocate ridx req_nodes (map Node.idx ex_idex)
130
        other -> fail ("Invalid request type '" ++ other ++ "'")
131
  return $ Request rqtype map_n map_i csf
132

    
133
-- | Formats the response into a valid IAllocator response message.
134
formatResponse :: Bool     -- ^ Whether the request was successful
135
               -> String   -- ^ Information text
136
               -> [String] -- ^ The list of chosen nodes
137
               -> String   -- ^ The JSON-formatted message
138
formatResponse success info nodes =
139
    let
140
        e_success = ("success", JSBool success)
141
        e_info = ("info", JSString . toJSString $ info)
142
        e_nodes = ("nodes", JSArray $ map (JSString . toJSString) nodes)
143
    in encodeStrict $ makeObj [e_success, e_info, e_nodes]