]>
git.ipfire.org Git - nitsi.git/blob - test.py
36d5277e4acb223539ab7b54b7482dac93cf642d
13 def __init__(self
, log_level
):
14 self
.log_level
= log_level
16 def debug(self
, string
):
17 if self
.log_level
>= 4:
18 print("DEBUG: {}".format(string
))
20 def error(self
, string
):
21 print("ERROR: {}".format(string
))
24 def __init__(self
, uri
):
27 self
.connection
= None
29 def get_domain_from_name(self
, name
):
30 dom
= self
.con
.lookupByName(name
)
38 if self
.connection
== None:
40 self
.connection
= libvirt
.open(self
.uri
)
41 except BaseException
as error
:
42 self
.log
.error("Could not connect to: {}".format(self
.uri
))
44 self
.log
.debug("Connected to: {}".format(self
.uri
))
45 return self
.connection
47 return self
.connection
51 # A class which define and undefine a virtual network based on an xml file
53 def __init__(self
, network_xml_file
):
55 self
.con
= libvirt_con("qemu:///system")
57 with
open(network_xml_file
) as fobj
:
58 self
.network_xml
= fobj
.read()
59 except FileNotFoundError
as error
:
60 self
.log
.error("No such file: {}".format(vm_xml_file
))
63 self
.network
= self
.con
.con
.networkDefineXML(self
.network_xml
)
66 self
.log
.error("Failed to define virtual network")
72 self
.network
.destroy()
76 class RecipeExeption(Exception):
81 # Should read the test, check if the syntax are valid
82 # and return tuples with the ( host, command ) structure
84 def __init__(self
, path
, circle
=[]):
86 self
.recipe_file
= path
87 self
.path
= os
.path
.dirname(self
.recipe_file
)
88 self
.log
.debug("Path of recipe is: {}".format(self
.recipe_file
))
92 self
.in_recursion
= True
94 self
.in_recursion
= False
97 self
.log
.debug(circle
)
98 self
.log
.debug(self
.circle
)
100 if not os
.path
.isfile(self
.recipe_file
):
101 self
.log
.error("No such file: {}".format(self
.recipe_file
))
104 with
open(self
.recipe_file
) as fobj
:
105 self
.raw_recipe
= fobj
.readlines()
106 except FileNotFoundError
as error
:
107 self
.log
.error("No such file: {}".format(vm_xml_file
))
118 if not self
._machines
:
120 for line
in self
._recipe
:
121 if line
[0] != "all" and line
[0] not in self
._machines
:
122 self
._machines
.append(line
[0])
124 return self
._machines
129 for line
in self
.raw_recipe
:
130 raw_line
= line
.split(":")
131 if len(raw_line
) < 2:
132 self
.log
.error("Error parsing the recipe in line {}".format(i
))
134 cmd
= raw_line
[1].strip()
135 raw_line
= raw_line
[0].strip().split(" ")
136 if len(raw_line
) == 0:
137 self
.log
.error("Failed to parse the recipe in line {}".format(i
))
140 if raw_line
[0].strip() == "":
141 self
.log
.error("Failed to parse the recipe in line {}".format(i
))
144 machine
= raw_line
[0].strip()
146 if len(raw_line
) == 2:
147 extra
= raw_line
[1].strip()
151 # We could get a machine here or a include statement
152 if machine
== "include":
154 path
= os
.path
.normpath(self
.path
+ "/" + path
)
155 path
= path
+ "/recipe"
156 if path
in self
.circle
:
157 self
.log
.error("Detect import loop!")
159 self
.circle
.append(path
)
160 recipe_to_include
= recipe(path
, circle
=self
.circle
)
162 if machine
== "include":
163 self
._recipe
.extend(recipe_to_include
.recipe
)
165 # Support also something like 'alice,bob: echo'
166 machines
= machine
.split(",")
167 for machine
in machines
:
168 self
._recipe
.append((machine
.strip(), extra
.strip(), cmd
.strip()))
171 if not self
.in_recursion
:
173 for line
in self
._recipe
:
175 tmp_recipe
.append(line
)
177 for machine
in self
.machines
:
178 tmp_recipe
.append((machine
.strip(), line
[1], line
[2]))
180 self
._recipe
= tmp_recipe
185 def __init__(self
, path
):
188 self
.path
= os
.path
.abspath(path
)
189 except BaseException
as e
:
190 self
.log
.error("Could not get absolute path")
192 self
.log
.debug(self
.path
)
194 self
.settings_file
= "{}/settings".format(self
.path
)
195 if not os
.path
.isfile(self
.settings_file
):
196 self
.log
.error("No such file: {}".format(self
.settings_file
))
198 self
.recipe_file
= "{}/recipe".format(self
.path
)
199 if not os
.path
.isfile(self
.recipe_file
):
200 self
.log
.error("No such file: {}".format(self
.recipe_file
))
202 def read_settings(self
):
203 self
.config
= configparser
.ConfigParser()
204 self
.config
.read(self
.settings_file
)
205 self
.name
= self
.config
["DEFAULT"]["Name"]
206 self
.description
= self
.config
["DEFAULT"]["Description"]
207 self
.copy_to
= self
.config
["DEFAULT"]["Copy_to"]
208 self
.copy_from
= self
.config
["DEFAULT"]["Copy_from"]
209 self
.copy_from
= self
.copy_from
.split(",")
212 for file in self
.copy_from
:
214 file = os
.path
.normpath(self
.path
+ "/" + file)
219 self
.virtual_environ_name
= self
.config
["VIRTUAL_ENVIRONMENT"]["Name"]
220 self
.virtual_environ_path
= self
.config
["VIRTUAL_ENVIRONMENT"]["Path"]
221 self
.virtual_environ_path
= os
.path
.normpath(self
.path
+ "/" + self
.virtual_environ_path
)
223 def virtual_environ_setup(self
):
224 self
.virtual_environ
= virtual_environ(self
.virtual_environ_path
)
226 self
.virtual_networks
= self
.virtual_environ
.get_networks()
228 self
.virtual_machines
= self
.virtual_environ
.get_machines()
230 def virtual_environ_start(self
):
231 for name
in self
.virtual_environ
.network_names
:
232 self
.virtual_networks
[name
].define()
233 self
.virtual_networks
[name
].start()
235 for name
in self
.virtual_environ
.machine_names
:
236 self
.virtual_machines
[name
].define()
237 self
.virtual_machines
[name
].create_snapshot()
238 self
.virtual_machines
[name
].copy_in(self
.copy_from
, self
.copy_to
)
239 self
.virtual_machines
[name
].start()
241 self
.log
.debug("Try to login on all machines")
242 for name
in self
.virtual_environ
.machine_names
:
243 self
.virtual_machines
[name
].login()
245 def load_recipe(self
):
247 self
.recipe
= recipe(self
.recipe_file
)
248 except BaseException
:
249 self
.log
.error("Failed to load recipe")
252 def run_recipe(self
):
253 for line
in self
.recipe
.recipe
:
254 return_value
= self
.virtual_machines
[line
[0]].cmd(line
[2])
255 self
.log
.debug("Return value is: {}".format(return_value
))
256 if return_value
!= "0" and line
[1] == "":
257 self
.log
.error("Failed to execute command '{}' on {}, return code: {}".format(line
[2],line
[0], return_value
))
259 elif return_value
== "0" and line
[1] == "!":
260 self
.log
.error("Succeded to execute command '{}' on {}, return code: {}".format(line
[2],line
[0],return_value
))
263 self
.log
.debug("Command '{}' on {} returned with: {}".format(line
[2],line
[0],return_value
))
265 def virtual_environ_stop(self
):
266 for name
in self
.virtual_environ
.machine_names
:
267 self
.virtual_machines
[name
].shutdown()
268 self
.virtual_machines
[name
].revert_snapshot()
269 self
.virtual_machines
[name
].undefine()
271 for name
in self
.virtual_environ
.network_names
:
272 self
.virtual_networks
[name
].undefine()
275 # Should return all vms and networks in a list
276 # and should provide the path to the necessary xml files
277 class virtual_environ():
278 def __init__(self
, path
):
281 self
.path
= os
.path
.abspath(path
)
282 except BaseException
as e
:
283 self
.log
.error("Could not get absolute path")
285 self
.log
.debug(self
.path
)
287 self
.settings_file
= "{}/settings".format(self
.path
)
288 if not os
.path
.isfile(self
.settings_file
):
289 self
.log
.error("No such file: {}".format(self
.settings_file
))
291 self
.log
.debug(self
.settings_file
)
292 self
.config
= configparser
.ConfigParser()
293 self
.config
.read(self
.settings_file
)
294 self
.name
= self
.config
["DEFAULT"]["name"]
295 self
.machines_string
= self
.config
["DEFAULT"]["machines"]
296 self
.networks_string
= self
.config
["DEFAULT"]["networks"]
299 for machine
in self
.machines_string
.split(","):
300 self
.machines
.append(machine
.strip())
303 for network
in self
.networks_string
.split(","):
304 self
.networks
.append(network
.strip())
306 self
.log
.debug(self
.machines
)
307 self
.log
.debug(self
.networks
)
309 def get_networks(self
):
311 for _network
in self
.networks
:
312 self
.log
.debug(_network
)
313 networks
.setdefault(_network
, network(os
.path
.normpath(self
.path
+ "/" + self
.config
[_network
]["xml_file"])))
316 def get_machines(self
):
318 for _machine
in self
.machines
:
319 self
.log
.debug(_machine
)
320 machines
.setdefault(_machine
, machine(
321 os
.path
.normpath(self
.path
+ "/" + self
.config
[_machine
]["xml_file"]),
322 os
.path
.normpath(self
.path
+ "/" + self
.config
[_machine
]["snapshot_xml_file"]),
323 self
.config
[_machine
]["image"],
324 self
.config
[_machine
]["root_uid"],
325 self
.config
[_machine
]["username"],
326 self
.config
[_machine
]["password"]))
331 def machine_names(self
):
335 def network_names(self
):
339 if __name__
== "__main__":
342 parser
= argparse
.ArgumentParser()
344 parser
.add_argument("-d", "--directory", dest
="dir")
346 args
= parser
.parse_args()
348 currenttest
= test(args
.dir)
349 currenttest
.read_settings()
350 currenttest
.virtual_environ_setup()
351 currenttest
.load_recipe()
353 currenttest
.virtual_environ_start()
354 currenttest
.run_recipe()
355 except BaseException
as e
:
358 currenttest
.virtual_environ_stop()