Commit 84e1ac7c authored by Jose A. Lopes's avatar Jose A. Lopes
Browse files

Move metad configuration related code to a separate module



... 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: default avatarJose A. Lopes <jabolopes@google.com>
Reviewed-by: default avatarHrvoje Ribicic <riba@google.com>
parent 3716e8c6
......@@ -779,6 +779,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 \
......
{-
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"
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment