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