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
22 from six.moves.urllib.parse import urlparse
25 from toscaparser.utils.gettextutils import _
26 import toscaparser.utils.yamlparser
28 YAML_ORDER_PARSER = toscaparser.utils.yamlparser.simple_ordered_parse
29 log = logging.getLogger('heat-translator')
31 # Required environment variables to create openstackclient object.
32 ENV_VARIABLES = ['OS_AUTH_URL', 'OS_PASSWORD', 'OS_USERNAME', 'OS_TENANT_NAME']
35 class MemoryUnit(object):
37 UNIT_SIZE_DEFAULT = 'B'
38 UNIT_SIZE_DICT = {'B': 1, 'kB': 1000, 'KiB': 1024, 'MB': 1000000,
39 'MiB': 1048576, 'GB': 1000000000,
40 'GiB': 1073741824, 'TB': 1000000000000,
44 def convert_unit_size_to_num(size, unit=None):
45 """Convert given size to a number representing given unit.
47 If unit is None, convert to a number representing UNIT_SIZE_DEFAULT
48 :param size: unit size e.g. 1 TB
49 :param unit: unit to be converted to e.g GB
50 :return: converted number e.g. 1000 for 1 TB size and unit GB
53 unit = MemoryUnit.validate_unit(unit)
55 unit = MemoryUnit.UNIT_SIZE_DEFAULT
56 log.info(_('A memory unit is not provided for size; using the '
57 'default unit %(default)s.') % {'default': 'B'})
58 regex = re.compile('(\d*)\s*(\w*)')
59 result = regex.match(str(size)).groups()
61 unit_size = MemoryUnit.validate_unit(result[1])
62 converted = int(str_to_num(result[0])
63 * MemoryUnit.UNIT_SIZE_DICT[unit_size]
64 * math.pow(MemoryUnit.UNIT_SIZE_DICT
66 log.info(_('Given size %(size)s is converted to %(num)s '
67 '%(unit)s.') % {'size': size,
68 'num': converted, 'unit': unit})
70 converted = (str_to_num(result[0]))
74 def validate_unit(unit):
75 if unit in MemoryUnit.UNIT_SIZE_DICT.keys():
78 for key in MemoryUnit.UNIT_SIZE_DICT.keys():
79 if key.upper() == unit.upper():
82 msg = _('Provided unit "{0}" is not valid. The valid units are'
83 ' {1}').format(unit, MemoryUnit.UNIT_SIZE_DICT.keys())
88 class CompareUtils(object):
90 MISMATCH_VALUE1_LABEL = "<Expected>"
91 MISMATCH_VALUE2_LABEL = "<Provided>"
92 ORDERLESS_LIST_KEYS = ['allowed_values', 'depends_on']
95 def compare_dicts(dict1, dict2):
96 """Return False if not equal, True if both are equal."""
98 if dict1 is None and dict2 is None:
100 if dict1 is None or dict2 is None:
104 for dict1_item, dict2_item in zip(dict1.items(), dict2.items()):
105 if dict1_item != dict2_item:
106 msg = (_("%(label1)s: %(item1)s \n is not equal to \n:"
107 "%(label2)s: %(item2)s")
108 % {'label1': CompareUtils.MISMATCH_VALUE2_LABEL,
110 'label2': CompareUtils.MISMATCH_VALUE1_LABEL,
111 'item2': dict2_item})
118 def compare_hot_yamls(generated_yaml, expected_yaml):
119 hot_translated_dict = YAML_ORDER_PARSER(generated_yaml)
120 hot_expected_dict = YAML_ORDER_PARSER(expected_yaml)
121 return CompareUtils.compare_dicts(hot_translated_dict,
126 '''Canonicalize list items in the dictionary for ease of comparison.
128 For properties whose value is a list in which the order does not
129 matter, some pre-processing is required to bring those lists into a
130 canonical format. We use sorting just to make sure such differences
131 in ordering would not cause to a mismatch.
134 if type(dic) is not dict:
138 for key in dic.keys():
140 if type(value) is dict:
141 reordered[key] = CompareUtils.reorder(value)
142 elif type(value) is list \
143 and key in CompareUtils.ORDERLESS_LIST_KEYS:
144 reordered[key] = sorted(value)
146 reordered[key] = value
150 def diff_dicts(dict1, dict2, reorder=True):
151 '''Compares two dictionaries and returns their differences.
153 Returns a dictionary of mismatches between the two dictionaries.
154 An empty dictionary is returned if two dictionaries are equivalent.
155 The reorder parameter indicates whether reordering is required
156 before comparison or not.
160 dict1 = CompareUtils.reorder(dict1)
161 dict2 = CompareUtils.reorder(dict2)
163 if dict1 is None and dict2 is None:
165 if dict1 is None or dict2 is None:
166 return {CompareUtils.MISMATCH_VALUE1_LABEL: dict1,
167 CompareUtils.MISMATCH_VALUE2_LABEL: dict2}
170 keys1 = set(dict1.keys())
171 keys2 = set(dict2.keys())
172 for key in keys1.union(keys2):
173 if key in keys1 and key not in keys2:
174 diff[key] = {CompareUtils.MISMATCH_VALUE1_LABEL: dict1[key],
175 CompareUtils.MISMATCH_VALUE2_LABEL: None}
176 elif key not in keys1 and key in keys2:
177 diff[key] = {CompareUtils.MISMATCH_VALUE1_LABEL: None,
178 CompareUtils.MISMATCH_VALUE2_LABEL: dict2[key]}
183 if type(val1) is dict and type(val2) is dict:
184 diff[key] = CompareUtils.diff_dicts(val1, val2, False)
186 diff[key] = {CompareUtils.MISMATCH_VALUE1_LABEL: val1,
187 CompareUtils.MISMATCH_VALUE2_LABEL: val2}
191 class YamlUtils(object):
194 def get_dict(yaml_file):
195 '''Returns the dictionary representation of the given YAML spec.'''
197 return yaml.load(open(yaml_file))
202 def compare_yamls(yaml1_file, yaml2_file):
203 '''Returns true if two dictionaries are equivalent, false otherwise.'''
204 dict1 = YamlUtils.get_dict(yaml1_file)
205 dict2 = YamlUtils.get_dict(yaml2_file)
206 return CompareUtils.compare_dicts(dict1, dict2)
209 def compare_yaml_dict(yaml_file, dic):
210 '''Returns true if yaml matches the dictionary, false otherwise.'''
211 return CompareUtils.compare_dicts(YamlUtils.get_dict(yaml_file), dic)
214 class TranslationUtils(object):
217 def compare_tosca_translation_with_hot(tosca_file, hot_file, params):
218 '''Verify tosca translation against the given hot specification.
221 tosca_file: relative local path or URL to the tosca input file
222 hot_file: relative path to expected hot output
223 params: dictionary of parameter name value pairs
225 Returns as a dictionary the difference between the HOT translation
226 of the given tosca_file and the given hot_file.
229 from toscaparser.tosca_template import ToscaTemplate
230 from translator.hot.tosca_translator import TOSCATranslator
232 tosca_tpl = os.path.normpath(os.path.join(
233 os.path.dirname(os.path.abspath(__file__)), tosca_file))
234 a_file = os.path.isfile(tosca_tpl)
236 tosca_tpl = tosca_file
238 expected_hot_tpl = os.path.join(
239 os.path.dirname(os.path.abspath(__file__)), hot_file)
241 tosca = ToscaTemplate(tosca_tpl, params, a_file)
242 translate = TOSCATranslator(tosca, params)
244 output = translate.translate()
245 output_dict = toscaparser.utils.yamlparser.simple_parse(output)
246 expected_output_dict = YamlUtils.get_dict(expected_hot_tpl)
247 return CompareUtils.diff_dicts(output_dict, expected_output_dict)
250 class UrlUtils(object):
253 def validate_url(path):
254 """Validates whether the given path is a URL or not.
256 If the given path includes a scheme (http, https, ftp, ...) and a net
257 location (a domain name such as www.github.com) it is validated as a
260 parsed = urlparse(path)
261 return bool(parsed.scheme) and bool(parsed.netloc)
264 def str_to_num(value):
265 """Convert a string representation of a number into a numeric type."""
266 if isinstance(value, numbers.Number) \
267 or isinstance(value, six.integer_types) \
268 or isinstance(value, float):
279 def check_for_env_variables():
280 return set(ENV_VARIABLES) < set(os.environ.keys())
283 def get_ks_access_dict():
284 tenant_name = os.getenv('OS_TENANT_NAME')
285 username = os.getenv('OS_USERNAME')
286 password = os.getenv('OS_PASSWORD')
287 auth_url = os.getenv('OS_AUTH_URL')
291 "tenantName": tenant_name,
292 "passwordCredentials": {
293 "username": username,
298 headers = {'Content-Type': 'application/json'}
300 keystone_response = requests.post(auth_url + '/tokens',
301 data=json.dumps(auth_dict),
303 if keystone_response.status_code != 200:
305 return json.loads(keystone_response.content)
310 def get_url_for(access_dict, service_type):
311 if access_dict is None:
313 service_catalog = access_dict['access']['serviceCatalog']
315 for service in service_catalog:
316 if service['type'] == service_type:
317 service_url = service['endpoints'][0]['publicURL']
322 def get_token_id(access_dict):
323 if access_dict is None:
325 return access_dict['access']['token']['id']