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 4# 5# http://www.apache.org/licenses/LICENSE-2.0 6# 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 11# under the License. 12 13import json 14import yaml 15 16from heatclient._i18n import _ 17 18if hasattr(yaml, 'CSafeLoader'): 19 yaml_loader_base = yaml.CSafeLoader 20else: 21 yaml_loader_base = yaml.SafeLoader 22 23if hasattr(yaml, 'CSafeDumper'): 24 yaml_dumper_base = yaml.CSafeDumper 25else: 26 yaml_dumper_base = yaml.SafeDumper 27 28 29# We create custom class to not overriden the default yaml behavior 30class yaml_loader(yaml_loader_base): 31 pass 32 33 34class yaml_dumper(yaml_dumper_base): 35 pass 36 37 38def _construct_yaml_str(self, node): 39 # Override the default string handling function 40 # to always return unicode objects 41 return self.construct_scalar(node) 42 43 44yaml_loader.add_constructor(u'tag:yaml.org,2002:str', _construct_yaml_str) 45# Unquoted dates like 2013-05-23 in yaml files get loaded as objects of type 46# datetime.data which causes problems in API layer when being processed by 47# openstack.common.jsonutils. Therefore, make unicode string out of timestamps 48# until jsonutils can handle dates. 49yaml_loader.add_constructor(u'tag:yaml.org,2002:timestamp', 50 _construct_yaml_str) 51 52 53def parse(tmpl_str): 54 """Takes a string and returns a dict containing the parsed structure. 55 56 This includes determination of whether the string is using the 57 JSON or YAML format. 58 """ 59 # strip any whitespace before the check 60 tmpl_str = tmpl_str.strip() 61 if tmpl_str.startswith('{'): 62 tpl = json.loads(tmpl_str) 63 else: 64 try: 65 tpl = yaml.load(tmpl_str, Loader=yaml_loader) 66 except yaml.YAMLError: 67 # NOTE(prazumovsky): we need to return more informative error for 68 # user, so use SafeLoader, which return error message with template 69 # snippet where error has been occurred. 70 try: 71 tpl = yaml.load(tmpl_str, Loader=yaml.SafeLoader) 72 except yaml.YAMLError as yea: 73 raise ValueError(yea) 74 else: 75 if tpl is None: 76 tpl = {} 77 # Looking for supported version keys in the loaded template 78 if not ('HeatTemplateFormatVersion' in tpl 79 or 'heat_template_version' in tpl 80 or 'AWSTemplateFormatVersion' in tpl): 81 raise ValueError(_("Template format version not found.")) 82 return tpl 83