Revision b37f4a76

b/htools/Ganeti/HTools/QC.hs
803 803
                ctags ==? ctags2 .&&.
804 804
                Types.defIPolicy ==? cpol2 .&&.
805 805
                il' ==? il2 .&&.
806
                -- we need to override the policy manually for now for
807
                -- nodes and groups
808
                defGroupList ==? (Container.map (\g -> g { Group.iPolicy =
809
                                                             nullIPolicy } )
810
                                  gl2) .&&.
811
                nl' ==? Container.map (Node.setPolicy nullIPolicy) nl2
806
                defGroupList ==? gl2 .&&.
807
                nl' ==? nl2
812 808

  
813 809
testSuite "Text"
814 810
            [ 'prop_Text_Load_Instance
b/htools/Ganeti/HTools/Text.hs
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

Also available in: Unified diff