Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Confd / Client.hs @ 3190ad64

History | View | Annotate | Download (4.6 kB)

1 04063ba7 Michele Tartara
{-| Implementation of the Ganeti Confd client functionality.
2 04063ba7 Michele Tartara
3 04063ba7 Michele Tartara
-}
4 04063ba7 Michele Tartara
5 04063ba7 Michele Tartara
{-
6 04063ba7 Michele Tartara
7 04063ba7 Michele Tartara
Copyright (C) 2012 Google Inc.
8 04063ba7 Michele Tartara
9 04063ba7 Michele Tartara
This program is free software; you can redistribute it and/or modify
10 04063ba7 Michele Tartara
it under the terms of the GNU General Public License as published by
11 04063ba7 Michele Tartara
the Free Software Foundation; either version 2 of the License, or
12 04063ba7 Michele Tartara
(at your option) any later version.
13 04063ba7 Michele Tartara
14 04063ba7 Michele Tartara
This program is distributed in the hope that it will be useful, but
15 04063ba7 Michele Tartara
WITHOUT ANY WARRANTY; without even the implied warranty of
16 04063ba7 Michele Tartara
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 04063ba7 Michele Tartara
General Public License for more details.
18 04063ba7 Michele Tartara
19 04063ba7 Michele Tartara
You should have received a copy of the GNU General Public License
20 04063ba7 Michele Tartara
along with this program; if not, write to the Free Software
21 04063ba7 Michele Tartara
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 04063ba7 Michele Tartara
02110-1301, USA.
23 04063ba7 Michele Tartara
24 04063ba7 Michele Tartara
-}
25 04063ba7 Michele Tartara
26 04063ba7 Michele Tartara
module Ganeti.Confd.Client
27 04063ba7 Michele Tartara
  ( getConfdClient
28 04063ba7 Michele Tartara
  , query
29 04063ba7 Michele Tartara
  ) where
30 04063ba7 Michele Tartara
31 04063ba7 Michele Tartara
import Control.Concurrent
32 04063ba7 Michele Tartara
import Control.Monad
33 04063ba7 Michele Tartara
import Data.List
34 04063ba7 Michele Tartara
import qualified Network.Socket as S
35 04063ba7 Michele Tartara
import System.Posix.Time
36 04063ba7 Michele Tartara
import qualified Text.JSON as J
37 04063ba7 Michele Tartara
38 04063ba7 Michele Tartara
import Ganeti.BasicTypes
39 04063ba7 Michele Tartara
import Ganeti.Confd.Types
40 04063ba7 Michele Tartara
import Ganeti.Confd.Utils
41 04063ba7 Michele Tartara
import qualified Ganeti.Constants as C
42 04063ba7 Michele Tartara
import Ganeti.Hash
43 04063ba7 Michele Tartara
import Ganeti.Ssconf
44 04063ba7 Michele Tartara
45 04063ba7 Michele Tartara
-- | Builds a properly initialized ConfdClient
46 04063ba7 Michele Tartara
getConfdClient :: IO ConfdClient
47 04063ba7 Michele Tartara
getConfdClient = S.withSocketsDo $ do
48 04063ba7 Michele Tartara
  hmac <- getClusterHmac
49 04063ba7 Michele Tartara
  candList <- getMasterCandidatesIps Nothing
50 04063ba7 Michele Tartara
  peerList <-
51 04063ba7 Michele Tartara
    case candList of
52 04063ba7 Michele Tartara
      (Ok p) -> return p
53 04063ba7 Michele Tartara
      (Bad msg) -> fail msg
54 04063ba7 Michele Tartara
  return . ConfdClient hmac peerList $ fromIntegral C.defaultConfdPort
55 04063ba7 Michele Tartara
56 04063ba7 Michele Tartara
-- | Sends a query to all the Confd servers the client is connected to.
57 04063ba7 Michele Tartara
-- Returns the most up-to-date result according to the serial number,
58 04063ba7 Michele Tartara
-- chosen between those received before the timeout.
59 04063ba7 Michele Tartara
query :: ConfdClient -> ConfdRequestType -> ConfdQuery -> IO (Maybe ConfdReply)
60 04063ba7 Michele Tartara
query client crType cQuery = do
61 04063ba7 Michele Tartara
  semaphore <- newMVar ()
62 04063ba7 Michele Tartara
  answer <- newMVar Nothing
63 04063ba7 Michele Tartara
  let dest = [(host, serverPort client) | host <- peers client]
64 04063ba7 Michele Tartara
      hmac = hmacKey client
65 04063ba7 Michele Tartara
      jobs = map (queryOneServer semaphore answer crType cQuery hmac) dest
66 04063ba7 Michele Tartara
      watchdog reqAnswers = do
67 04063ba7 Michele Tartara
        threadDelay $ 1000000 * C.confdClientExpireTimeout
68 04063ba7 Michele Tartara
        _ <- swapMVar reqAnswers 0
69 04063ba7 Michele Tartara
        putMVar semaphore ()
70 04063ba7 Michele Tartara
      waitForResult reqAnswers = do
71 04063ba7 Michele Tartara
        _ <- takeMVar semaphore
72 04063ba7 Michele Tartara
        l <- takeMVar reqAnswers
73 04063ba7 Michele Tartara
        unless (l == 0) $ do
74 04063ba7 Michele Tartara
          putMVar reqAnswers $ l - 1
75 04063ba7 Michele Tartara
          waitForResult reqAnswers
76 04063ba7 Michele Tartara
  reqAnswers <- newMVar . min C.confdDefaultReqCoverage $ length dest
77 04063ba7 Michele Tartara
  workers <- mapM forkIO jobs
78 04063ba7 Michele Tartara
  watcher <- forkIO $ watchdog reqAnswers
79 04063ba7 Michele Tartara
  waitForResult reqAnswers
80 04063ba7 Michele Tartara
  mapM_ killThread $ watcher:workers
81 04063ba7 Michele Tartara
  takeMVar answer
82 04063ba7 Michele Tartara
83 04063ba7 Michele Tartara
-- | Updates the reply to the query. As per the Confd design document,
84 04063ba7 Michele Tartara
-- only the reply with the highest serial number is kept.
85 04063ba7 Michele Tartara
updateConfdReply :: ConfdReply -> Maybe ConfdReply -> Maybe ConfdReply
86 04063ba7 Michele Tartara
updateConfdReply newValue Nothing = Just newValue
87 04063ba7 Michele Tartara
updateConfdReply newValue (Just currentValue) = Just $
88 04063ba7 Michele Tartara
  if confdReplyStatus newValue == ReplyStatusOk
89 2663321c Michele Tartara
      && (confdReplyStatus currentValue /= ReplyStatusOk
90 2663321c Michele Tartara
          || confdReplySerial newValue > confdReplySerial currentValue)
91 04063ba7 Michele Tartara
    then newValue
92 04063ba7 Michele Tartara
    else currentValue
93 04063ba7 Michele Tartara
94 04063ba7 Michele Tartara
-- | Send a query to a single server, waits for the result and stores it
95 04063ba7 Michele Tartara
-- in a shared variable. Then, sends a signal on another shared variable
96 04063ba7 Michele Tartara
-- acting as a semaphore.
97 04063ba7 Michele Tartara
-- This function is meant to be used as one of multiple threads querying
98 04063ba7 Michele Tartara
-- multiple servers in parallel.
99 04063ba7 Michele Tartara
queryOneServer
100 04063ba7 Michele Tartara
  :: MVar ()                 -- ^ The semaphore that will be signalled
101 04063ba7 Michele Tartara
  -> MVar (Maybe ConfdReply) -- ^ The shared variable for the result
102 04063ba7 Michele Tartara
  -> ConfdRequestType        -- ^ The type of the query to be sent
103 04063ba7 Michele Tartara
  -> ConfdQuery              -- ^ The content of the query
104 04063ba7 Michele Tartara
  -> HashKey                 -- ^ The hmac key to sign the message
105 04063ba7 Michele Tartara
  -> (String, S.PortNumber)  -- ^ The address and port of the server
106 04063ba7 Michele Tartara
  -> IO ()
107 04063ba7 Michele Tartara
queryOneServer semaphore answer crType cQuery hmac (host, port) = do
108 04063ba7 Michele Tartara
  request <- newConfdRequest crType cQuery
109 04063ba7 Michele Tartara
  timestamp <- fmap show epochTime
110 04063ba7 Michele Tartara
  let signedMsg =
111 04063ba7 Michele Tartara
        signMessage hmac timestamp (J.encodeStrict request)
112 04063ba7 Michele Tartara
      completeMsg = C.confdMagicFourcc ++ J.encodeStrict signedMsg
113 04063ba7 Michele Tartara
  s <- S.socket S.AF_INET S.Datagram S.defaultProtocol
114 04063ba7 Michele Tartara
  hostAddr <- S.inet_addr host
115 04063ba7 Michele Tartara
  _ <- S.sendTo s completeMsg $ S.SockAddrInet port hostAddr
116 04063ba7 Michele Tartara
  replyMsg <- S.recv s C.maxUdpDataSize
117 04063ba7 Michele Tartara
  parsedReply <-
118 04063ba7 Michele Tartara
    if C.confdMagicFourcc `isPrefixOf` replyMsg
119 04063ba7 Michele Tartara
      then return . parseReply hmac (drop 4 replyMsg) $ confdRqRsalt request
120 04063ba7 Michele Tartara
      else fail "Invalid magic code!"
121 04063ba7 Michele Tartara
  reply <-
122 04063ba7 Michele Tartara
    case parsedReply of
123 04063ba7 Michele Tartara
      Ok (_, r) -> return r
124 04063ba7 Michele Tartara
      Bad msg -> fail msg
125 04063ba7 Michele Tartara
  modifyMVar_ answer $! return . updateConfdReply reply
126 04063ba7 Michele Tartara
  putMVar semaphore ()