Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Ssconf.hs @ ce52f060

History | View | Annotate | Download (5.9 kB)

1
{-# LANGUAGE TemplateHaskell #-}
2

    
3
{-| Implementation of the Ganeti Ssconf interface.
4

    
5
-}
6

    
7
{-
8

    
9
Copyright (C) 2012 Google Inc.
10

    
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.
15

    
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.
20

    
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
24
02110-1301, USA.
25

    
26
-}
27

    
28
module Ganeti.Ssconf
29
  ( SSKey(..)
30
  , sSKeyToRaw
31
  , sSKeyFromRaw
32
  , getPrimaryIPFamily
33
  , getMasterCandidatesIps
34
  , getMasterNode
35
  , keyToFilename
36
  , sSFilePrefix
37
  , SSConf(..)
38
  , emptySSConf
39
  ) where
40

    
41
import Control.Exception
42
import Control.Monad (liftM)
43
import qualified Data.Map as M
44
import Data.Maybe (fromMaybe)
45
import qualified Network.Socket as Socket
46
import System.FilePath ((</>))
47
import System.IO.Error (isDoesNotExistError)
48
import qualified Text.JSON as J
49

    
50
import qualified AutoConf
51
import Ganeti.BasicTypes
52
import qualified Ganeti.Constants as C
53
import Ganeti.JSON (GenericContainer(..), HasStringRepr(..))
54
import qualified Ganeti.Path as Path
55
import Ganeti.THH
56
import Ganeti.Utils
57

    
58
-- * Reading individual ssconf entries
59

    
60
-- | Maximum ssconf file size we support.
61
maxFileSize :: Int
62
maxFileSize = 131072
63

    
64
-- | ssconf file prefix, re-exported from Constants.
65
sSFilePrefix :: FilePath
66
sSFilePrefix = C.ssconfFileprefix
67

    
68
$(declareSADT "SSKey"
69
  [ ("SSClusterName",          'C.ssClusterName)
70
  , ("SSClusterTags",          'C.ssClusterTags)
71
  , ("SSFileStorageDir",       'C.ssFileStorageDir)
72
  , ("SSSharedFileStorageDir", 'C.ssSharedFileStorageDir)
73
  , ("SSGlusterStorageDir",    'C.ssGlusterStorageDir)
74
  , ("SSMasterCandidates",     'C.ssMasterCandidates)
75
  , ("SSMasterCandidatesIps",  'C.ssMasterCandidatesIps)
76
  , ("SSMasterCandidatesCerts",'C.ssMasterCandidatesCerts)
77
  , ("SSMasterIp",             'C.ssMasterIp)
78
  , ("SSMasterNetdev",         'C.ssMasterNetdev)
79
  , ("SSMasterNetmask",        'C.ssMasterNetmask)
80
  , ("SSMasterNode",           'C.ssMasterNode)
81
  , ("SSNodeList",             'C.ssNodeList)
82
  , ("SSNodePrimaryIps",       'C.ssNodePrimaryIps)
83
  , ("SSNodeSecondaryIps",     'C.ssNodeSecondaryIps)
84
  , ("SSOfflineNodes",         'C.ssOfflineNodes)
85
  , ("SSOnlineNodes",          'C.ssOnlineNodes)
86
  , ("SSPrimaryIpFamily",      'C.ssPrimaryIpFamily)
87
  , ("SSInstanceList",         'C.ssInstanceList)
88
  , ("SSReleaseVersion",       'C.ssReleaseVersion)
89
  , ("SSHypervisorList",       'C.ssHypervisorList)
90
  , ("SSMaintainNodeHealth",   'C.ssMaintainNodeHealth)
91
  , ("SSUidPool",              'C.ssUidPool)
92
  , ("SSNodegroups",           'C.ssNodegroups)
93
  , ("SSNetworks",             'C.ssNetworks)
94
  ])
95

    
96
instance HasStringRepr SSKey where
97
  fromStringRepr = sSKeyFromRaw
98
  toStringRepr = sSKeyToRaw
99

    
100
-- | Convert a ssconf key into a (full) file path.
101
keyToFilename :: FilePath     -- ^ Config path root
102
              -> SSKey        -- ^ Ssconf key
103
              -> FilePath     -- ^ Full file name
104
keyToFilename cfgpath key =
105
  cfgpath </> sSFilePrefix ++ sSKeyToRaw key
106

    
107
-- | Runs an IO action while transforming any error into 'Bad'
108
-- values. It also accepts an optional value to use in case the error
109
-- is just does not exist.
110
catchIOErrors :: Maybe a         -- ^ Optional default
111
              -> IO a            -- ^ Action to run
112
              -> IO (Result a)
113
catchIOErrors def action =
114
  Control.Exception.catch
115
        (do
116
          result <- action
117
          return (Ok result)
118
        ) (\err -> let bad_result = Bad (show err)
119
                   in return $ if isDoesNotExistError err
120
                                 then maybe bad_result Ok def
121
                                 else bad_result)
122

    
123
-- | Read an ssconf file.
124
readSSConfFile :: Maybe FilePath            -- ^ Optional config path override
125
               -> Maybe String              -- ^ Optional default value
126
               -> SSKey                     -- ^ Desired ssconf key
127
               -> IO (Result String)
128
readSSConfFile optpath def key = do
129
  dpath <- Path.dataDir
130
  result <- catchIOErrors def . readFile .
131
            keyToFilename (fromMaybe dpath optpath) $ key
132
  return (liftM (take maxFileSize) result)
133

    
134
-- | Parses a string containing an IP family
135
parseIPFamily :: Int -> Result Socket.Family
136
parseIPFamily fam | fam == AutoConf.pyAfInet4 = Ok Socket.AF_INET
137
                  | fam == AutoConf.pyAfInet6 = Ok Socket.AF_INET6
138
                  | otherwise = Bad $ "Unknown af_family value: " ++ show fam
139

    
140
-- | Read the primary IP family.
141
getPrimaryIPFamily :: Maybe FilePath -> IO (Result Socket.Family)
142
getPrimaryIPFamily optpath = do
143
  result <- readSSConfFile optpath
144
                           (Just (show AutoConf.pyAfInet4))
145
                           SSPrimaryIpFamily
146
  return (liftM rStripSpace result >>=
147
          tryRead "Parsing af_family" >>= parseIPFamily)
148

    
149
-- | Read the list of IP addresses of the master candidates of the cluster.
150
getMasterCandidatesIps :: Maybe FilePath -> IO (Result [String])
151
getMasterCandidatesIps optPath = do
152
  result <- readSSConfFile optPath Nothing SSMasterCandidatesIps
153
  return $ liftM lines result
154

    
155
-- | Read the name of the master node.
156
getMasterNode :: Maybe FilePath -> IO (Result String)
157
getMasterNode optPath = do
158
  result <- readSSConfFile optPath Nothing SSMasterNode
159
  return (liftM rStripSpace result)
160

    
161
-- * Working with the whole ssconf map
162

    
163
-- | The data type used for representing the ssconf.
164
newtype SSConf = SSConf { getSSConf :: M.Map SSKey [String] }
165
  deriving (Eq, Ord, Show)
166

    
167
instance J.JSON SSConf where
168
  showJSON = J.showJSON . GenericContainer . getSSConf
169
  readJSON = liftM (SSConf . fromContainer) . J.readJSON
170

    
171
emptySSConf :: SSConf
172
emptySSConf = SSConf M.empty