LGTM, thanks
On Thu, Apr 3, 2014 at 4:46 PM, Jose A. Lopes <[email protected]> wrote: > ... as an intermediate step before moving the responsbility of > computing the final OS parameter configuration from the configuration > server to the web server. This will allow the metadata daemon to > store a more general configuration and thus reuse that configuration > for replying to more general queries. > > Signed-off-by: Jose A. Lopes <[email protected]> > --- > Makefile.am | 1 + > src/Ganeti/Metad/Config.hs | 131 > +++++++++++++++++++++++++++++++++++++++ > src/Ganeti/Metad/ConfigServer.hs | 109 +------------------------------- > 3 files changed, 134 insertions(+), 107 deletions(-) > create mode 100644 src/Ganeti/Metad/Config.hs > > diff --git a/Makefile.am b/Makefile.am > index 9a44cce..22b72a8 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/Config.hs \ > src/Ganeti/Metad/ConfigServer.hs \ > src/Ganeti/Metad/Server.hs \ > src/Ganeti/Metad/Types.hs \ > diff --git a/src/Ganeti/Metad/Config.hs b/src/Ganeti/Metad/Config.hs > new file mode 100644 > index 0000000..83dbdf5 > --- /dev/null > +++ b/src/Ganeti/Metad/Config.hs > @@ -0,0 +1,131 @@ > +{- > + > +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.Config where > + > +import Control.Arrow (second) > +import qualified Data.List as List (isPrefixOf) > +import qualified Data.Map as Map > +import Text.JSON > +import qualified Text.JSON as JSON > + > +import Ganeti.Constants as Constants > +import Ganeti.Metad.Types > + > +-- | Merges two instance configurations into one. > +-- > +-- In the case where instance IPs (i.e., map keys) are repeated, the > +-- old instance configuration is thrown away by 'Map.union' and > +-- replaced by the new configuration. As a result, the old private > +-- and secret OS parameters are completely lost. > +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" > + > +-- | 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) > + > +-- | 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 _ = > + Error "Found wrong data in instance NICs" > + > + 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" > + > +-- | 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" > diff --git a/src/Ganeti/Metad/ConfigServer.hs > b/src/Ganeti/Metad/ConfigServer.hs > index c1db6bb..9610cca 100644 > --- a/src/Ganeti/Metad/ConfigServer.hs > +++ b/src/Ganeti/Metad/ConfigServer.hs > @@ -25,18 +25,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, > Boston, MA > -} > 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 > @@ -44,6 +39,7 @@ import Ganeti.Runtime (GanetiDaemon(..)) > import Ganeti.UDSServer (Client, ConnectConfig(..), Server) > import qualified Ganeti.UDSServer as UDSServer > > +import Ganeti.Metad.Config as Config > import Ganeti.Metad.Types (InstanceParams) > > metadSocket :: IO FilePath > @@ -51,107 +47,6 @@ metadSocket = > do dir <- Path.socketDir > return $ dir </> "ganeti-metad" > > --- | Merges two instance configurations into one. > --- > --- In the case where instance IPs (i.e., map keys) are repeated, the > --- old instance configuration is thrown away by 'Map.union' and > --- replaced by the new configuration. As a result, the old private > --- and secret OS parameters are completely lost. > -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 _ = > - Error "Found wrong data in instance NICs" > - > - 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 = > @@ -159,7 +54,7 @@ updateConfig config str = > Error err -> > Logging.logDebug $ show err > Ok x -> > - case getInstanceParams x of > + case Config.getInstanceParams x of > Error err -> > Logging.logError $ "Could not get instance parameters: " ++ err > Ok (name, instanceParams) -> do > -- > 1.9.1.423.g4596e3a > >
