The only way we provide OS params to metadata daemon clients is through a JSON file containing a lot of data. This patch exposes individual parameters in a RESTful way, making it easier to actually use the metadata daemon.
Signed-off-by: Hrvoje Ribicic <[email protected]> --- doc/design-os.rst | 5 +++++ src/Ganeti/Metad/Config.hs | 9 ++++++--- src/Ganeti/Metad/WebServer.hs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/doc/design-os.rst b/doc/design-os.rst index 1ff09c0..d89d133 100644 --- a/doc/design-os.rst +++ b/doc/design-os.rst @@ -460,6 +460,11 @@ pair ``(<value>, <visibility>)`` as the value, where ``<value>`` is the user-provided value of the parameter, and ``<visibility>`` is either ``public``, ``private`` or ``secret``. +The OS parameters can also be accessed individually by issuing a GET request +to:: + + http://169.254.169.254/ganeti/<version>/os/parameters/<parameter> + The installation scripts to be run inside the virtualized environment will be available at:: diff --git a/src/Ganeti/Metad/Config.hs b/src/Ganeti/Metad/Config.hs index ebd27b2..3162243 100644 --- a/src/Ganeti/Metad/Config.hs +++ b/src/Ganeti/Metad/Config.hs @@ -80,9 +80,12 @@ getSecretOsParams = getOsParams "osparams_secret" "secret" -- > { "os-image": ["http://example.com/disk.img", "public"], -- > "os-password": ["mypassword", "secret"] } makeInstanceParams - :: JSObject JSValue -> JSObject JSValue -> JSObject JSValue -> JSValue + :: JSObject JSValue + -> JSObject JSValue + -> JSObject JSValue + -> JSObject JSValue makeInstanceParams pub priv sec = - JSObject . JSON.toJSObject $ + JSON.toJSObject $ addVisibility "public" pub ++ addVisibility "private" priv ++ addVisibility "secret" sec @@ -92,7 +95,7 @@ makeInstanceParams pub priv sec = addVisibility param params = map (second (JSArray . (:[key param]))) (JSON.fromJSObject params) -getOsParamsWithVisibility :: JSValue -> Result JSValue +getOsParamsWithVisibility :: JSValue -> Result (JSObject JSValue) getOsParamsWithVisibility json = do obj <- readJSON json publicOsParams <- getPublicOsParams obj diff --git a/src/Ganeti/Metad/WebServer.hs b/src/Ganeti/Metad/WebServer.hs index 338d3e4..d47ab52 100644 --- a/src/Ganeti/Metad/WebServer.hs +++ b/src/Ganeti/Metad/WebServer.hs @@ -43,6 +43,7 @@ import qualified Control.Monad.CatchIO as CatchIO (catch) import qualified Data.CaseInsensitive as CI import Data.List (intercalate) import Data.Map (Map) +import qualified Data.List as List import qualified Data.Map as Map import qualified Data.ByteString.Char8 as ByteString (pack, unpack) import Snap.Core @@ -99,6 +100,19 @@ serveOsParams inst params = ByteString.pack . JSON.encode $ osParams +lookupSingleParam :: String -> JSObject JSValue -> Result String +lookupSingleParam param osParams = + case List.lookup param (JSON.fromJSObject osParams) of + Nothing -> Error $ "Instance does not have param " ++ param + Just v -> head <$> JSON.readJSON v + +serveSingleOsParam :: String -> Map String JSValue -> String -> MetaM +serveSingleOsParam inst params param = + do instParams <- lookupInstanceParams inst params + maybeResult (Config.getOsParamsWithVisibility instParams >>= + lookupSingleParam param) $ \paramValue -> + writeBS . ByteString.pack $ paramValue + serveOsPackage :: String -> Map String JSValue -> String -> MetaM serveOsPackage inst params key = do instParams <- lookupInstanceParams inst params @@ -164,6 +178,23 @@ handleMetadata params GET "ganeti" "latest" "os/parameters.json" = \err -> do liftIO . Logging.logWarning $ "Could not serve OS parameters: " ++ err error404 +handleMetadata params GET "ganeti" "latest" paramPath | isParamPath paramPath = + case split paramPath of + -- The validation of the first two entries is done in isParamPath + [_, _, param] -> do + remoteAddr <- ByteString.unpack . rqRemoteAddr <$> getRequest + instanceParams <- liftIO $ do + Logging.logInfo $ "OS package for " ++ show remoteAddr + readMVar params + serveSingleOsParam remoteAddr instanceParams param + `catchError` + \err -> do + liftIO . + Logging.logWarning $ "Could not serve single OS param " ++ param ++ + ": " ++ err + error404 + _ -> error404 + where isParamPath = (==) ["os", "parameters"] . take 2 . split handleMetadata params GET "ganeti" "latest" script | isScript script = do remoteAddr <- ByteString.unpack . rqRemoteAddr <$> getRequest instanceParams <- liftIO $ do -- 2.6.0.rc2.230.g3dd15c0
