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