Revision ebf38064 htools/Ganeti/Luxi.hs
b/htools/Ganeti/Luxi.hs | ||
---|---|---|
26 | 26 |
-} |
27 | 27 |
|
28 | 28 |
module Ganeti.Luxi |
29 |
( LuxiOp(..)
|
|
30 |
, QrViaLuxi(..)
|
|
31 |
, ResultStatus(..)
|
|
32 |
, Client
|
|
33 |
, checkRS
|
|
34 |
, getClient
|
|
35 |
, closeClient
|
|
36 |
, callMethod
|
|
37 |
, submitManyJobs
|
|
38 |
, queryJobsStatus
|
|
39 |
) where
|
|
29 |
( LuxiOp(..) |
|
30 |
, QrViaLuxi(..) |
|
31 |
, ResultStatus(..) |
|
32 |
, Client |
|
33 |
, checkRS |
|
34 |
, getClient |
|
35 |
, closeClient |
|
36 |
, callMethod |
|
37 |
, submitManyJobs |
|
38 |
, queryJobsStatus |
|
39 |
) where |
|
40 | 40 |
|
41 | 41 |
import Data.IORef |
42 | 42 |
import Control.Monad |
... | ... | |
59 | 59 |
-- | Wrapper over System.Timeout.timeout that fails in the IO monad. |
60 | 60 |
withTimeout :: Int -> String -> IO a -> IO a |
61 | 61 |
withTimeout secs descr action = do |
62 |
result <- timeout (secs * 1000000) action
|
|
63 |
(case result of
|
|
64 |
Nothing -> fail $ "Timeout in " ++ descr
|
|
65 |
Just v -> return v)
|
|
62 |
result <- timeout (secs * 1000000) action |
|
63 |
(case result of |
|
64 |
Nothing -> fail $ "Timeout in " ++ descr |
|
65 |
Just v -> return v) |
|
66 | 66 |
|
67 | 67 |
-- * Generic protocol functionality |
68 | 68 |
|
69 | 69 |
$(declareSADT "QrViaLuxi" |
70 |
[ ("QRLock", 'qrLock)
|
|
71 |
, ("QRInstance", 'qrInstance)
|
|
72 |
, ("QRNode", 'qrNode)
|
|
73 |
, ("QRGroup", 'qrGroup)
|
|
74 |
, ("QROs", 'qrOs)
|
|
75 |
])
|
|
70 |
[ ("QRLock", 'qrLock) |
|
71 |
, ("QRInstance", 'qrInstance) |
|
72 |
, ("QRNode", 'qrNode) |
|
73 |
, ("QRGroup", 'qrGroup) |
|
74 |
, ("QROs", 'qrOs) |
|
75 |
]) |
|
76 | 76 |
$(makeJSONInstance ''QrViaLuxi) |
77 | 77 |
|
78 | 78 |
-- | Currently supported Luxi operations and JSON serialization. |
79 | 79 |
$(genLuxiOp "LuxiOp" |
80 |
[("Query" ,
|
|
81 |
[ ("what", [t| QrViaLuxi |], [| id |])
|
|
82 |
, ("fields", [t| [String] |], [| id |])
|
|
83 |
, ("qfilter", [t| () |], [| const JSNull |])
|
|
84 |
])
|
|
85 |
, ("QueryNodes",
|
|
86 |
[ ("names", [t| [String] |], [| id |])
|
|
87 |
, ("fields", [t| [String] |], [| id |])
|
|
88 |
, ("lock", [t| Bool |], [| id |])
|
|
89 |
])
|
|
90 |
, ("QueryGroups",
|
|
91 |
[ ("names", [t| [String] |], [| id |])
|
|
92 |
, ("fields", [t| [String] |], [| id |])
|
|
93 |
, ("lock", [t| Bool |], [| id |])
|
|
94 |
])
|
|
95 |
, ("QueryInstances",
|
|
96 |
[ ("names", [t| [String] |], [| id |])
|
|
97 |
, ("fields", [t| [String] |], [| id |])
|
|
98 |
, ("lock", [t| Bool |], [| id |])
|
|
99 |
])
|
|
100 |
, ("QueryJobs",
|
|
101 |
[ ("ids", [t| [Int] |], [| map show |])
|
|
102 |
, ("fields", [t| [String] |], [| id |])
|
|
103 |
])
|
|
104 |
, ("QueryExports",
|
|
105 |
[ ("nodes", [t| [String] |], [| id |])
|
|
106 |
, ("lock", [t| Bool |], [| id |])
|
|
107 |
])
|
|
108 |
, ("QueryConfigValues",
|
|
109 |
[ ("fields", [t| [String] |], [| id |]) ]
|
|
110 |
)
|
|
111 |
, ("QueryClusterInfo", [])
|
|
112 |
, ("QueryTags",
|
|
113 |
[ ("kind", [t| String |], [| id |])
|
|
114 |
, ("name", [t| String |], [| id |])
|
|
115 |
])
|
|
116 |
, ("SubmitJob",
|
|
117 |
[ ("job", [t| [OpCode] |], [| id |]) ]
|
|
118 |
)
|
|
119 |
, ("SubmitManyJobs",
|
|
120 |
[ ("ops", [t| [[OpCode]] |], [| id |]) ]
|
|
121 |
)
|
|
122 |
, ("WaitForJobChange",
|
|
123 |
[ ("job", [t| Int |], [| id |])
|
|
124 |
, ("fields", [t| [String]|], [| id |])
|
|
125 |
, ("prev_job", [t| JSValue |], [| id |])
|
|
126 |
, ("prev_log", [t| JSValue |], [| id |])
|
|
127 |
, ("tmout", [t| Int |], [| id |])
|
|
128 |
])
|
|
129 |
, ("ArchiveJob",
|
|
130 |
[ ("job", [t| Int |], [| show |]) ]
|
|
131 |
)
|
|
132 |
, ("AutoArchiveJobs",
|
|
133 |
[ ("age", [t| Int |], [| id |])
|
|
134 |
, ("tmout", [t| Int |], [| id |])
|
|
135 |
])
|
|
136 |
, ("CancelJob",
|
|
137 |
[ ("job", [t| Int |], [| show |]) ]
|
|
138 |
)
|
|
139 |
, ("SetDrainFlag",
|
|
140 |
[ ("flag", [t| Bool |], [| id |]) ]
|
|
141 |
)
|
|
142 |
, ("SetWatcherPause",
|
|
143 |
[ ("duration", [t| Double |], [| id |]) ]
|
|
144 |
)
|
|
80 |
[("Query" , |
|
81 |
[ ("what", [t| QrViaLuxi |], [| id |]) |
|
82 |
, ("fields", [t| [String] |], [| id |]) |
|
83 |
, ("qfilter", [t| () |], [| const JSNull |]) |
|
84 |
]) |
|
85 |
, ("QueryNodes", |
|
86 |
[ ("names", [t| [String] |], [| id |]) |
|
87 |
, ("fields", [t| [String] |], [| id |]) |
|
88 |
, ("lock", [t| Bool |], [| id |]) |
|
89 |
]) |
|
90 |
, ("QueryGroups", |
|
91 |
[ ("names", [t| [String] |], [| id |]) |
|
92 |
, ("fields", [t| [String] |], [| id |]) |
|
93 |
, ("lock", [t| Bool |], [| id |]) |
|
94 |
]) |
|
95 |
, ("QueryInstances", |
|
96 |
[ ("names", [t| [String] |], [| id |]) |
|
97 |
, ("fields", [t| [String] |], [| id |]) |
|
98 |
, ("lock", [t| Bool |], [| id |]) |
|
99 |
]) |
|
100 |
, ("QueryJobs", |
|
101 |
[ ("ids", [t| [Int] |], [| map show |]) |
|
102 |
, ("fields", [t| [String] |], [| id |]) |
|
103 |
]) |
|
104 |
, ("QueryExports", |
|
105 |
[ ("nodes", [t| [String] |], [| id |]) |
|
106 |
, ("lock", [t| Bool |], [| id |]) |
|
107 |
]) |
|
108 |
, ("QueryConfigValues", |
|
109 |
[ ("fields", [t| [String] |], [| id |]) ] |
|
110 |
) |
|
111 |
, ("QueryClusterInfo", []) |
|
112 |
, ("QueryTags", |
|
113 |
[ ("kind", [t| String |], [| id |]) |
|
114 |
, ("name", [t| String |], [| id |]) |
|
115 |
]) |
|
116 |
, ("SubmitJob", |
|
117 |
[ ("job", [t| [OpCode] |], [| id |]) ] |
|
118 |
) |
|
119 |
, ("SubmitManyJobs", |
|
120 |
[ ("ops", [t| [[OpCode]] |], [| id |]) ] |
|
121 |
) |
|
122 |
, ("WaitForJobChange", |
|
123 |
[ ("job", [t| Int |], [| id |]) |
|
124 |
, ("fields", [t| [String]|], [| id |]) |
|
125 |
, ("prev_job", [t| JSValue |], [| id |]) |
|
126 |
, ("prev_log", [t| JSValue |], [| id |]) |
|
127 |
, ("tmout", [t| Int |], [| id |]) |
|
128 |
]) |
|
129 |
, ("ArchiveJob", |
|
130 |
[ ("job", [t| Int |], [| show |]) ] |
|
131 |
) |
|
132 |
, ("AutoArchiveJobs", |
|
133 |
[ ("age", [t| Int |], [| id |]) |
|
134 |
, ("tmout", [t| Int |], [| id |]) |
|
135 |
]) |
|
136 |
, ("CancelJob", |
|
137 |
[ ("job", [t| Int |], [| show |]) ] |
|
138 |
) |
|
139 |
, ("SetDrainFlag", |
|
140 |
[ ("flag", [t| Bool |], [| id |]) ] |
|
141 |
) |
|
142 |
, ("SetWatcherPause", |
|
143 |
[ ("duration", [t| Double |], [| id |]) ] |
|
144 |
) |
|
145 | 145 |
]) |
146 | 146 |
|
147 | 147 |
-- | The serialisation of LuxiOps into strings in messages. |
148 | 148 |
$(genStrOfOp ''LuxiOp "strOfOp") |
149 | 149 |
|
150 | 150 |
$(declareIADT "ResultStatus" |
151 |
[ ("RSNormal", 'rsNormal)
|
|
152 |
, ("RSUnknown", 'rsUnknown)
|
|
153 |
, ("RSNoData", 'rsNodata)
|
|
154 |
, ("RSUnavailable", 'rsUnavail)
|
|
155 |
, ("RSOffline", 'rsOffline)
|
|
156 |
])
|
|
151 |
[ ("RSNormal", 'rsNormal) |
|
152 |
, ("RSUnknown", 'rsUnknown) |
|
153 |
, ("RSNoData", 'rsNodata) |
|
154 |
, ("RSUnavailable", 'rsUnavail) |
|
155 |
, ("RSOffline", 'rsOffline) |
|
156 |
]) |
|
157 | 157 |
|
158 | 158 |
$(makeJSONInstance ''ResultStatus) |
159 | 159 |
|
... | ... | |
186 | 186 |
-- | Connects to the master daemon and returns a luxi Client. |
187 | 187 |
getClient :: String -> IO Client |
188 | 188 |
getClient path = do |
189 |
s <- S.socket S.AF_UNIX S.Stream S.defaultProtocol
|
|
190 |
withTimeout connTimeout "creating luxi connection" $
|
|
191 |
S.connect s (S.SockAddrUnix path)
|
|
192 |
rf <- newIORef ""
|
|
193 |
return Client { socket=s, rbuf=rf}
|
|
189 |
s <- S.socket S.AF_UNIX S.Stream S.defaultProtocol |
|
190 |
withTimeout connTimeout "creating luxi connection" $ |
|
191 |
S.connect s (S.SockAddrUnix path) |
|
192 |
rf <- newIORef "" |
|
193 |
return Client { socket=s, rbuf=rf} |
|
194 | 194 |
|
195 | 195 |
-- | Closes the client socket. |
196 | 196 |
closeClient :: Client -> IO () |
... | ... | |
199 | 199 |
-- | Sends a message over a luxi transport. |
200 | 200 |
sendMsg :: Client -> String -> IO () |
201 | 201 |
sendMsg s buf = |
202 |
let _send obuf = do
|
|
203 |
sbytes <- withTimeout queryTimeout
|
|
204 |
"sending luxi message" $
|
|
205 |
S.send (socket s) obuf
|
|
206 |
unless (sbytes == length obuf) $ _send (drop sbytes obuf)
|
|
207 |
in _send (buf ++ [eOM])
|
|
202 |
let _send obuf = do |
|
203 |
sbytes <- withTimeout queryTimeout |
|
204 |
"sending luxi message" $ |
|
205 |
S.send (socket s) obuf |
|
206 |
unless (sbytes == length obuf) $ _send (drop sbytes obuf) |
|
207 |
in _send (buf ++ [eOM]) |
|
208 | 208 |
|
209 | 209 |
-- | Waits for a message over a luxi transport. |
210 | 210 |
recvMsg :: Client -> IO String |
... | ... | |
229 | 229 |
buildCall :: LuxiOp -- ^ The method |
230 | 230 |
-> String -- ^ The serialized form |
231 | 231 |
buildCall lo = |
232 |
let ja = [ (strOfKey Method, JSString $ toJSString $ strOfOp lo::JSValue)
|
|
233 |
, (strOfKey Args, opToArgs lo::JSValue)
|
|
234 |
]
|
|
235 |
jo = toJSObject ja
|
|
236 |
in encodeStrict jo
|
|
232 |
let ja = [ (strOfKey Method, JSString $ toJSString $ strOfOp lo::JSValue) |
|
233 |
, (strOfKey Args, opToArgs lo::JSValue) |
|
234 |
] |
|
235 |
jo = toJSObject ja |
|
236 |
in encodeStrict jo |
|
237 | 237 |
|
238 | 238 |
-- | Check that luxi responses contain the required keys and that the |
239 | 239 |
-- call was successful. |
Also available in: Unified diff