X-Git-Url: http://git.ipfire.org/?p=nitsi.git;a=blobdiff_plain;f=test.py;h=2b26e6815cfe09440eb36127715f0f6984e16bb7;hp=53f0052fa95d321647fe1e9d9cdd669bef625945;hb=14cd493f0bb7cfffe753b0575f1a4ac4a650a98e;hpb=e54f9c23e2579d8142c06e1b054df01e550d31fe diff --git a/test.py b/test.py index 53f0052..2b26e68 100755 --- a/test.py +++ b/test.py @@ -14,6 +14,8 @@ import os import configparser +from disk import disk + class log(): def __init__(self, log_level): self.log_level = log_level @@ -74,6 +76,7 @@ class vm(): self.log.error("No such file: {}".format(self.image)) self.root_uid = root_uid + self.disk = disk(image) self.username = username self.password = password @@ -150,6 +153,15 @@ class vm(): def cmd(self, cmd): return self.serial_con.command(cmd) + def copy_in(self, fr, to): + try: + self.disk.mount(self.root_uid, "/") + self.disk.copy_in(fr, to) + except BaseException as e: + self.log.error(e) + finally: + self.disk.umount("/") + self.disk.close() class connection(): def __init__(self, device, username=None): @@ -274,17 +286,33 @@ class connection(): print("We are not logged in") return False + def print_lines_in_buffer(self): + while True: + self.log.debug("Fill buffer ...") + self.peek(len(self.buffer) + self.in_waiting) + self.log.debug("Current buffer length: {}".format(len(self.buffer))) + if self.line_in_buffer() == True: + while self.line_in_buffer() == True: + data = self.readline() + self.log_console_line(data.decode()) + else: + self.log.debug("We have printed all lines in the buffer") + break + def login(self, password): if self.username == None: self.log.error("Username cannot be blank") return False + self.print_lines_in_buffer() + # Hit enter to see what we get self.con.write(b'\n') # We get two new lines \r\n ? data = self.readline() self.log_console_line(data.decode()) + self.print_lines_in_buffer() if self.back_at_prompt(): self.log.debug("We are already logged in.") @@ -292,11 +320,6 @@ class connection(): # Read all line till we get login: while 1: - data = self.peek() - if not data.decode() == "l": - self.log.debug("We get no l at the start") - self.log_console_line(self.readline().decode()) - # We need to use self.in_waiting because with self.con.in_waiting we get # not the complete string size = len(self.buffer) + self.in_waiting @@ -344,7 +367,7 @@ class connection(): self.con.flush() def command(self, command): - self.write("{}\n".format(command)) + self.write("{}; echo \"END: $?\"\n".format(command)) # We need to read out the prompt for this command first # If we do not do this we will break the loop immediately @@ -356,6 +379,13 @@ class connection(): data = self.readline() self.log_console_line(data.decode()) + # We saved our exit code in data (the last line) + self.log.debug(data.decode()) + data = data.decode().replace("END: ", "") + self.log.debug(data) + self.log.debug(data.strip()) + return data.strip() + # A class which define and undefine a virtual network based on an xml file class network(): @@ -390,10 +420,21 @@ class RecipeExeption(Exception): # Should read the test, check if the syntax are valid # and return tuples with the ( host, command ) structure class recipe(): - def __init__(self, path): + def __init__(self, path, circle=[]): self.log = log(4) self.recipe_file = path + self.path = os.path.dirname(self.recipe_file) + self.log.debug("Path of recipe is: {}".format(self.recipe_file)) self._recipe = None + self._machines = None + + self.in_recursion = True + if len(circle) == 0: + self.in_recursion = False + + self.circle = circle + self.log.debug(circle) + self.log.debug(self.circle) if not os.path.isfile(self.recipe_file): self.log.error("No such file: {}".format(self.recipe_file)) @@ -411,6 +452,16 @@ class recipe(): return self._recipe + @property + def machines(self): + if not self._machines: + self._machines = [] + for line in self._recipe: + if line[0] != "all" and line[0] not in self._machines: + self._machines.append(line[0]) + + return self._machines + def parse(self): self._recipe = [] i = 1 @@ -419,24 +470,55 @@ class recipe(): if len(raw_line) < 2: self.log.error("Error parsing the recipe in line {}".format(i)) raise RecipeExeption - cmd = raw_line[1] + cmd = raw_line[1].strip() raw_line = raw_line[0].strip().split(" ") if len(raw_line) == 0: self.log.error("Failed to parse the recipe in line {}".format(i)) raise RecipeExeption - elif len(raw_line) == 1: - if raw_line[0] == "": + + if raw_line[0].strip() == "": self.log.error("Failed to parse the recipe in line {}".format(i)) raise RecipeExeption - machine = raw_line[0] + + machine = raw_line[0].strip() + + if len(raw_line) == 2: + extra = raw_line[1].strip() + else: extra = "" - elif len(raw_line) == 2: - machine = raw_line[0] - extra = raw_line[1] - self._recipe.append((machine.strip(), extra.strip(), cmd.strip())) + # We could get a machine here or a include statement + if machine == "include": + path = cmd.strip() + path = os.path.normpath(self.path + "/" + path) + path = path + "/recipe" + if path in self.circle: + self.log.error("Detect import loop!") + raise RecipeExeption + self.circle.append(path) + recipe_to_include = recipe(path, circle=self.circle) + + if machine == "include": + self._recipe.extend(recipe_to_include.recipe) + else: + # Support also something like 'alice,bob: echo' + machines = machine.split(",") + for machine in machines: + self._recipe.append((machine.strip(), extra.strip(), cmd.strip())) i = i + 1 + if not self.in_recursion: + tmp_recipe = [] + for line in self._recipe: + if line[0] != "all": + tmp_recipe.append(line) + else: + for machine in self.machines: + tmp_recipe.append((machine.strip(), line[1], line[2])) + + self._recipe = tmp_recipe + + class test(): def __init__(self, path): @@ -461,6 +543,17 @@ class test(): self.config.read(self.settings_file) self.name = self.config["DEFAULT"]["Name"] self.description = self.config["DEFAULT"]["Description"] + self.copy_to = self.config["DEFAULT"]["Copy_to"] + self.copy_from = self.config["DEFAULT"]["Copy_from"] + self.copy_from = self.copy_from.split(",") + + tmp = [] + for file in self.copy_from: + file = file.strip() + file = os.path.normpath(self.path + "/" + file) + tmp.append(file) + + self.copy_from = tmp self.virtual_environ_name = self.config["VIRTUAL_ENVIRONMENT"]["Name"] self.virtual_environ_path = self.config["VIRTUAL_ENVIRONMENT"]["Path"] @@ -481,6 +574,7 @@ class test(): for name in self.virtual_environ.machine_names: self.virtual_machines[name].define() self.virtual_machines[name].create_snapshot() + self.virtual_machines[name].copy_in(self.copy_from, self.copy_to) self.virtual_machines[name].start() self.log.debug("Try to login on all machines") @@ -497,12 +591,15 @@ class test(): def run_recipe(self): for line in self.recipe.recipe: return_value = self.virtual_machines[line[0]].cmd(line[2]) - if not return_value and line[1] == "": - self.log.error("Failed to execute command '{}' on {}".format(line[2],line[0])) + self.log.debug("Return value is: {}".format(return_value)) + if return_value != "0" and line[1] == "": + self.log.error("Failed to execute command '{}' on {}, return code: {}".format(line[2],line[0], return_value)) return False - elif return_value == True and line[1] == "!": - self.log.error("Succeded to execute command '{}' on {}".format(line[2],line[0])) + elif return_value == "0" and line[1] == "!": + self.log.error("Succeded to execute command '{}' on {}, return code: {}".format(line[2],line[0],return_value)) return False + else: + self.log.debug("Command '{}' on {} returned with: {}".format(line[2],line[0],return_value)) def virtual_environ_stop(self): for name in self.virtual_environ.machine_names: @@ -591,6 +688,11 @@ if __name__ == "__main__": currenttest.read_settings() currenttest.virtual_environ_setup() currenttest.load_recipe() - currenttest.virtual_environ_start() - currenttest.run_recipe() - currenttest.virtual_environ_stop() \ No newline at end of file + try: + currenttest.virtual_environ_start() + currenttest.run_recipe() + except BaseException as e: + print(e) + finally: + currenttest.virtual_environ_stop() +