module Ganeti.Metad.Config where
import Control.Arrow (second)
import Control.Monad ((>=>), mzero)
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
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
mergeConfig :: InstanceParams -> InstanceParams -> InstanceParams
mergeConfig cfg1 cfg2 = cfg2 `Map.union` cfg1
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 x -> readJSON x
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"
makeInstanceParams
:: JSObject JSValue
-> JSObject JSValue
-> JSObject JSValue
-> JSObject JSValue
makeInstanceParams pub priv sec =
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)
getOsParamsWithVisibility :: JSValue -> Result (JSObject JSValue)
getOsParamsWithVisibility json =
do obj <- readJSON json
publicOsParams <- getPublicOsParams obj
privateOsParams <- getPrivateOsParams obj
secretOsParams <- getSecretOsParams obj
Ok $ makeInstanceParams publicOsParams privateOsParams secretOsParams
getInstanceCommunicationIp :: JSObject JSValue -> Result (Maybe String)
getInstanceCommunicationIp =
runMaybeT . (getNics >=> getInstanceCommunicationNic >=> getIp)
where
getIp :: JSObject JSValue -> MaybeT Result String
getIp nic =
case lookup "ip" (fromJSObject nic) of
Nothing -> failErrorT "Could not find instance communication IP"
Just (JSString ip) -> return (JSON.fromJSString ip)
_ -> failErrorT "Instance communication IP is not a string"
getInstanceCommunicationNic :: [JSValue] -> MaybeT Result (JSObject JSValue)
getInstanceCommunicationNic [] = mzero
getInstanceCommunicationNic (JSObject nic : nics) =
case lookup "name" (fromJSObject nic) of
Just (JSString name)
| Constants.instanceCommunicationNicPrefix
`List.isPrefixOf` JSON.fromJSString name ->
return nic
_ -> getInstanceCommunicationNic nics
getInstanceCommunicationNic (n : _) =
failErrorT $ "Found wrong data in instance NICs: " ++ show n
getNics :: JSObject JSValue -> MaybeT Result [JSValue]
getNics jsonObj =
case lookup "nics" (fromJSObject jsonObj) of
Nothing -> failErrorT "Could not find OS parameters key 'nics'"
Just (JSArray nics) -> return nics
_ -> failErrorT "Instance nics is not an array"
failErrorT :: (MonadTrans t) => String -> t Result a
failErrorT = lift . JSON.Error
getInstanceParams :: JSValue -> Result (String, Maybe InstanceParams)
getInstanceParams json =
case json of
JSObject jsonObj -> do
name <- case lookup "name" (fromJSObject jsonObj) of
Nothing -> failError "Could not find instance name"
Just (JSString x) -> return (JSON.fromJSString x)
_ -> failError "Name is not a string"
m'ip <- getInstanceCommunicationIp jsonObj
return (name, fmap (\ip -> Map.fromList [(ip, json)]) m'ip)
_ ->
failError "Expecting a dictionary"
where
failError = JSON.Error