1 {-# LANGUAGE TemplateHaskell #-}
3 {-| Implementation of the Ganeti Ssconf interface.
9 Copyright (C) 2012 Google Inc.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
33 , getMasterCandidatesIps
40 import Control.Exception
41 import Control.Monad (liftM)
42 import Data.Maybe (fromMaybe)
43 import qualified Network.Socket as Socket
44 import System.FilePath ((</>))
45 import System.IO.Error (isDoesNotExistError)
47 import qualified Ganeti.Constants as C
48 import qualified Ganeti.Path as Path
49 import Ganeti.BasicTypes
52 -- | Maximum ssconf file size we support.
56 -- | ssconf file prefix, re-exported from Constants.
57 sSFilePrefix :: FilePath
58 sSFilePrefix = C.ssconfFileprefix
61 [ ("SSClusterName", 'C.ssClusterName)
62 , ("SSClusterTags", 'C.ssClusterTags)
63 , ("SSFileStorageDir", 'C.ssFileStorageDir)
64 , ("SSSharedFileStorageDir", 'C.ssSharedFileStorageDir)
65 , ("SSMasterCandidates", 'C.ssMasterCandidates)
66 , ("SSMasterCandidatesIps", 'C.ssMasterCandidatesIps)
67 , ("SSMasterIp", 'C.ssMasterIp)
68 , ("SSMasterNetdev", 'C.ssMasterNetdev)
69 , ("SSMasterNetmask", 'C.ssMasterNetmask)
70 , ("SSMasterNode", 'C.ssMasterNode)
71 , ("SSNodeList", 'C.ssNodeList)
72 , ("SSNodePrimaryIps", 'C.ssNodePrimaryIps)
73 , ("SSNodeSecondaryIps", 'C.ssNodeSecondaryIps)
74 , ("SSOfflineNodes", 'C.ssOfflineNodes)
75 , ("SSOnlineNodes", 'C.ssOnlineNodes)
76 , ("SSPrimaryIpFamily", 'C.ssPrimaryIpFamily)
77 , ("SSInstanceList", 'C.ssInstanceList)
78 , ("SSReleaseVersion", 'C.ssReleaseVersion)
79 , ("SSHypervisorList", 'C.ssHypervisorList)
80 , ("SSMaintainNodeHealth", 'C.ssMaintainNodeHealth)
81 , ("SSUidPool", 'C.ssUidPool)
82 , ("SSNodegroups", 'C.ssNodegroups)
85 -- | Convert a ssconf key into a (full) file path.
86 keyToFilename :: FilePath -- ^ Config path root
87 -> SSKey -- ^ Ssconf key
88 -> FilePath -- ^ Full file name
89 keyToFilename cfgpath key =
90 cfgpath </> sSFilePrefix ++ sSKeyToRaw key
92 -- | Runs an IO action while transforming any error into 'Bad'
93 -- values. It also accepts an optional value to use in case the error
94 -- is just does not exist.
95 catchIOErrors :: Maybe a -- ^ Optional default
96 -> IO a -- ^ Action to run
98 catchIOErrors def action =
99 Control.Exception.catch
103 ) (\err -> let bad_result = Bad (show err)
104 in return $ if isDoesNotExistError err
105 then maybe bad_result Ok def
108 -- | Read an ssconf file.
109 readSSConfFile :: Maybe FilePath -- ^ Optional config path override
110 -> Maybe String -- ^ Optional default value
111 -> SSKey -- ^ Desired ssconf key
112 -> IO (Result String)
113 readSSConfFile optpath def key = do
114 dpath <- Path.dataDir
115 result <- catchIOErrors def . readFile .
116 keyToFilename (fromMaybe dpath optpath) $ key
117 return (liftM (take maxFileSize) result)
119 -- | Parses a string containing an IP family
120 parseIPFamily :: Int -> Result Socket.Family
121 parseIPFamily fam | fam == C.ip4Family = Ok Socket.AF_INET
122 | fam == C.ip6Family = Ok Socket.AF_INET6
123 | otherwise = Bad $ "Unknown af_family value: " ++ show fam
125 -- | Read the primary IP family.
126 getPrimaryIPFamily :: Maybe FilePath -> IO (Result Socket.Family)
127 getPrimaryIPFamily optpath = do
128 result <- readSSConfFile optpath (Just (show C.ip4Family)) SSPrimaryIpFamily
129 return (liftM rStripSpace result >>=
130 tryRead "Parsing af_family" >>= parseIPFamily)
132 -- | Read the list of IP addresses of the master candidates of the cluster.
133 getMasterCandidatesIps :: Maybe FilePath -> IO (Result [String])
134 getMasterCandidatesIps optPath = do
135 result <- readSSConfFile optPath Nothing SSMasterCandidatesIps
136 return $ liftM lines result