blob: 7eb3381d2ff85500b8e00f863d35a7d048ac1dcd [file] [log] [blame]
Matteo Scandolo9ce18252017-06-22 10:48:25 -07001from toscaparser.tosca_template import ToscaTemplate
2from default import TOSCA_RECIPES_DIR
3from resources import RESOURCES
4from grpc._channel import _Rendezvous
5
6class TOSCA_Parser:
7
8 def compute_dependencies(self):
9 nodetemplates_by_name = {}
10 for nodetemplate in self.template.nodetemplates:
11 nodetemplates_by_name[nodetemplate.name] = nodetemplate
12
13 self.nodetemplates_by_name = nodetemplates_by_name
14
15 for nodetemplate in self.template.nodetemplates:
16 nodetemplate.dependencies = []
17 nodetemplate.dependencies_names = []
18 for reqs in nodetemplate.requirements:
19 for (k,v) in reqs.items():
20 name = v["node"]
21 if (name in nodetemplates_by_name):
22 nodetemplate.dependencies.append(nodetemplates_by_name[name])
23 nodetemplate.dependencies_names.append(name)
24
25 # go another level deep, as our requirements can have requirements...
26 for sd_req in v.get("requirements",[]):
27 for (sd_req_k, sd_req_v) in sd_req.items():
28 name = sd_req_v["node"]
29 if (name in nodetemplates_by_name):
30 nodetemplate.dependencies.append(nodetemplates_by_name[name])
31 nodetemplate.dependencies_names.append(name)
32
33 def topsort_dependencies(self):
34 # stolen from observer
35 g = self.nodetemplates_by_name
36
37 # Get set of all nodes, including those without outgoing edges
38 keys = set(g.keys())
39 values = set({})
40 for v in g.values():
41 values = values | set(v.dependencies_names)
42
43 all_nodes = list(keys | values)
44 steps = all_nodes
45
46
47 # Final order
48 order = []
49
50 # DFS stack, not using recursion
51 stack = []
52
53 # Unmarked set
54 unmarked = all_nodes
55
56 # visiting = [] - skip, don't expect 1000s of nodes, |E|/|V| is small
57
58 while unmarked:
59 stack.insert(0, unmarked[0]) # push first unmarked
60
61 while (stack):
62 n = stack[0]
63 add = True
64 try:
65 for m in g[n].dependencies_names:
66 if (m in unmarked):
67 add = False
68 stack.insert(0, m)
69 except KeyError:
70 pass
71 if (add):
72 if (n in steps and n not in order):
73 order.append(n)
74 item = stack.pop(0)
75 try:
76 unmarked.remove(item)
77 except ValueError:
78 pass
79
80 noorder = list(set(steps) - set(order))
81 return order + noorder
82
83 def execute(self):
84 for nodetemplate in self.ordered_nodetemplates:
85 self.execute_nodetemplate(nodetemplate)
86
87 def execute_nodetemplate(self, nodetemplate):
88 node_class = nodetemplate.type.replace("tosca.nodes.", "")
89 if node_class not in RESOURCES:
90 raise Exception("Nodetemplate %s's type %s is not a known resource" % (nodetemplate.name, node_class))
91
92 # find the class corresponding to a node
93 cls = RESOURCES[node_class]
94
95
96 # read properties from TOSCA
97 data = nodetemplate.templates[nodetemplate.name]['properties']
98
99 TOSCA_Parser.creat_or_update(cls, data)
100
101 @staticmethod
102 def populate_model(model, data):
103 for k,v in data.iteritems():
104 setattr(model, k, v)
105 return model
106
107 @staticmethod
108 def creat_or_update(cls, data):
109
110 # default case
111 if data.get('name'):
112 used_key = 'name'
113 else:
114 used_key = data.keys()[0]
115
116 models = cls.objects.filter(**{used_key: data[used_key]})
117
118 if len(models) == 1:
119 print "[XOS-Tosca] Model %s already exist, updating..." % data[used_key]
120 model = models[0]
121 elif len(models) == 0:
122 model = cls.objects.new()
123 print "[XOS-Tosca] Model %s is new, creating..." % data[used_key]
124 else:
125 raise Exception("[XOS-Tosca] Model %s has multiple instances, I can't handle it" % data[used_key])
126
127 model = TOSCA_Parser.populate_model(model, data)
128 model.save()
129
130
131 @staticmethod
132 def _translate_exception(msg):
133 readable = []
134 for line in msg.splitlines():
135 print line
136 if line.strip().startswith('MissingRequiredFieldError'):
137 readable.append(line)
138
139 if len(readable) > 0:
140 return '/n'.join(readable)
141 else:
142 return msg
143
144 def __init__(self, recipe):
145
146 self.template = None
147 self.nodetemplates_by_name = None
148 self.ordered_nodetemplates = []
149 self.ordered_names = None
150
151 tmp_file_path = TOSCA_RECIPES_DIR + '/tmp.yaml'
152
153 # write the receive recipe in a tmp file
154 tmp_file = open(tmp_file_path, 'w')
155 tmp_file.write(recipe)
156 tmp_file.close()
157
158 try:
159 self.template = ToscaTemplate(tmp_file_path)
160 self.compute_dependencies()
161 self.ordered_names = self.topsort_dependencies()
162 for name in self.ordered_names:
163 if name in self.nodetemplates_by_name:
164 self.ordered_nodetemplates.append(self.nodetemplates_by_name[name])
165
166 self.execute()
167
168 except Exception as e:
169 print e
170 import sys, os
171 exc_type, exc_obj, exc_tb = sys.exc_info()
172 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
173 print(exc_type, fname, exc_tb.tb_lineno)
174 raise Exception(self._translate_exception(e.message))
175
176