heat api management and template functions parameters
[bottlenecks.git] / utils / infra_setup / heat / common.py
1 ##############################################################################
2 # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 import os
11 import re
12 import ConfigParser
13 import logging
14 import fileinput
15
16 import consts.files as files
17 import consts.parameters as parameters
18
19 # ------------------------------------------------------
20 # List of common variables
21 # ------------------------------------------------------
22
23 LOG = None
24 CONF_FILE = None
25 DEPLOYMENT_UNIT = None
26 ITERATIONS = None
27
28 BASE_DIR = None
29 TEMPLATE_DIR = None
30 TEMPLATE_NAME = None
31 TEMPLATE_EXTENSION = None
32
33 # ------------------------------------------------------
34 # Initialization and Input 'heat_templates/'validation
35 # ------------------------------------------------------
36
37 def init(api=False):
38     global BASE_DIR
39     # BASE_DIR = os.getcwd()
40     BASE_DIR = os.path.dirname(os.path.abspath(__file__))
41     BASE_DIR = BASE_DIR.replace('/heat', '')
42     BASE_DIR = InputValidation.validate_directory_exist_and_format(
43         BASE_DIR, "Error 000001")
44
45     conf_file_init(api)
46     log_init()
47     general_vars_init(api)
48
49 def conf_file_init(api=False):
50     global CONF_FILE
51     if api:
52         CONF_FILE = ConfigurationFile(files.get_sections_api(),
53                                       '/tmp/bottlenecks.conf')
54     else:
55         CONF_FILE = ConfigurationFile(cf.get_sections(),
56                                       '/tmp/bottlenecks.conf')
57
58
59 def general_vars_init(api=False):
60     global TEMPLATE_EXTENSION
61     global TEMPLATE_NAME
62     global TEMPLATE_DIR
63     global ITERATIONS
64
65     TEMPLATE_EXTENSION = '.yaml'
66
67     # Check Section in Configuration File
68     InputValidation.validate_configuration_file_section(
69             files.GENERAL,
70             "Section " + files.GENERAL +
71             "is not present in configuration file")
72
73     InputValidation.validate_configuration_file_section(
74             files.OPENSTACK,
75             "Section " + files.OPENSTACK +
76             "is not present in configuration file")
77
78     TEMPLATE_DIR = '/tmp/heat_templates/'
79
80     if not api:
81         # Validate template name
82         InputValidation.validate_configuration_file_parameter(
83                 files.GENERAL,
84                 files.TEMPLATE_NAME,
85                 "Parameter " + files.TEMPLATE_NAME +
86                 "is not present in configuration file")
87         TEMPLATE_NAME = CONF_FILE.get_variable(files.GENERAL,
88                                                files.TEMPLATE_NAME)
89         InputValidation.validate_file_exist(
90             TEMPLATE_DIR + TEMPLATE_NAME,
91             "The provided template file does not exist")
92
93     # Validate and assign Iterations
94     if files.ITERATIONS in CONF_FILE.get_variable_list(files.GENERAL):
95         ITERATIONS = int(CONF_FILE.get_variable(files.GENERAL,
96                                                 files.ITERATIONS))
97     else:
98         ITERATIONS = 1
99
100
101 def log_init():
102     global LOG
103     LOG = logging.getLogger()
104     LOG.setLevel(level=logging.DEBUG)
105     log_formatter = logging.Formatter("%(asctime)s --- %(message)s")
106     file_handler = logging.FileHandler("{0}/{1}.log".format("./", "benchmark"))
107     file_handler.setFormatter(log_formatter)
108     file_handler.setLevel(logging.DEBUG)
109     LOG.addHandler(file_handler)
110
111 # ------------------------------------------------------
112 # Configuration file access
113 # ------------------------------------------------------
114
115 class ConfigurationFile:
116     """
117     Used to extract data from the configuration file
118     """
119
120     def __init__(self, sections, config_file='conf.cfg'):
121         """
122         Reads configuration file sections
123
124         :param sections: list of strings representing the sections to be
125                          loaded
126         :param config_file: name of the configuration file (string)
127         :return: None
128         """
129         InputValidation.validate_string(
130             config_file, "The configuration file name must be a string")
131         InputValidation.validate_file_exist(
132             config_file, 'The provided configuration file does not exist')
133         self.config = ConfigParser.ConfigParser()
134         self.config.read(config_file)
135         for section in sections:
136             setattr(
137                 self, section, ConfigurationFile.
138                 _config_section_map(section, self.config))
139
140     @staticmethod
141     def _config_section_map(section, config_file):
142         """
143         Returns a dictionary with the configuration values for the specific
144         section
145
146         :param section: section to be loaded (string)
147         :param config_file: name of the configuration file (string)
148         :return: dict
149         """
150         dict1 = dict()
151         options = config_file.options(section)
152         for option in options:
153             dict1[option] = config_file.get(section, option)
154         return dict1
155
156     def get_variable(self, section, variable_name):
157         """
158         Returns the value correspondent to a variable
159
160         :param section: section to be loaded (string)
161         :param variable_name: name of the variable (string)
162         :return: string
163         """
164         message = "The variable name must be a string"
165         InputValidation.validate_string(variable_name, message)
166         if variable_name in self.get_variable_list(section):
167             sect = getattr(self, section)
168             return sect[variable_name]
169         else:
170             exc_msg = 'Parameter {} is not in the {} section of the ' \
171                       'conf file'.format(variable_name, section)
172             raise ValueError(exc_msg)
173
174     def get_variable_list(self, section):
175         """
176         Returns the list of the available variables in a section
177         :param section: section to be loaded (string)
178         :return: list
179         """
180         try:
181             return getattr(self, section)
182         except:
183             msg = 'Section {}  not found in the configuration file'.\
184                 format(section)
185             raise ValueError(msg)
186
187 # ------------------------------------------------------
188 # Manage files
189 # ------------------------------------------------------
190
191 def get_heat_template_params():
192     """
193     Returns the list of deployment parameters from the configuration file
194     for the heat template
195
196     :return: dict
197     """
198     heat_parameters_list = CONF_FILE.get_variable_list(
199         files.DEPLOYMENT_PARAMETERS)
200     testcase_parameters = dict()
201     for param in heat_parameters_list:
202         testcase_parameters[param] = CONF_FILE.get_variable(
203             files.DEPLOYMENT_PARAMETERS, param)
204     return testcase_parameters
205
206 def get_testcase_params():
207     """
208     Returns the list of testcase parameters from the configuration file
209
210     :return: dict
211     """
212     testcase_parameters = dict()
213     parameters = CONF_FILE.get_variable_list(files.TESTCASE_PARAMETERS)
214     for param in parameters:
215         testcase_parameters[param] = CONF_FILE.get_variable(
216             files.TESTCASE_PARAMETERS, param)
217     return testcase_parameters
218
219 def get_file_first_line(file_name):
220     """
221     Returns the first line of a file
222
223     :param file_name: name of the file to be read (str)
224     :return: str
225     """
226     message = "name of the file must be a string"
227     InputValidation.validate_string(file_name, message)
228     message = 'file {} does not exist'.format(file_name)
229     InputValidation.validate_file_exist(file_name, message)
230     res = open(file_name, 'r')
231     return res.readline()
232
233
234 def replace_in_file(file, text_to_search, text_to_replace):
235     """
236     Replaces a string within a file
237
238     :param file: name of the file (str)
239     :param text_to_search: text to be replaced
240     :param text_to_replace: new text that will replace the previous
241     :return: None
242     """
243     message = 'text to be replaced in the file must be a string'
244     InputValidation.validate_string(text_to_search, message)
245     message = 'text to replace in the file must be a string'
246     InputValidation.validate_string(text_to_replace, message)
247     message = "name of the file must be a string"
248     InputValidation.validate_string(file, message)
249     message = "The file does not exist"
250     InputValidation.validate_file_exist(file, message)
251     for line in fileinput.input(file, inplace=True):
252         print(line.replace(text_to_search, text_to_replace).rstrip())
253
254 # ------------------------------------------------------
255 # Shell interaction
256 # ------------------------------------------------------
257 def run_command(command):
258     LOG.info("Running command: {}".format(command))
259     return os.system(command)
260
261 # ------------------------------------------------------
262 # Expose variables to other modules
263 # ------------------------------------------------------
264
265 def get_base_dir():
266     return BASE_DIR
267
268 def get_template_dir():
269     return TEMPLATE_DIR
270
271 # ------------------------------------------------------
272 # Configuration Variables from Config File
273 # ------------------------------------------------------
274 def get_deployment_configuration_variables_from_conf_file():
275     variables = dict()
276     types = dict()
277     all_variables = CONF_FILE.get_variable_list(files.EXPERIMENT_VNF)
278     for var in all_variables:
279         v = CONF_FILE.get_variable(files.EXPERIMENT_VNF, var)
280         type = re.findall(r'@\w*', v)
281         values = re.findall(r'\"(.+?)\"', v)
282         variables[var] = values
283         try:
284             types[var] = type[0][1:]
285         except IndexError:
286             LOG.debug("No type has been specified for variable " + var)
287     return variables
288
289 # ------------------------------------------------------
290 # benchmarks from Config File
291 # ------------------------------------------------------
292 def get_benchmarks_from_conf_file():
293     requested_benchmarks = list()
294     benchmarks = CONF_FILE.get_variable(files.GENERAL, files.BENCHMARKS).split(', ')
295     for benchmark in benchmarks:
296         requested_benchmarks.append(benchmark)
297     return requested_benchmarks
298
299 class InputValidation(object):
300
301     @staticmethod
302     def validate_string(param, message):
303         if not isinstance(param, str):
304             raise ValueError(message)
305         return True
306
307     @staticmethod
308     def validate_integer(param, message):
309         if not isinstance(param, int):
310             raise ValueError(message)
311         return True
312
313     @staticmethod
314     def validate_dictionary(param, message):
315         if not isinstance(param, dict):
316             raise ValueError(message)
317         return True
318
319     @staticmethod
320     def validate_file_exist(file_name, message):
321         if not os.path.isfile(file_name):
322             raise ValueError(message + ' ' + file_name)
323         return True
324
325     @staticmethod
326     def validate_directory_exist_and_format(directory, message):
327         if not os.path.isdir(directory):
328             raise ValueError(message)
329         if not directory.endswith('/'):
330             return directory + '/'
331         return directory
332
333     @staticmethod
334     def validate_configuration_file_parameter(section, parameter, message):
335         params = CONF_FILE.get_variable_list(section)
336         if parameter not in params:
337             raise ValueError(message)
338         return True
339
340     @staticmethod
341     def validate_configuration_file_section(section, message):
342         if section not in files.get_sections():
343             raise ValueError(message)
344         return True
345
346     @staticmethod
347     def validate_boolean(boolean, message):
348         if isinstance(boolean, bool):
349             return boolean
350         if isinstance(boolean, str):
351             if boolean == 'True':
352                 return True
353             if boolean == 'False':
354                 return False
355         raise ValueError(message)
356
357     @staticmethod
358     def validate_os_credentials(credentials):
359         if not isinstance(credentials, dict):
360             raise ValueError(
361                 'The provided openstack_credentials '
362                 'variable must be in dictionary format')
363
364         credential_keys = ['user', 'password', 'ip_controller', 'heat_url',
365                            'auth_uri', 'project']
366         missing = [
367             credential_key
368             for credential_key in credential_keys
369             if credential_key not in credentials.keys()
370         ]
371         if len(missing) == 0:
372             return True
373         msg = 'OpenStack Credentials Error! ' \
374               'The following parameters are missing: {}'.\
375             format(", ".join(missing))
376         raise ValueError(msg)