blob: 22e26a0b24f2f56bc07e203dea497e3b13be33d6 [file] [log] [blame]
Matteo Scandolo9ce18252017-06-22 10:48:25 -07001from toscaparser.tosca_template import ToscaTemplate
2from default import TOSCA_RECIPES_DIR
Matteo Scandolo485b7132017-06-30 11:46:47 -07003from grpc_client.resources import RESOURCES
4from grpc_client.models_accessor import GRPCModelsAccessor
Matteo Scandolo9ce18252017-06-22 10:48:25 -07005
6class TOSCA_Parser:
7
Matteo Scandolo485b7132017-06-30 11:46:47 -07008 def compute_dependencies(self, template, models_by_name):
9 """
10 NOTE this method is augmenting self.template, isn't there a more explicit way to achieve it?
11 """
12 for nodetemplate in template.nodetemplates:
Matteo Scandolo9ce18252017-06-22 10:48:25 -070013 nodetemplate.dependencies = []
14 nodetemplate.dependencies_names = []
15 for reqs in nodetemplate.requirements:
16 for (k,v) in reqs.items():
17 name = v["node"]
Matteo Scandolo485b7132017-06-30 11:46:47 -070018 if (name in models_by_name):
19 nodetemplate.dependencies.append(models_by_name[name])
Matteo Scandolo9ce18252017-06-22 10:48:25 -070020 nodetemplate.dependencies_names.append(name)
21
22 # go another level deep, as our requirements can have requirements...
23 for sd_req in v.get("requirements",[]):
24 for (sd_req_k, sd_req_v) in sd_req.items():
25 name = sd_req_v["node"]
Matteo Scandolo485b7132017-06-30 11:46:47 -070026 if (name in models_by_name):
27 nodetemplate.dependencies.append(models_by_name[name])
Matteo Scandolo9ce18252017-06-22 10:48:25 -070028 nodetemplate.dependencies_names.append(name)
29
Matteo Scandolo485b7132017-06-30 11:46:47 -070030 @staticmethod
31 def topsort_dependencies(g):
Matteo Scandolo9ce18252017-06-22 10:48:25 -070032
33 # Get set of all nodes, including those without outgoing edges
34 keys = set(g.keys())
35 values = set({})
36 for v in g.values():
37 values = values | set(v.dependencies_names)
38
39 all_nodes = list(keys | values)
40 steps = all_nodes
41
42
43 # Final order
44 order = []
45
46 # DFS stack, not using recursion
47 stack = []
48
49 # Unmarked set
50 unmarked = all_nodes
51
52 # visiting = [] - skip, don't expect 1000s of nodes, |E|/|V| is small
53
54 while unmarked:
55 stack.insert(0, unmarked[0]) # push first unmarked
56
57 while (stack):
58 n = stack[0]
59 add = True
60 try:
61 for m in g[n].dependencies_names:
62 if (m in unmarked):
63 add = False
64 stack.insert(0, m)
65 except KeyError:
66 pass
67 if (add):
68 if (n in steps and n not in order):
69 order.append(n)
70 item = stack.pop(0)
71 try:
72 unmarked.remove(item)
73 except ValueError:
74 pass
75
76 noorder = list(set(steps) - set(order))
77 return order + noorder
78
Matteo Scandolo9ce18252017-06-22 10:48:25 -070079 @staticmethod
80 def populate_model(model, data):
81 for k,v in data.iteritems():
82 setattr(model, k, v)
83 return model
84
85 @staticmethod
Matteo Scandolo9ce18252017-06-22 10:48:25 -070086 def _translate_exception(msg):
87 readable = []
88 for line in msg.splitlines():
89 print line
90 if line.strip().startswith('MissingRequiredFieldError'):
91 readable.append(line)
92
93 if len(readable) > 0:
94 return '/n'.join(readable)
95 else:
96 return msg
97
Matteo Scandolo485b7132017-06-30 11:46:47 -070098 def save_recipe_to_tmp_file(self, recipe):
99 tmp_file = open(self.recipe_file, 'w')
Matteo Scandolo9ce18252017-06-22 10:48:25 -0700100 tmp_file.write(recipe)
101 tmp_file.close()
102
Matteo Scandolo485b7132017-06-30 11:46:47 -0700103 @staticmethod
104 def get_tosca_models_by_name(template):
105 models_by_name = {}
106 for node in template.nodetemplates:
107 models_by_name[node.name] = node
108 return models_by_name
Matteo Scandolo9ce18252017-06-22 10:48:25 -0700109
Matteo Scandolo485b7132017-06-30 11:46:47 -0700110 @staticmethod
111 def get_ordered_models_template(ordered_models_name, templates_by_model_name):
112 ordered_models_templates = []
113 for name in ordered_models_name:
114 if name in templates_by_model_name:
115 ordered_models_templates.append(templates_by_model_name[name])
116 return ordered_models_templates
117
Matteo Scandolo8bbb03a2017-07-05 14:03:33 -0700118 @staticmethod
119 def populate_dependencies(model, requirements, saved_models):
120 for dep in requirements:
121 class_name = dep.keys()[0]
122 related_model = saved_models[dep[class_name]['node']]
123 setattr(model, "%s_id" % class_name, related_model.id)
124 return model
Matteo Scandolo485b7132017-06-30 11:46:47 -0700125
126 def __init__(self, recipe):
127
128 # the template returned by TOSCA-Parser
129 self.template = None
130 # dictionary containing the models in the recipe and their template
131 self.templates_by_model_name = None
132 # list of models ordered by requirements
133 self.ordered_models_name = None
Matteo Scandolo8bbb03a2017-07-05 14:03:33 -0700134 # dictionary containing the saved model
135 self.saved_model_by_name = {}
Matteo Scandolo485b7132017-06-30 11:46:47 -0700136
137 self.ordered_models_template = []
138 self.recipe_file = TOSCA_RECIPES_DIR + '/tmp.yaml'
139
140 try:
141 # [] save the recipe to a tmp file
142 self.save_recipe_to_tmp_file(recipe)
143 # [] parse the recipe with TOSCA Parse
144 self.template = ToscaTemplate(self.recipe_file)
145 # [] get all models in the recipe
146 self.templates_by_model_name = self.get_tosca_models_by_name(self.template)
147 # [] compute requirements
148 self.compute_dependencies(self.template, self.templates_by_model_name)
149 # [] topsort requirements
150 self.ordered_models_name = self.topsort_dependencies(self.templates_by_model_name)
151 # [] topsort templates
152 self.ordered_models_template = self.get_ordered_models_template(self.ordered_models_name, self.templates_by_model_name)
153
154 for recipe in self.ordered_models_template:
155 # get properties from tosca
156 data = recipe.templates[recipe.name]['properties']
157 # [] get model by class name
158 class_name = recipe.type.replace("tosca.nodes.", "")
159 if class_name not in RESOURCES:
160 raise Exception("Nodetemplate %s's type %s is not a known resource" % (recipe.name, class_name))
161 model = GRPCModelsAccessor.get_model_from_classname(class_name, data)
Matteo Scandolo8bbb03a2017-07-05 14:03:33 -0700162 # [] populate model with data[[
Matteo Scandolo485b7132017-06-30 11:46:47 -0700163 model = self.populate_model(model, data)
164 # [] check if the model has requirements
165 # [] if it has populate them
Matteo Scandolo8bbb03a2017-07-05 14:03:33 -0700166 model = self.populate_dependencies(model, recipe.requirements, self.saved_model_by_name)
Matteo Scandolo485b7132017-06-30 11:46:47 -0700167 # [] save or update
168 model.save()
Matteo Scandolo9ce18252017-06-22 10:48:25 -0700169
Matteo Scandolo8bbb03a2017-07-05 14:03:33 -0700170 self.saved_model_by_name[recipe.name] = model
171
Matteo Scandolo9ce18252017-06-22 10:48:25 -0700172 except Exception as e:
173 print e
Matteo Scandolo485b7132017-06-30 11:46:47 -0700174 if e.message:
175 exception_msg = e.message
176 else:
177 exception_msg = str(e)
178 raise Exception(exception_msg)
Matteo Scandolo9ce18252017-06-22 10:48:25 -0700179
180