7 |
7 |
|
8 |
8 |
{-
|
9 |
9 |
|
10 |
|
Copyright (C) 2009, 2010, 2011 Google Inc.
|
|
10 |
Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
|
11 |
11 |
|
12 |
12 |
This program is free software; you can redistribute it and/or modify
|
13 |
13 |
it under the terms of the GNU General Public License as published by
|
... | ... | |
50 |
50 |
import qualified Ganeti.HTools.Node as Node
|
51 |
51 |
import qualified Ganeti.HTools.Instance as Instance
|
52 |
52 |
|
|
53 |
-- * Helper functions
|
|
54 |
|
|
55 |
-- | Simple wrapper over sepSplit
|
|
56 |
commaSplit :: String -> [String]
|
|
57 |
commaSplit = sepSplit ','
|
|
58 |
|
53 |
59 |
-- * Serialisation functions
|
54 |
60 |
|
55 |
61 |
-- | Serialize a single group.
|
... | ... | |
102 |
108 |
serializeInstances nl =
|
103 |
109 |
unlines . map (serializeInstance nl) . Container.elems
|
104 |
110 |
|
|
111 |
-- | Generate a spec data from a given ISpec object.
|
|
112 |
serializeISpec :: ISpec -> String
|
|
113 |
serializeISpec ispec =
|
|
114 |
-- this needs to be kept in sync with the object definition
|
|
115 |
let ISpec mem_s cpu_c disk_s disk_c nic_c = ispec
|
|
116 |
strings = [show mem_s, show cpu_c, show disk_s, show disk_c, show nic_c]
|
|
117 |
in intercalate "," strings
|
|
118 |
|
|
119 |
-- | Generate disk template data.
|
|
120 |
serializeDiskTemplates :: [DiskTemplate] -> String
|
|
121 |
serializeDiskTemplates = intercalate "," . map diskTemplateToRaw
|
|
122 |
|
|
123 |
-- | Generate policy data from a given policy object.
|
|
124 |
serializeIPolicy :: String -> IPolicy -> String
|
|
125 |
serializeIPolicy owner ipol =
|
|
126 |
let IPolicy stdspec minspec maxspec dts = ipol
|
|
127 |
strings = [ owner
|
|
128 |
, serializeISpec stdspec
|
|
129 |
, serializeISpec minspec
|
|
130 |
, serializeISpec maxspec
|
|
131 |
, serializeDiskTemplates dts
|
|
132 |
]
|
|
133 |
in intercalate "|" strings
|
|
134 |
|
|
135 |
-- | Generates the entire ipolicy section from the cluster and group
|
|
136 |
-- objects.
|
|
137 |
serializeAllIPolicies :: IPolicy -> Group.List -> String
|
|
138 |
serializeAllIPolicies cpol gl =
|
|
139 |
let groups = Container.elems gl
|
|
140 |
allpolicies = [("", cpol)] ++
|
|
141 |
map (\g -> (Group.name g, Group.iPolicy g)) groups
|
|
142 |
strings = map (uncurry serializeIPolicy) allpolicies
|
|
143 |
in unlines strings
|
|
144 |
|
105 |
145 |
-- | Generate complete cluster data from node and instance lists.
|
106 |
146 |
serializeCluster :: ClusterData -> String
|
107 |
|
serializeCluster (ClusterData gl nl il ctags _) =
|
|
147 |
serializeCluster (ClusterData gl nl il ctags cpol) =
|
108 |
148 |
let gdata = serializeGroups gl
|
109 |
149 |
ndata = serializeNodes gl nl
|
110 |
150 |
idata = serializeInstances nl il
|
|
151 |
pdata = serializeAllIPolicies cpol gl
|
111 |
152 |
-- note: not using 'unlines' as that adds too many newlines
|
112 |
|
in intercalate "\n" [gdata, ndata, idata, unlines ctags]
|
|
153 |
in intercalate "\n" [gdata, ndata, idata, unlines ctags, pdata]
|
113 |
154 |
|
114 |
155 |
-- * Parsing functions
|
115 |
156 |
|
... | ... | |
170 |
211 |
(diskTemplateFromRaw dt)
|
171 |
212 |
when (sidx == pidx) $ fail $ "Instance " ++ name ++
|
172 |
213 |
" has same primary and secondary node - " ++ pnode
|
173 |
|
let vtags = sepSplit ',' tags
|
|
214 |
let vtags = commaSplit tags
|
174 |
215 |
newinst = Instance.create name vmem vdsk vvcpus vstatus vtags
|
175 |
216 |
auto_balance pidx sidx disk_template
|
176 |
217 |
return (name, newinst)
|
177 |
218 |
loadInst _ s = fail $ "Invalid/incomplete instance data: '" ++ show s ++ "'"
|
178 |
219 |
|
|
220 |
-- | Loads a spec from a field list.
|
|
221 |
loadISpec :: String -> [String] -> Result ISpec
|
|
222 |
loadISpec owner [mem_s, cpu_c, dsk_s, dsk_c, nic_c] = do
|
|
223 |
xmem_s <- tryRead (owner ++ "/memsize") mem_s
|
|
224 |
xcpu_c <- tryRead (owner ++ "/cpucount") cpu_c
|
|
225 |
xdsk_s <- tryRead (owner ++ "/disksize") dsk_s
|
|
226 |
xdsk_c <- tryRead (owner ++ "/diskcount") dsk_c
|
|
227 |
xnic_c <- tryRead (owner ++ "/niccount") nic_c
|
|
228 |
return $ ISpec xmem_s xcpu_c xdsk_s xdsk_c xnic_c
|
|
229 |
loadISpec owner s = fail $ "Invalid ispec data for " ++ owner ++ ": " ++ show s
|
|
230 |
|
|
231 |
-- | Loads an ipolicy from a field list.
|
|
232 |
loadIPolicy :: [String] -> Result (String, IPolicy)
|
|
233 |
loadIPolicy [owner, stdspec, minspec, maxspec, dtemplates] = do
|
|
234 |
xstdspec <- loadISpec (owner ++ "/stdspec") (commaSplit stdspec)
|
|
235 |
xminspec <- loadISpec (owner ++ "/minspec") (commaSplit minspec)
|
|
236 |
xmaxspec <- loadISpec (owner ++ "/maxspec") (commaSplit maxspec)
|
|
237 |
xdts <- mapM diskTemplateFromRaw $ commaSplit dtemplates
|
|
238 |
return $ (owner, IPolicy xstdspec xminspec xmaxspec xdts)
|
|
239 |
loadIPolicy s = fail $ "Invalid ipolicy data: '" ++ show s ++ "'"
|
|
240 |
|
|
241 |
loadOnePolicy :: (IPolicy, Group.List) -> String
|
|
242 |
-> Result (IPolicy, Group.List)
|
|
243 |
loadOnePolicy (cpol, gl) line = do
|
|
244 |
(owner, ipol) <- loadIPolicy (sepSplit '|' line)
|
|
245 |
case owner of
|
|
246 |
"" -> return (ipol, gl) -- this is a cluster policy (no owner)
|
|
247 |
_ -> do
|
|
248 |
grp <- Container.findByName gl owner
|
|
249 |
let grp' = grp { Group.iPolicy = ipol }
|
|
250 |
gl' = Container.add (Group.idx grp') grp' gl
|
|
251 |
return (cpol, gl')
|
|
252 |
|
|
253 |
-- | Loads all policies from the policy section
|
|
254 |
loadAllIPolicies :: Group.List -> [String] -> Result (IPolicy, Group.List)
|
|
255 |
loadAllIPolicies gl =
|
|
256 |
foldM loadOnePolicy (defIPolicy, gl)
|
|
257 |
|
179 |
258 |
-- | Convert newline and delimiter-separated text.
|
180 |
259 |
--
|
181 |
260 |
-- This function converts a text in tabular format as generated by
|
... | ... | |
209 |
288 |
-> Result ClusterData
|
210 |
289 |
parseData fdata = do
|
211 |
290 |
let flines = lines fdata
|
212 |
|
(glines, nlines, ilines, ctags) <-
|
|
291 |
(glines, nlines, ilines, ctags, pollines) <-
|
213 |
292 |
case sepSplit "" flines of
|
214 |
|
[a, b, c, d] -> Ok (a, b, c, d)
|
|
293 |
[a, b, c, d, e] -> Ok (a, b, c, d, e)
|
|
294 |
[a, b, c, d] -> Ok (a, b, c, d, [])
|
215 |
295 |
xs -> Bad $ printf "Invalid format of the input file: %d sections\
|
216 |
|
\ instead of 4" (length xs)
|
|
296 |
\ instead of 4 or 5" (length xs)
|
217 |
297 |
{- group file: name uuid -}
|
218 |
298 |
(ktg, gl) <- loadTabular glines loadGroup
|
219 |
299 |
{- node file: name t_mem n_mem f_mem t_disk f_disk -}
|
... | ... | |
221 |
301 |
{- instance file: name mem disk status pnode snode -}
|
222 |
302 |
(_, il) <- loadTabular ilines (loadInst ktn)
|
223 |
303 |
{- the tags are simply line-based, no processing needed -}
|
224 |
|
return (ClusterData gl nl il ctags defIPolicy)
|
|
304 |
{- process policies -}
|
|
305 |
(cpol, gl') <- loadAllIPolicies gl pollines
|
|
306 |
return (ClusterData gl' nl il ctags cpol)
|
225 |
307 |
|
226 |
308 |
-- | Top level function for data loading.
|
227 |
309 |
loadData :: String -- ^ Path to the text file
|