Interdiff:
diff --git a/src/Ganeti/Metad/ConfigServer.hs b/src/Ganeti/Metad/ConfigServer.hs
index b49c7d9..7707a16 100644
--- a/src/Ganeti/Metad/ConfigServer.hs
+++ b/src/Ganeti/Metad/ConfigServer.hs
@@ -96,8 +96,8 @@ getInstanceCommunicationIp jsonObj =
`List.isPrefixOf` JSON.fromJSString name ->
Ok nic
_ -> getInstanceCommunicationNic nics
- getInstanceCommunicationNic (_:nics) =
- getInstanceCommunicationNic nics
+ getInstanceCommunicationNic _ =
+ Error "Found wrong data in instance NICs"
getNics =
case lookup "nics" (fromJSObject jsonObj) of
Cheers,
Jose
On Apr 02 11:46, Hrvoje Ribicic wrote:
> On Wed, Apr 2, 2014 at 9:34 AM, Jose A. Lopes <[email protected]> wrote:
>
> > The configuration server listens on a Unix socket for connections from
> > the node daemon. The node daemon sends the instance parameters to the
> > configuration server so they can be served through the metadata daemon
> > web server to the instances which have the communication mechanism
> > enabled.
> >
> > The configuration server reads the instance parameters and, currently,
> > it extracts the instance's name and the instance's IP address on the
> > instance communication NIC. The instance's name is used for logging
> > and the IP address is used to index the instance parameters, given
> > that instances do not authenticate with the metadata daemon, and the
> > only thing we know about them is their IP address.
> >
> > The configuration server also extracts the OS parameters, including
> > public, private and secret, and creates an object containing those
> > parameters and their visibility.
> >
> > The configuration is kept internally in an 'MVar' which will be shared
> > with the metadata daemon web server.
> >
> > Signed-off-by: Jose A. Lopes <[email protected]>
> > ---
> > Makefile.am | 1 +
> > src/Ganeti/Metad/ConfigServer.hs | 196
> > +++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 197 insertions(+)
> > create mode 100644 src/Ganeti/Metad/ConfigServer.hs
> >
> > diff --git a/Makefile.am b/Makefile.am
> > index 279013a..67b54fd 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -773,6 +773,7 @@ HS_LIB_SRCS = \
> > src/Ganeti/Logging.hs \
> > src/Ganeti/Logging/Lifted.hs \
> > src/Ganeti/Luxi.hs \
> > + src/Ganeti/Metad/ConfigServer.hs \
> > src/Ganeti/Metad/Types.hs \
> > src/Ganeti/Metad/WebServer.hs \
> > src/Ganeti/Monitoring/Server.hs \
> > diff --git a/src/Ganeti/Metad/ConfigServer.hs
> > b/src/Ganeti/Metad/ConfigServer.hs
> > new file mode 100644
> > index 0000000..b49c7d9
> > --- /dev/null
> > +++ b/src/Ganeti/Metad/ConfigServer.hs
> > @@ -0,0 +1,196 @@
> > +{-# LANGUAGE TupleSections #-}
> > +{-| Configuration server for the metadata daemon.
> > +
> > +-}
> > +
> > +{-
> > +
> > +Copyright (C) 2014 Google Inc.
> > +
> > +This program is free software; you can redistribute it and/or modify
> > +it under the terms of the GNU General Public License as published by
> > +the Free Software Foundation; either version 2 of the License, or
> > +(at your option) any later version.
> > +
> > +This program is distributed in the hope that it will be useful, but
> > +WITHOUT ANY WARRANTY; without even the implied warranty of
> > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> > +General Public License for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with this program; if not, write to the Free Software
> > +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> > +02110-1301, USA.
> > +
> > +-}
> > +module Ganeti.Metad.ConfigServer where
> > +
> > +import Control.Arrow (second)
> > +import Control.Concurrent
> > +import Control.Exception (try, finally)
> > +import Control.Monad (unless)
> > +import qualified Data.List as List
> > +import qualified Data.Map as Map
> > +import Text.JSON
> > +import qualified Text.JSON as JSON
> > +import System.FilePath ((</>))
> > +import System.IO.Error (isEOFError)
> > +
> > +import Ganeti.Constants as Constants
> > +import Ganeti.Path as Path
> > +import Ganeti.Daemon (DaemonOptions)
> > +import qualified Ganeti.Logging as Logging
> > +import Ganeti.Runtime (GanetiDaemon(..))
> > +import Ganeti.UDSServer (Client, ConnectConfig(..), Server)
> > +import qualified Ganeti.UDSServer as UDSServer
> > +
> > +import Ganeti.Metad.Types (InstanceParams)
> > +
> > +metadSocket :: IO FilePath
> > +metadSocket =
> > + do dir <- Path.socketDir
> > + return $ dir </> "ganeti-metad"
> > +
> > +mergeConfig :: InstanceParams -> InstanceParams -> InstanceParams
> > +mergeConfig cfg1 cfg2 = cfg2 `Map.union` cfg1
> > +
> > +-- | Extracts the OS parameters (public, private, secret) from a JSON
> > +-- object.
> > +--
> > +-- This function checks whether the OS parameters are in fact a JSON
> > +-- object.
> > +getOsParams :: String -> String -> JSObject JSValue -> Result (JSObject
> > JSValue)
> > +getOsParams key msg jsonObj =
> > + case lookup key (fromJSObject jsonObj) of
> > + Nothing -> Error $ "Could not find " ++ msg ++ " OS parameters"
> > + Just (JSObject x) -> Ok x
> > + _ -> Error "OS params is not a JSON object"
> > +
> > +getPublicOsParams :: JSObject JSValue -> Result (JSObject JSValue)
> > +getPublicOsParams = getOsParams "osparams" "public"
> > +
> > +getPrivateOsParams :: JSObject JSValue -> Result (JSObject JSValue)
> > +getPrivateOsParams = getOsParams "osparams_private" "private"
> > +
> > +getSecretOsParams :: JSObject JSValue -> Result (JSObject JSValue)
> > +getSecretOsParams = getOsParams "osparams_secret" "secret"
> > +
> > +-- | Finds the IP address of the instance communication NIC in the
> > +-- instance's NICs.
> > +getInstanceCommunicationIp :: JSObject JSValue -> Result String
> > +getInstanceCommunicationIp jsonObj =
> > + getNics >>= getInstanceCommunicationNic >>= getIp
> > + where
> > + getIp nic =
> > + case lookup "ip" (fromJSObject nic) of
> > + Nothing -> Error "Could not find instance communication IP"
> > + Just (JSString ip) -> Ok (JSON.fromJSString ip)
> > + _ -> Error "Instance communication IP is not a string"
> > +
> > + getInstanceCommunicationNic [] =
> > + Error "Could not find instance communication NIC"
> > + getInstanceCommunicationNic (JSObject nic:nics) =
> > + case lookup "name" (fromJSObject nic) of
> > + Just (JSString name)
> > + | Constants.instanceCommunicationNicPrefix
> > + `List.isPrefixOf` JSON.fromJSString name ->
> > + Ok nic
> > + _ -> getInstanceCommunicationNic nics
> > + getInstanceCommunicationNic (_:nics) =
> > + getInstanceCommunicationNic nics
> >
>
> Why not an error here?
>
>
> > +
> > + getNics =
> > + case lookup "nics" (fromJSObject jsonObj) of
> > + Nothing -> Error "Could not find OS parameters key 'nics'"
> > + Just (JSArray nics) -> Ok nics
> > + _ -> Error "Instance nics is not an array"
> > +
> > +-- | Merges the OS parameters (public, private, secret) in a single
> > +-- data structure containing all parameters and their visibility.
> > +--
> > +-- Example:
> > +-- { "os-image": ["http://example.com/disk.img", "public"],
> > +-- "os-password": ["mypassword", "secret"] }
> > +makeInstanceParams
> > + :: JSObject JSValue -> JSObject JSValue -> JSObject JSValue -> JSValue
> > +makeInstanceParams pub priv sec =
> > + JSObject . JSON.toJSObject $
> > + addVisibility "public" pub ++
> > + addVisibility "private" priv ++
> > + addVisibility "secret" sec
> > + where
> > + key = JSString . JSON.toJSString
> > +
> > + addVisibility param params =
> > + map (second (JSArray . (:[key param]))) (JSON.fromJSObject params)
> > +
> > +-- | Extracts the OS parameters from the instance's parameters and
> > +-- returns a data structure containing all the OS parameters and their
> > +-- visibility indexed by the instance's IP address which is used in
> > +-- the instance communication NIC.
> > +getInstanceParams :: JSValue -> Result (String, InstanceParams)
> > +getInstanceParams json =
> > + case json of
> > + JSObject jsonObj -> do
> > + name <- case lookup "name" (fromJSObject jsonObj) of
> > + Nothing -> Error "Could not find instance name"
> > + Just (JSString x) -> Ok (JSON.fromJSString x)
> > + _ -> Error "Name is not a string"
> > + ip <- getInstanceCommunicationIp jsonObj
> > + publicOsParams <- getPublicOsParams jsonObj
> > + privateOsParams <- getPrivateOsParams jsonObj
> > + secretOsParams <- getSecretOsParams jsonObj
> > + let instanceParams =
> > + makeInstanceParams publicOsParams privateOsParams
> > secretOsParams
> > + Ok (name, Map.fromList [(ip, instanceParams)])
> > + _ ->
> > + Error "Expecting a dictionary"
> > +
> > +-- | Update the configuration with the received instance parameters.
> > +updateConfig :: MVar InstanceParams -> String -> IO ()
> > +updateConfig config str =
> > + case decode str of
> > + Error err ->
> > + Logging.logDebug $ show err
> > + Ok x ->
> > + case getInstanceParams x of
> > + Error err ->
> > + Logging.logError $ "Could not get instance parameters: " ++ err
> > + Ok (name, instanceParams) -> do
> > + cfg <- takeMVar config
> > + let cfg' = mergeConfig cfg instanceParams
> > + putMVar config cfg'
> > + Logging.logInfo $
> > + "Updated instance " ++ show name ++ " configuration"
> > + Logging.logDebug $ "Instance configuration: " ++ show cfg'
> > +
> > +-- | Reads messages from clients and update the configuration
> > +-- according to these messages.
> > +acceptConfig :: MVar InstanceParams -> Client -> IO ()
> > +acceptConfig config client =
> > + do res <- try $ UDSServer.recvMsg client
> > + case res of
> > + Left err -> do
> > + unless (isEOFError err) .
> > + Logging.logDebug $ show err
> > + return ()
> > + Right str -> do
> > + Logging.logDebug $ "Received: " ++ str
> > + updateConfig config str
> > +
> > +-- | Loop that accepts clients and dispatches them to an isolated
> > +-- thread that will handle the client's requests.
> > +acceptClients :: MVar InstanceParams -> Server -> IO ()
> > +acceptClients config server =
> > + do client <- UDSServer.acceptClient server
> > + _ <- forkIO $ acceptConfig config client
> > + acceptClients config server
> > +
> > +start :: DaemonOptions -> MVar InstanceParams -> IO ()
> > +start _ config =
> > + do server <- UDSServer.connectServer metadConfig True =<< metadSocket
> > + finally
> > + (acceptClients config server)
> > + (UDSServer.closeServer server)
> > + where
> > + metadConfig = ConnectConfig GanetiMetad 60 60
> > --
> > 1.9.1.423.g4596e3a
> >
> >
--
Jose Antonio Lopes
Ganeti Engineering
Google Germany GmbH
Dienerstr. 12, 80331, München
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Geschäftsführer: Graham Law, Christine Elizabeth Flores
Steuernummer: 48/725/00206
Umsatzsteueridentifikationsnummer: DE813741370