]>
git.ipfire.org Git - nitsi.git/blob - src/nitsi/test.py
10 from . import virtual_environ
12 logger
= logging
.getLogger("nitsi.test")
15 class TestException(Exception):
16 def __init__(self
, message
):
17 self
.message
= message
20 def __init__(self
, log_path
, dir=None, recipe_file
=None, settings_file
=None, cmd_settings
=None):
24 # Set default values for the settings dict
25 self
.settings
["name"] = ""
26 self
.settings
["description"] = ""
27 self
.settings
["copy_from"] = None
28 self
.settings
["copy_to"] = None
29 self
.settings
["virtual_environ_path"] = None
31 self
.cmd_settings
= cmd_settings
32 self
.log_path
= log_path
34 # Init all vars with None
35 self
.settings_file
= None
36 self
.recipe_file
= None
39 # We need at least a path to a recipe file or a dir to a test
40 if not dir and not recipe
:
41 raise TestException("Did not get a path to a test or to a recipe file")
43 # We cannot decide which to use when we get both
44 if (dir and recipe_file
) or (dir and settings_file
):
45 raise TestException("Get dir and path to recipe or settings file")
49 if not os
.path
.isabs(dir):
50 self
.path
= os
.path
.abspath(dir)
51 except BaseException
as e
:
52 logger
.error("Could not get absolute path")
55 logger
.debug("Path of this test is: {}".format(self
.path
))
57 self
.recipe_file
= "{}/recipe".format(self
.path
)
58 self
.settings_file
= "{}/settings".format(self
.path
)
61 if not os
.path
.isabs(recipe_file
):
62 self
.recipe_file
= os
.path
.abspath(recipe_file
)
64 self
.recipe_file
= recipe_file
67 if not os
.path
.isabs(settings_file
):
68 self
.settings_file
= os
.path
.abspath(settings_file
)
70 self
.settings_file
= settings_file
72 # We can also go on without a settings file
73 if self
.settings_file
:
74 if not os
.path
.isfile(self
.settings_file
):
75 logger
.error("No such file: {}".format(self
.settings_file
))
76 raise TestException("No settings file found")
78 # os.path.isfile fails if self.recipe_file is None so we need to catch exceptions here
80 if not (self
.recipe_file
or os
.path
.isfile(self
.recipe_file
)):
81 logger
.error("No such file: {}".format(self
.recipe_file
))
82 raise TestException("No recipe file found")
89 self
.log
= logger
.getChild(os
.path
.basename(self
.path
))
92 self
.log
= logger
.getChild(os
.path
.basename(self
.recipe_file
))
94 def read_settings(self
):
95 if self
.settings_file
:
96 self
.log
.debug("Going to read all settings from the ini file")
98 self
.config
= configparser
.ConfigParser()
99 self
.config
.read(self
.settings_file
)
100 except BaseException
as e
:
101 self
.log
.error("Failed to parse the config")
104 self
.settings
["name"] = self
.config
.get("GENERAL","name", fallback
="")
105 self
.settings
["description"] = self
.config
.get("GENERAL", "description", fallback
="")
106 self
.settings
["copy_to"] = self
.config
.get("GENERAL", "copy_to", fallback
=None)
107 self
.settings
["copy_from"] = self
.config
.get("GENERAL", "copy_from", fallback
=None)
108 self
.settings
["virtual_environ_path"] = self
.config
.get("VIRTUAL_ENVIRONMENT", "path", fallback
=None)
110 if not self
.settings
["virtual_environ_path"]:
111 self
.log
.error("No path for virtual environment found.")
112 raise TestException("No path for virtual environment found.")
114 self
.settings
["virtual_environ_path"] = os
.path
.normpath(self
.path
+ "/" + self
.settings
["virtual_environ_path"])
116 # Parse copy_from setting
117 if self
.settings
["copy_from"]:
118 self
.log
.debug("Going to parse the copy_from setting.")
119 self
.settings
["copy_from"] = self
.settings
["copy_from"].split(",")
122 for file in self
.settings
["copy_from"]:
124 # If file is empty we do not want to add it to the list
126 # If we get an absolut path we do nothing
127 # If not we add self.path to get an absolut path
128 if not os
.path
.isabs(file):
129 file = os
.path
.normpath(self
.path
+ "/" + file)
131 # We need to check if file is a valid file or dir
132 if not (os
.path
.isdir(file) or os
.path
.isfile(file)):
133 raise TestException("'{}' is not a valid file nor a valid directory".format(file))
135 self
.log
.debug("'{}' will be copied into all images".format(file))
138 self
.settings
["copy_from"] = tmp
142 def virtual_environ_setup(self
):
143 self
.virtual_environ
= virtual_environ
.Virtual_environ(self
.settings
["virtual_environ_path"])
145 self
.virtual_networks
= self
.virtual_environ
.get_networks()
147 self
.virtual_machines
= self
.virtual_environ
.get_machines()
149 def virtual_environ_start(self
):
150 for name
in self
.virtual_environ
.network_names
:
151 self
.virtual_networks
[name
].define()
152 self
.virtual_networks
[name
].start()
154 for name
in self
.virtual_environ
.machine_names
:
155 self
.virtual_machines
[name
].define()
156 self
.virtual_machines
[name
].create_snapshot()
157 # We can only copy files when we know which and to which dir
158 if self
.settings
["copy_from"] and self
.settings
["copy_to"]:
159 self
.virtual_machines
[name
].copy_in(self
.settings
["copy_from"], self
.settings
["copy_to"])
160 self
.virtual_machines
[name
].start()
162 # Time to which all serial output log entries are relativ
163 log_start_time
= time
.time()
165 # Number of chars of the longest machine name
166 longest_machine_name
= self
.virtual_environ
.longest_machine_name
168 self
.log
.info("Try to login on all machines")
169 for name
in self
.virtual_environ
.machine_names
:
170 self
.log
.info("Try to login on {}".format(name
))
171 self
.virtual_machines
[name
].login("{}/test.log".format(self
.log_path
),
172 log_start_time
=log_start_time
,
173 longest_machine_name
=longest_machine_name
)
175 def load_recipe(self
):
176 self
.log
.info("Going to load the recipe")
178 self
.recipe
= recipe
.Recipe(self
.recipe_file
, machines
=self
.virtual_environ
.machine_names
)
179 for line
in self
.recipe
.recipe
:
182 self
.log
.debug("This was the recipe")
183 except BaseException
as e
:
184 self
.log
.error("Failed to load recipe")
187 def run_recipe(self
):
188 for line
in self
.recipe
.recipe
:
189 return_value
= self
.virtual_machines
[line
[0]].cmd(line
[2])
190 self
.log
.debug("Return value is: {}".format(return_value
))
191 if return_value
!= "0" and line
[1] == "":
192 raise TestException("Failed to execute command '{}' on {}, return code: {}".format(line
[2],line
[0], return_value
))
193 elif return_value
== "0" and line
[1] == "!":
194 raise TestException("Succeded to execute command '{}' on {}, return code: {}".format(line
[2],line
[0],return_value
))
196 self
.log
.debug("Command '{}' on {} returned with: {}".format(line
[2],line
[0],return_value
))
198 def virtual_environ_stop(self
):
199 for name
in self
.virtual_environ
.machine_names
:
200 # We just catch exception here to avoid
201 # that we stop the cleanup process if only one command fails
203 self
.virtual_machines
[name
].shutdown()
204 self
.virtual_machines
[name
].revert_snapshot()
205 self
.virtual_machines
[name
].undefine()
206 except BaseException
as e
:
207 self
.log
.exception(e
)
209 for name
in self
.virtual_environ
.network_names
:
211 self
.virtual_networks
[name
].undefine()
212 except BaseException
as e
:
213 self
.log
.exception(e
)