Move tests and virtual environment example into examples subfolder
[nitsi.git] / src / nitsi / recipe.py
CommitLineData
3a4eb2c7
JS
1#!/usr/bin/python3
2
3import os
4
1ed8ca9f
JS
5import logging
6
7logger = logging.getLogger("nitsi.recipe")
8
3a4eb2c7
JS
9
10
11class RecipeExeption(Exception):
12 pass
13
14
15
16# Should read the test, check if the syntax are valid
17# and return tuples with the ( host, command ) structure
18class recipe():
19 def __init__(self, path, circle=[]):
3a4eb2c7 20 self.recipe_file = path
518441de
JS
21 try:
22 self.path = os.path.dirname(self.recipe_file)
23 self.name = os.path.basename(self.path)
24 except BaseException as e:
25 logger.error("Failed to get the name of the test to this recipe")
26 raise e
27
28 self.log = logger.getChild(self.name)
3a4eb2c7
JS
29 self.log.debug("Path of recipe is: {}".format(self.recipe_file))
30 self._recipe = None
31 self._machines = None
32
33 self.in_recursion = True
34 if len(circle) == 0:
35 self.in_recursion = False
36
37 self.circle = circle
2fa4467d 38 self.log.debug("Recipes we have already included: {}".format(self.circle))
3a4eb2c7
JS
39
40 if not os.path.isfile(self.recipe_file):
faff2d5c
JS
41 self.log.error("{} is not a file".format(self.recipe_file))
42 raise RecipeExeption
3a4eb2c7
JS
43
44 try:
45 with open(self.recipe_file) as fobj:
46 self.raw_recipe = fobj.readlines()
47 except FileNotFoundError as error:
48 self.log.error("No such file: {}".format(vm_xml_file))
49
50 @property
51 def recipe(self):
52 if not self._recipe:
53 self.parse()
54
55 return self._recipe
56
57 @property
58 def machines(self):
59 if not self._machines:
60 self._machines = []
61 for line in self._recipe:
62 if line[0] != "all" and line[0] not in self._machines:
63 self._machines.append(line[0])
64
65 return self._machines
66
67 def parse(self):
68 self._recipe = []
69 i = 1
70 for line in self.raw_recipe:
2e8d0473 71 raw_line = line.split(":", 1)
3a4eb2c7
JS
72 if len(raw_line) < 2:
73 self.log.error("Error parsing the recipe in line {}".format(i))
74 raise RecipeExeption
75 cmd = raw_line[1].strip()
76 raw_line = raw_line[0].strip().split(" ")
77 if len(raw_line) == 0:
78 self.log.error("Failed to parse the recipe in line {}".format(i))
79 raise RecipeExeption
80
81 if raw_line[0].strip() == "":
82 self.log.error("Failed to parse the recipe in line {}".format(i))
83 raise RecipeExeption
84
85 machine = raw_line[0].strip()
86
87 if len(raw_line) == 2:
88 extra = raw_line[1].strip()
89 else:
90 extra = ""
91
92 # We could get a machine here or a include statement
93 if machine == "include":
94 path = cmd.strip()
95 path = os.path.normpath(self.path + "/" + path)
96 path = path + "/recipe"
97 if path in self.circle:
98 self.log.error("Detect import loop!")
99 raise RecipeExeption
100 self.circle.append(path)
101 recipe_to_include = recipe(path, circle=self.circle)
102
103 if machine == "include":
104 self._recipe.extend(recipe_to_include.recipe)
105 else:
106 # Support also something like 'alice,bob: echo'
107 machines = machine.split(",")
108 for machine in machines:
109 self._recipe.append((machine.strip(), extra.strip(), cmd.strip()))
110 i = i + 1
111
112 if not self.in_recursion:
113 tmp_recipe = []
114 for line in self._recipe:
115 if line[0] != "all":
116 tmp_recipe.append(line)
117 else:
118 for machine in self.machines:
119 tmp_recipe.append((machine.strip(), line[1], line[2]))
120
121 self._recipe = tmp_recipe