Merge "Add unittest framework for Yardstick API"
[yardstick.git] / yardstick / vTC / apexlake / experimental_framework / heat_template_generation.py
1 # Copyright (c) 2015 Intel Research and Development Ireland Ltd.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15
16 """
17 Generation of the heat templates from the base template
18 """
19
20 from __future__ import absolute_import
21 import json
22 import os
23 import shutil
24 from experimental_framework import common
25 from experimental_framework.constants import framework_parameters as fp
26
27
28 class TreeNode:
29     """
30     This class represent the node of the configuration tree.\
31     Each node represents a single configuration value for a single
32     configuration parameter.
33     """
34
35     def __init__(self):
36         self.up = None
37         self.down = []
38         self.variable_name = ''
39         self.variable_value = 0
40
41     def add_child(self, node):
42         """
43         Adds a node as a child for the current node
44         :param node: node to be added as a child (type: TreeNode)
45         :return: None
46         """
47         node.up = self
48         self.down.append(node)
49
50     def get_parent(self):
51         """
52         Returns the parent node of the current one
53         :return type: TreeNode
54         """
55         return self.up
56
57     def get_children(self):
58         """
59         Returns the children of the current node
60         :return type: list of TreeNode
61         """
62         if len(self.down) == 0:
63             # return [self]
64             return []
65         return self.down
66
67     def get_variable_name(self):
68         """
69         Returns the name of the variable correspondent to the current node
70         :return type: str
71         """
72         return self.variable_name
73
74     def get_variable_value(self):
75         """
76         Returns the value of the variable correspondent to the current node
77         :return type: str or int
78         """
79         return self.variable_value
80
81     def set_variable_name(self, name):
82         """
83         Sets the name of the variable for the current node
84         :param name: Name of the variable (type: str)
85         :return None
86         """
87         self.variable_name = name
88
89     def set_variable_value(self, value):
90         """
91         Sets the value of the variable for the current node
92         :param value: value of the variable (type: str)
93         :return None
94         """
95         self.variable_value = value
96
97     def get_path(self):
98         """
99         Returns all the path from the current node to the root of the tree.
100         :return type: list of TreeNode
101         """
102         ret_val = []
103         if not self.up:
104             ret_val.append(self)
105             return ret_val
106         for node in self.up.get_path():
107             ret_val.append(node)
108         ret_val.append(self)
109         return ret_val
110
111     def __str__(self):
112         return str(self.variable_name) + " --> " + str(self.variable_value)
113
114     def __repr__(self):
115         return str(self.variable_name) + " = " + str(self.variable_value)
116
117     @staticmethod
118     def _get_leaves(node, leaves):
119         """
120         Returns all the leaves of a tree.
121         It changes the "leaves" list.
122         :param node: root of the tree (type: TreeNode)
123         :param leaves: partial list of leaves (type: list of TreeNode)
124         :return type: None
125         """
126         children = node.get_children()
127         if len(children) == 0:
128             leaves.append(node)
129             return
130         for child in children:
131             TreeNode._get_leaves(child, leaves)
132
133     @staticmethod
134     def get_leaves(node):
135         """
136         Returns all the leaves of a tree.
137         :param node: root of the tree (TreeNode)
138         :return type: list
139         """
140         leaves = list()
141         TreeNode._get_leaves(node, leaves)
142         return leaves
143
144
145 template_name = fp.EXPERIMENT_TEMPLATE_NAME
146
147
148 def generates_templates(base_heat_template, deployment_configuration):
149     """
150     Generates the heat templates for the experiments
151     :return: None
152     """
153     # Load useful parameters from file
154     template_dir = common.get_template_dir()
155     template_file_extension = fp.TEMPLATE_FILE_EXTENSION
156     template_base_name = base_heat_template
157
158     variables = deployment_configuration
159
160     # Delete the templates eventually generated in previous running of the
161     # framework
162     common.LOG.info("Removing the heat templates previously generated")
163     command = "rm {}{}_*".format(template_dir, template_name)
164     os.system(command)
165
166     # Creation of the tree with all the new configurations
167     common.LOG.info("Creation of the tree with all the new configurations")
168     tree = TreeNode()
169     for variable in variables:
170         leaves = TreeNode.get_leaves(tree)
171         common.LOG.debug("LEAVES: " + str(leaves))
172         common.LOG.debug("VALUES: " + str(variables[variable]))
173
174         for value in variables[variable]:
175             for leaf in leaves:
176                 new_node = TreeNode()
177                 new_node.set_variable_name(variable)
178                 new_node.set_variable_value(value)
179                 leaf.add_child(new_node)
180
181     common.LOG.debug("CONFIGURATION TREE: " + str(tree))
182
183     common.LOG.info("Heat Template and metadata file creation")
184     leaves = TreeNode.get_leaves(tree)
185     counter = 1
186     for leaf in leaves:
187         heat_template_vars = leaf.get_path()
188         if os.path.isabs(template_base_name):
189             base_template = template_base_name
190         else:
191             base_template = template_dir + template_base_name
192         new_template = template_dir + template_name
193         new_template += "_" + str(counter) + template_file_extension
194         shutil.copy(base_template, new_template)
195
196         metadata = dict()
197         for var in heat_template_vars:
198             if var.get_variable_name():
199                 common.replace_in_file(new_template, "#" +
200                                        var.get_variable_name(),
201                                        var.get_variable_value())
202                 metadata[var.get_variable_name()] = var.get_variable_value()
203
204         # Save the metadata on a JSON file
205         with open(new_template + ".json", 'w') as outfile:
206             json.dump(metadata, outfile)
207
208         common.LOG.debug("Heat Templates and Metadata file " + str(counter) +
209                          " created")
210         counter += 1
211
212     # Creation of the template files
213     common.LOG.info(str(counter - 1) + " Heat Templates and Metadata files "
214                                        "created")
215
216
217 def get_all_heat_templates(template_dir, template_file_extension):
218     """
219     Loads and returns all the generated heat templates
220     :param template_dir: directory to search in (type: str)
221     :param template_file_extension: extension of the file for templates
222             (type: str)
223     :return: type: list
224     """
225     template_files = list()
226     for dirname, dirnames, filenames in os.walk(template_dir):
227         for filename in filenames:
228             if template_file_extension in filename and \
229                     filename.endswith(template_file_extension) and \
230                     template_name in filename:
231                 template_files.append(filename)
232     template_files.sort()
233     return template_files