Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / Config.hs @ 9a94c848

History | View | Annotate | Download (7 kB)

1 eaa64cd8 Iustin Pop
{-| Implementation of the Ganeti configuration database.
2 eaa64cd8 Iustin Pop
3 eaa64cd8 Iustin Pop
-}
4 eaa64cd8 Iustin Pop
5 eaa64cd8 Iustin Pop
{-
6 eaa64cd8 Iustin Pop
7 eaa64cd8 Iustin Pop
Copyright (C) 2011, 2012 Google Inc.
8 eaa64cd8 Iustin Pop
9 eaa64cd8 Iustin Pop
This program is free software; you can redistribute it and/or modify
10 eaa64cd8 Iustin Pop
it under the terms of the GNU General Public License as published by
11 eaa64cd8 Iustin Pop
the Free Software Foundation; either version 2 of the License, or
12 eaa64cd8 Iustin Pop
(at your option) any later version.
13 eaa64cd8 Iustin Pop
14 eaa64cd8 Iustin Pop
This program is distributed in the hope that it will be useful, but
15 eaa64cd8 Iustin Pop
WITHOUT ANY WARRANTY; without even the implied warranty of
16 eaa64cd8 Iustin Pop
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 eaa64cd8 Iustin Pop
General Public License for more details.
18 eaa64cd8 Iustin Pop
19 eaa64cd8 Iustin Pop
You should have received a copy of the GNU General Public License
20 eaa64cd8 Iustin Pop
along with this program; if not, write to the Free Software
21 eaa64cd8 Iustin Pop
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 eaa64cd8 Iustin Pop
02110-1301, USA.
23 eaa64cd8 Iustin Pop
24 eaa64cd8 Iustin Pop
-}
25 eaa64cd8 Iustin Pop
26 eaa64cd8 Iustin Pop
module Ganeti.Config
27 eaa64cd8 Iustin Pop
    ( LinkIpMap
28 eaa64cd8 Iustin Pop
    , loadConfig
29 eaa64cd8 Iustin Pop
    , getNodeInstances
30 eaa64cd8 Iustin Pop
    , getDefaultNicLink
31 eaa64cd8 Iustin Pop
    , getInstancesIpByLink
32 eaa64cd8 Iustin Pop
    , getNode
33 eaa64cd8 Iustin Pop
    , getInstance
34 eaa64cd8 Iustin Pop
    , getInstPrimaryNode
35 d81ec8b7 Iustin Pop
    , getInstMinorsForNode
36 eaa64cd8 Iustin Pop
    , buildLinkIpInstnameMap
37 7b2ead5a Iustin Pop
    , instNodes
38 eaa64cd8 Iustin Pop
    ) where
39 eaa64cd8 Iustin Pop
40 2cdaf225 Iustin Pop
import Control.Monad (liftM)
41 eaa64cd8 Iustin Pop
import Data.List (foldl')
42 eaa64cd8 Iustin Pop
import qualified Data.Map as M
43 7b2ead5a Iustin Pop
import qualified Data.Set as S
44 eaa64cd8 Iustin Pop
import qualified Text.JSON as J
45 eaa64cd8 Iustin Pop
46 eaa64cd8 Iustin Pop
import Ganeti.HTools.JSON
47 eaa64cd8 Iustin Pop
import Ganeti.BasicTypes
48 eaa64cd8 Iustin Pop
49 eaa64cd8 Iustin Pop
import qualified Ganeti.Constants as C
50 eaa64cd8 Iustin Pop
import Ganeti.Objects
51 eaa64cd8 Iustin Pop
52 eaa64cd8 Iustin Pop
-- | Type alias for the link and ip map.
53 eaa64cd8 Iustin Pop
type LinkIpMap = M.Map String (M.Map String String)
54 eaa64cd8 Iustin Pop
55 eaa64cd8 Iustin Pop
-- | Reads the config file.
56 eaa64cd8 Iustin Pop
readConfig :: FilePath -> IO String
57 eaa64cd8 Iustin Pop
readConfig = readFile
58 eaa64cd8 Iustin Pop
59 eaa64cd8 Iustin Pop
-- | Parses the configuration file.
60 eaa64cd8 Iustin Pop
parseConfig :: String -> Result ConfigData
61 eaa64cd8 Iustin Pop
parseConfig = fromJResult "parsing configuration" . J.decodeStrict
62 eaa64cd8 Iustin Pop
63 eaa64cd8 Iustin Pop
-- | Wrapper over 'readConfig' and 'parseConfig'.
64 eaa64cd8 Iustin Pop
loadConfig :: FilePath -> IO (Result ConfigData)
65 eaa64cd8 Iustin Pop
loadConfig = fmap parseConfig . readConfig
66 eaa64cd8 Iustin Pop
67 eaa64cd8 Iustin Pop
-- * Query functions
68 eaa64cd8 Iustin Pop
69 7b2ead5a Iustin Pop
-- | Computes the nodes covered by a disk.
70 7b2ead5a Iustin Pop
computeDiskNodes :: Disk -> S.Set String
71 7b2ead5a Iustin Pop
computeDiskNodes dsk =
72 7b2ead5a Iustin Pop
  case diskLogicalId dsk of
73 7b2ead5a Iustin Pop
    LIDDrbd8 nodeA nodeB _ _ _ _ -> S.fromList [nodeA, nodeB]
74 7b2ead5a Iustin Pop
    _ -> S.empty
75 7b2ead5a Iustin Pop
76 7b2ead5a Iustin Pop
-- | Computes all disk-related nodes of an instance. For non-DRBD,
77 7b2ead5a Iustin Pop
-- this will be empty, for DRBD it will contain both the primary and
78 7b2ead5a Iustin Pop
-- the secondaries.
79 7b2ead5a Iustin Pop
instDiskNodes :: Instance -> S.Set String
80 7b2ead5a Iustin Pop
instDiskNodes = S.unions . map computeDiskNodes . instDisks
81 7b2ead5a Iustin Pop
82 7b2ead5a Iustin Pop
-- | Computes all nodes of an instance.
83 7b2ead5a Iustin Pop
instNodes :: Instance -> S.Set String
84 7b2ead5a Iustin Pop
instNodes inst = instPrimaryNode inst `S.insert` instDiskNodes inst
85 7b2ead5a Iustin Pop
86 7b2ead5a Iustin Pop
-- | Computes the secondary nodes of an instance. Since this is valid
87 7b2ead5a Iustin Pop
-- only for DRBD, we call directly 'instDiskNodes', skipping over the
88 7b2ead5a Iustin Pop
-- extra primary insert.
89 7b2ead5a Iustin Pop
instSecondaryNodes :: Instance -> S.Set String
90 7b2ead5a Iustin Pop
instSecondaryNodes inst =
91 7b2ead5a Iustin Pop
  instPrimaryNode inst `S.delete` instDiskNodes inst
92 7b2ead5a Iustin Pop
93 eaa64cd8 Iustin Pop
-- | Get instances of a given node.
94 eaa64cd8 Iustin Pop
getNodeInstances :: ConfigData -> String -> ([Instance], [Instance])
95 eaa64cd8 Iustin Pop
getNodeInstances cfg nname =
96 84835174 Iustin Pop
    let all_inst = M.elems . fromContainer . configInstances $ cfg
97 eaa64cd8 Iustin Pop
        pri_inst = filter ((== nname) . instPrimaryNode) all_inst
98 7b2ead5a Iustin Pop
        sec_inst = filter ((nname `S.member`) . instSecondaryNodes) all_inst
99 eaa64cd8 Iustin Pop
    in (pri_inst, sec_inst)
100 eaa64cd8 Iustin Pop
101 eaa64cd8 Iustin Pop
-- | Returns the default cluster link.
102 eaa64cd8 Iustin Pop
getDefaultNicLink :: ConfigData -> String
103 eaa64cd8 Iustin Pop
getDefaultNicLink =
104 84835174 Iustin Pop
  nicpLink . (M.! C.ppDefault) . fromContainer .
105 84835174 Iustin Pop
  clusterNicparams . configCluster
106 eaa64cd8 Iustin Pop
107 eaa64cd8 Iustin Pop
-- | Returns instances of a given link.
108 eaa64cd8 Iustin Pop
getInstancesIpByLink :: LinkIpMap -> String -> [String]
109 eaa64cd8 Iustin Pop
getInstancesIpByLink linkipmap link =
110 eaa64cd8 Iustin Pop
  M.keys $ M.findWithDefault M.empty link linkipmap
111 eaa64cd8 Iustin Pop
112 0fc8e521 Iustin Pop
-- | Generic lookup function that converts from a possible abbreviated
113 0fc8e521 Iustin Pop
-- name to a full name.
114 0fc8e521 Iustin Pop
getItem :: String -> String -> M.Map String a -> Result a
115 0fc8e521 Iustin Pop
getItem kind name allitems = do
116 0fc8e521 Iustin Pop
  let lresult = lookupName (M.keys allitems) name
117 0fc8e521 Iustin Pop
      err = \details -> Bad $ kind ++ " name " ++ name ++ " " ++ details
118 0fc8e521 Iustin Pop
  fullname <- case lrMatchPriority lresult of
119 0fc8e521 Iustin Pop
                PartialMatch -> Ok $ lrContent lresult
120 0fc8e521 Iustin Pop
                ExactMatch -> Ok $ lrContent lresult
121 0fc8e521 Iustin Pop
                MultipleMatch -> err "has multiple matches"
122 0fc8e521 Iustin Pop
                FailMatch -> err "not found"
123 0fc8e521 Iustin Pop
  maybe (err "not found after successfull match?!") Ok $
124 0fc8e521 Iustin Pop
        M.lookup fullname allitems
125 0fc8e521 Iustin Pop
126 eaa64cd8 Iustin Pop
-- | Looks up a node.
127 eaa64cd8 Iustin Pop
getNode :: ConfigData -> String -> Result Node
128 84835174 Iustin Pop
getNode cfg name = getItem "Node" name (fromContainer $ configNodes cfg)
129 eaa64cd8 Iustin Pop
130 eaa64cd8 Iustin Pop
-- | Looks up an instance.
131 eaa64cd8 Iustin Pop
getInstance :: ConfigData -> String -> Result Instance
132 84835174 Iustin Pop
getInstance cfg name =
133 84835174 Iustin Pop
  getItem "Instance" name (fromContainer $ configInstances cfg)
134 eaa64cd8 Iustin Pop
135 eaa64cd8 Iustin Pop
-- | Looks up an instance's primary node.
136 eaa64cd8 Iustin Pop
getInstPrimaryNode :: ConfigData -> String -> Result Node
137 eaa64cd8 Iustin Pop
getInstPrimaryNode cfg name =
138 2cdaf225 Iustin Pop
  liftM instPrimaryNode (getInstance cfg name) >>= getNode cfg
139 eaa64cd8 Iustin Pop
140 d81ec8b7 Iustin Pop
-- | Filters DRBD minors for a given node.
141 d81ec8b7 Iustin Pop
getDrbdMinorsForNode :: String -> Disk -> [(Int, String)]
142 d81ec8b7 Iustin Pop
getDrbdMinorsForNode node disk =
143 d81ec8b7 Iustin Pop
  let child_minors = concatMap (getDrbdMinorsForNode node) (diskChildren disk)
144 d81ec8b7 Iustin Pop
      this_minors =
145 d81ec8b7 Iustin Pop
        case diskLogicalId disk of
146 d81ec8b7 Iustin Pop
          LIDDrbd8 nodeA nodeB _ minorA minorB _
147 d81ec8b7 Iustin Pop
            | nodeA == node -> [(minorA, nodeB)]
148 d81ec8b7 Iustin Pop
            | nodeB == node -> [(minorB, nodeA)]
149 d81ec8b7 Iustin Pop
          _ -> []
150 d81ec8b7 Iustin Pop
  in this_minors ++ child_minors
151 d81ec8b7 Iustin Pop
152 d81ec8b7 Iustin Pop
-- | String for primary role.
153 d81ec8b7 Iustin Pop
rolePrimary :: String
154 d81ec8b7 Iustin Pop
rolePrimary = "primary"
155 d81ec8b7 Iustin Pop
156 d81ec8b7 Iustin Pop
-- | String for secondary role.
157 d81ec8b7 Iustin Pop
roleSecondary :: String
158 d81ec8b7 Iustin Pop
roleSecondary = "secondary"
159 d81ec8b7 Iustin Pop
160 d81ec8b7 Iustin Pop
-- | Gets the list of DRBD minors for an instance that are related to
161 d81ec8b7 Iustin Pop
-- a given node.
162 d81ec8b7 Iustin Pop
getInstMinorsForNode :: String -> Instance
163 d81ec8b7 Iustin Pop
                     -> [(String, Int, String, String, String, String)]
164 d81ec8b7 Iustin Pop
getInstMinorsForNode node inst =
165 d81ec8b7 Iustin Pop
  let role = if node == instPrimaryNode inst
166 d81ec8b7 Iustin Pop
               then rolePrimary
167 d81ec8b7 Iustin Pop
               else roleSecondary
168 d81ec8b7 Iustin Pop
      iname = instName inst
169 d81ec8b7 Iustin Pop
  -- FIXME: the disk/ build there is hack-ish; unify this in a
170 d81ec8b7 Iustin Pop
  -- separate place, or reuse the iv_name (but that is deprecated on
171 d81ec8b7 Iustin Pop
  -- the Python side)
172 d81ec8b7 Iustin Pop
  in concatMap (\(idx, dsk) ->
173 d81ec8b7 Iustin Pop
            [(node, minor, iname, "disk/" ++ show idx, role, peer)
174 d81ec8b7 Iustin Pop
               | (minor, peer) <- getDrbdMinorsForNode node dsk]) .
175 d81ec8b7 Iustin Pop
     zip [(0::Int)..] . instDisks $ inst
176 d81ec8b7 Iustin Pop
177 eaa64cd8 Iustin Pop
-- | Builds link -> ip -> instname map.
178 eaa64cd8 Iustin Pop
--
179 eaa64cd8 Iustin Pop
-- TODO: improve this by splitting it into multiple independent functions:
180 eaa64cd8 Iustin Pop
--
181 eaa64cd8 Iustin Pop
-- * abstract the \"fetch instance with filled params\" functionality
182 eaa64cd8 Iustin Pop
--
183 eaa64cd8 Iustin Pop
-- * abstsract the [instance] -> [(nic, instance_name)] part
184 eaa64cd8 Iustin Pop
--
185 eaa64cd8 Iustin Pop
-- * etc.
186 eaa64cd8 Iustin Pop
buildLinkIpInstnameMap :: ConfigData -> LinkIpMap
187 eaa64cd8 Iustin Pop
buildLinkIpInstnameMap cfg =
188 eaa64cd8 Iustin Pop
  let cluster = configCluster cfg
189 84835174 Iustin Pop
      instances = M.elems . fromContainer . configInstances $ cfg
190 84835174 Iustin Pop
      defparams = (M.!) (fromContainer $ clusterNicparams cluster) C.ppDefault
191 eaa64cd8 Iustin Pop
      nics = concatMap (\i -> [(instName i, nic) | nic <- instNics i])
192 eaa64cd8 Iustin Pop
             instances
193 eaa64cd8 Iustin Pop
  in foldl' (\accum (iname, nic) ->
194 eaa64cd8 Iustin Pop
               let pparams = nicNicparams nic
195 eaa64cd8 Iustin Pop
                   fparams = fillNICParams defparams pparams
196 eaa64cd8 Iustin Pop
                   link = nicpLink fparams
197 eaa64cd8 Iustin Pop
               in case nicIp nic of
198 eaa64cd8 Iustin Pop
                    Nothing -> accum
199 eaa64cd8 Iustin Pop
                    Just ip -> let oldipmap = M.findWithDefault (M.empty)
200 eaa64cd8 Iustin Pop
                                              link accum
201 eaa64cd8 Iustin Pop
                                   newipmap = M.insert ip iname oldipmap
202 eaa64cd8 Iustin Pop
                               in M.insert link newipmap accum
203 eaa64cd8 Iustin Pop
            ) M.empty nics