1 # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 # not use this file except in compliance with the License. You may obtain
3 # a copy of the License at
5 # http://www.apache.org/licenses/LICENSE-2.0
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 # License for the specific language governing permissions and limitations
21 from six.moves.urllib.parse import urlparse
24 from toscaparser.utils.gettextutils import _
25 import toscaparser.utils.yamlparser
27 YAML_ORDER_PARSER = toscaparser.utils.yamlparser.simple_ordered_parse
28 log = logging.getLogger('heat-translator')
30 # Required environment variables to create openstackclient object.
31 ENV_VARIABLES = ['OS_AUTH_URL', 'OS_PASSWORD', 'OS_USERNAME', 'OS_TENANT_NAME']
34 class MemoryUnit(object):
36 UNIT_SIZE_DEFAULT = 'B'
37 UNIT_SIZE_DICT = {'B': 1, 'kB': 1000, 'KiB': 1024, 'MB': 1000000,
38 'MiB': 1048576, 'GB': 1000000000,
39 'GiB': 1073741824, 'TB': 1000000000000,
43 def convert_unit_size_to_num(size, unit=None):
44 """Convert given size to a number representing given unit.
46 If unit is None, convert to a number representing UNIT_SIZE_DEFAULT
47 :param size: unit size e.g. 1 TB
48 :param unit: unit to be converted to e.g GB
49 :return: converted number e.g. 1000 for 1 TB size and unit GB
52 unit = MemoryUnit.validate_unit(unit)
54 unit = MemoryUnit.UNIT_SIZE_DEFAULT
55 log.info(_('A memory unit is not provided for size; using the '
56 'default unit %(default)s.') % {'default': 'B'})
57 regex = re.compile('(\d*)\s*(\w*)')
58 result = regex.match(str(size)).groups()
60 unit_size = MemoryUnit.validate_unit(result[1])
61 converted = int(str_to_num(result[0])
62 * MemoryUnit.UNIT_SIZE_DICT[unit_size]
63 * math.pow(MemoryUnit.UNIT_SIZE_DICT
65 log.info(_('Given size %(size)s is converted to %(num)s '
66 '%(unit)s.') % {'size': size,
67 'num': converted, 'unit': unit})
69 converted = (str_to_num(result[0]))
73 def validate_unit(unit):
74 if unit in MemoryUnit.UNIT_SIZE_DICT.keys():
77 for key in MemoryUnit.UNIT_SIZE_DICT.keys():
78 if key.upper() == unit.upper():
81 msg = _('Provided unit "{0}" is not valid. The valid units are'
82 ' {1}').format(unit, MemoryUnit.UNIT_SIZE_DICT.keys())
87 class CompareUtils(object):
89 MISMATCH_VALUE1_LABEL = "<Expected>"
90 MISMATCH_VALUE2_LABEL = "<Provided>"
91 ORDERLESS_LIST_KEYS = ['allowed_values', 'depends_on']
94 def compare_dicts(dict1, dict2):
95 """Return False if not equal, True if both are equal."""
97 if dict1 is None and dict2 is None:
99 if dict1 is None or dict2 is None:
103 for dict1_item, dict2_item in zip(dict1.items(), dict2.items()):
104 if dict1_item != dict2_item:
105 msg = (_("%(label1)s: %(item1)s \n is not equal to \n:"
106 "%(label2)s: %(item2)s")
107 % {'label1': CompareUtils.MISMATCH_VALUE2_LABEL,
109 'label2': CompareUtils.MISMATCH_VALUE1_LABEL,
110 'item2': dict2_item})
117 def compare_hot_yamls(generated_yaml, expected_yaml):
118 hot_translated_dict = YAML_ORDER_PARSER(generated_yaml)
119 hot_expected_dict = YAML_ORDER_PARSER(expected_yaml)
120 return CompareUtils.compare_dicts(hot_translated_dict,
125 '''Canonicalize list items in the dictionary for ease of comparison.
127 For properties whose value is a list in which the order does not
128 matter, some pre-processing is required to bring those lists into a
129 canonical format. We use sorting just to make sure such differences
130 in ordering would not cause to a mismatch.
133 if type(dic) is not dict:
137 for key in dic.keys():
139 if type(value) is dict:
140 reordered[key] = CompareUtils.reorder(value)
141 elif type(value) is list \
142 and key in CompareUtils.ORDERLESS_LIST_KEYS:
143 reordered[key] = sorted(value)
145 reordered[key] = value
149 def diff_dicts(dict1, dict2, reorder=True):
150 '''Compares two dictionaries and returns their differences.
152 Returns a dictionary of mismatches between the two dictionaries.
153 An empty dictionary is returned if two dictionaries are equivalent.
154 The reorder parameter indicates whether reordering is required
155 before comparison or not.
159 dict1 = CompareUtils.reorder(dict1)
160 dict2 = CompareUtils.reorder(dict2)
162 if dict1 is None and dict2 is None:
164 if dict1 is None or dict2 is None:
165 return {CompareUtils.MISMATCH_VALUE1_LABEL: dict1,
166 CompareUtils.MISMATCH_VALUE2_LABEL: dict2}
169 keys1 = set(dict1.keys())
170 keys2 = set(dict2.keys())
171 for key in keys1.union(keys2):
172 if key in keys1 and key not in keys2:
173 diff[key] = {CompareUtils.MISMATCH_VALUE1_LABEL: dict1[key],
174 CompareUtils.MISMATCH_VALUE2_LABEL: None}
175 elif key not in keys1 and key in keys2:
176 diff[key] = {CompareUtils.MISMATCH_VALUE1_LABEL: None,
177 CompareUtils.MISMATCH_VALUE2_LABEL: dict2[key]}
182 if type(val1) is dict and type(val2) is dict:
183 diff[key] = CompareUtils.diff_dicts(val1, val2, False)
185 diff[key] = {CompareUtils.MISMATCH_VALUE1_LABEL: val1,
186 CompareUtils.MISMATCH_VALUE2_LABEL: val2}
190 class YamlUtils(object):
193 def get_dict(yaml_file):
194 '''Returns the dictionary representation of the given YAML spec.'''
196 return yaml.load(open(yaml_file))
201 def compare_yamls(yaml1_file, yaml2_file):
202 '''Returns true if two dictionaries are equivalent, false otherwise.'''
203 dict1 = YamlUtils.get_dict(yaml1_file)
204 dict2 = YamlUtils.get_dict(yaml2_file)
205 return CompareUtils.compare_dicts(dict1, dict2)
208 def compare_yaml_dict(yaml_file, dic):
209 '''Returns true if yaml matches the dictionary, false otherwise.'''
210 return CompareUtils.compare_dicts(YamlUtils.get_dict(yaml_file), dic)
213 class TranslationUtils(object):
216 def compare_tosca_translation_with_hot(tosca_file, hot_file, params):
217 '''Verify tosca translation against the given hot specification.
220 tosca_file: relative local path or URL to the tosca input file
221 hot_file: relative path to expected hot output
222 params: dictionary of parameter name value pairs
224 Returns as a dictionary the difference between the HOT translation
225 of the given tosca_file and the given hot_file.
228 from toscaparser.tosca_template import ToscaTemplate
229 from translator.hot.tosca_translator import TOSCATranslator
231 tosca_tpl = os.path.normpath(os.path.join(
232 os.path.dirname(os.path.abspath(__file__)), tosca_file))
233 a_file = os.path.isfile(tosca_tpl)
235 tosca_tpl = tosca_file
237 expected_hot_tpl = os.path.join(
238 os.path.dirname(os.path.abspath(__file__)), hot_file)
240 tosca = ToscaTemplate(tosca_tpl, params, a_file)
241 translate = TOSCATranslator(tosca, params)
243 output = translate.translate()
244 output_dict = toscaparser.utils.yamlparser.simple_parse(output)
245 expected_output_dict = YamlUtils.get_dict(expected_hot_tpl)
246 return CompareUtils.diff_dicts(output_dict, expected_output_dict)
249 class UrlUtils(object):
252 def validate_url(path):
253 """Validates whether the given path is a URL or not.
255 If the given path includes a scheme (http, https, ftp, ...) and a net
256 location (a domain name such as www.github.com) it is validated as a
259 parsed = urlparse(path)
260 return bool(parsed.scheme) and bool(parsed.netloc)
263 def str_to_num(value):
264 """Convert a string representation of a number into a numeric type."""
265 if isinstance(value, numbers.Number):
273 def check_for_env_variables():
274 return set(ENV_VARIABLES) < set(os.environ.keys())
277 def get_ks_access_dict():
278 tenant_name = os.getenv('OS_TENANT_NAME')
279 username = os.getenv('OS_USERNAME')
280 password = os.getenv('OS_PASSWORD')
281 auth_url = os.getenv('OS_AUTH_URL')
285 "tenantName": tenant_name,
286 "passwordCredentials": {
287 "username": username,
292 headers = {'Content-Type': 'application/json'}
294 keystone_response = requests.post(auth_url + '/tokens',
295 data=json.dumps(auth_dict),
297 if keystone_response.status_code != 200:
299 return json.loads(keystone_response.content)
304 def get_url_for(access_dict, service_type):
305 if access_dict is None:
307 service_catalog = access_dict['access']['serviceCatalog']
309 for service in service_catalog:
310 if service['type'] == service_type:
311 service_url = service['endpoints'][0]['publicURL']
316 def get_token_id(access_dict):
317 if access_dict is None:
319 return access_dict['access']['token']['id']