summaryrefslogtreecommitdiffstats
path: root/tosca2heat/tosca-parser/toscaparser/utils
diff options
context:
space:
mode:
Diffstat (limited to 'tosca2heat/tosca-parser/toscaparser/utils')
-rw-r--r--tosca2heat/tosca-parser/toscaparser/utils/__init__.py0
-rw-r--r--tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py22
-rw-r--r--tosca2heat/tosca-parser/toscaparser/utils/urlutils.py61
-rw-r--r--tosca2heat/tosca-parser/toscaparser/utils/validateutils.py189
-rw-r--r--tosca2heat/tosca-parser/toscaparser/utils/yamlparser.py86
5 files changed, 358 insertions, 0 deletions
diff --git a/tosca2heat/tosca-parser/toscaparser/utils/__init__.py b/tosca2heat/tosca-parser/toscaparser/utils/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/utils/__init__.py
diff --git a/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py b/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py
new file mode 100644
index 0000000..f5562e2
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py
@@ -0,0 +1,22 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import gettext
+import os
+
+_localedir = os.environ.get('tosca-parser'.upper() + '_LOCALEDIR')
+_t = gettext.translation('tosca-parser', localedir=_localedir,
+ fallback=True)
+
+
+def _(msg):
+ return _t.gettext(msg)
diff --git a/tosca2heat/tosca-parser/toscaparser/utils/urlutils.py b/tosca2heat/tosca-parser/toscaparser/utils/urlutils.py
new file mode 100644
index 0000000..8022158
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/utils/urlutils.py
@@ -0,0 +1,61 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+from six.moves.urllib.parse import urljoin
+from six.moves.urllib.parse import urlparse
+from toscaparser.common.exception import ExceptionCollector
+from toscaparser.utils.gettextutils import _
+
+try:
+ # Python 3.x
+ import urllib.request as urllib
+except ImportError:
+ # Python 2.x
+ import urllib
+
+
+class UrlUtils(object):
+
+ @staticmethod
+ def validate_url(path):
+ """Validates whether the given path is a URL or not.
+
+ If the given path includes a scheme (http, https, ftp, ...) and a net
+ location (a domain name such as www.github.com) it is validated as a
+ URL.
+ """
+ parsed = urlparse(path)
+ return bool(parsed.scheme) and bool(parsed.netloc)
+
+ @staticmethod
+ def join_url(url, relative_path):
+ """Builds a new URL from the given URL and the relative path.
+
+ Example:
+ url: http://www.githib.com/openstack/heat
+ relative_path: heat-translator
+ - joined: http://www.githib.com/openstack/heat-translator
+ """
+ if not UrlUtils.validate_url(url):
+ ExceptionCollector.appendException(
+ ValueError(_('"%s" is not a valid URL.') % url))
+ return urljoin(url, relative_path)
+
+ @staticmethod
+ def url_accessible(url):
+ """Validates whether the given URL is accessible.
+
+ Returns true if the get call returns a 200 response code.
+ Otherwise, returns false.
+ """
+ return urllib.urlopen(url).getcode() == 200
diff --git a/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py b/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py
new file mode 100644
index 0000000..f9b9fc5
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py
@@ -0,0 +1,189 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import collections
+import dateutil.parser
+import logging
+import numbers
+import re
+import six
+
+from toscaparser.common.exception import ExceptionCollector
+from toscaparser.common.exception import InvalidTOSCAVersionPropertyException
+from toscaparser.utils.gettextutils import _
+log = logging.getLogger('tosca')
+
+
+def str_to_num(value):
+ '''Convert a string representation of a number into a numeric type.'''
+ if isinstance(value, numbers.Number):
+ return value
+ try:
+ return int(value)
+ except ValueError:
+ return float(value)
+
+
+def validate_number(value):
+ return str_to_num(value)
+
+
+def validate_integer(value):
+ if not isinstance(value, int):
+ try:
+ value = int(value)
+ except Exception:
+ ExceptionCollector.appendException(
+ ValueError(_('"%s" is not an integer.') % value))
+ return value
+
+
+def validate_float(value):
+ if not isinstance(value, float):
+ ExceptionCollector.appendException(
+ ValueError(_('"%s" is not a float.') % value))
+ return validate_number(value)
+
+
+def validate_string(value):
+ if not isinstance(value, six.string_types):
+ ExceptionCollector.appendException(
+ ValueError(_('"%s" is not a string.') % value))
+ return value
+
+
+def validate_list(value):
+ if not isinstance(value, list):
+ ExceptionCollector.appendException(
+ ValueError(_('"%s" is not a list.') % value))
+ return value
+
+
+def validate_range(value):
+ validate_list(value)
+ if isinstance(value, list):
+ if len(value) != 2 or not (value[0] <= value[1]):
+ ExceptionCollector.appendException(
+ ValueError(_('"%s" is not a valid range.') % value))
+ validate_integer(value[0])
+ if not value[1] == "UNBOUNDED":
+ validate_integer(value[1])
+ return value
+
+
+def validate_map(value):
+ if not isinstance(value, collections.Mapping):
+ ExceptionCollector.appendException(
+ ValueError(_('"%s" is not a map.') % value))
+ return value
+
+
+def validate_boolean(value):
+ if isinstance(value, bool):
+ return value
+
+ if isinstance(value, str):
+ normalised = value.lower()
+ if normalised in ['true', 'false']:
+ return normalised == 'true'
+
+ ExceptionCollector.appendException(
+ ValueError(_('"%s" is not a boolean.') % value))
+
+
+def validate_timestamp(value):
+ try:
+ # Note: we must return our own exception message
+ # as dateutil's parser returns different types / values on
+ # different systems. OSX, for example, returns a tuple
+ # containing a different error message than Linux
+ dateutil.parser.parse(value)
+ except Exception as e:
+ original_err_msg = str(e)
+ log.error(original_err_msg)
+ ExceptionCollector.appendException(
+ ValueError(_('"%(val)s" is not a valid timestamp. "%(msg)s"') %
+ {'val': value, 'msg': original_err_msg}))
+ return
+
+
+class TOSCAVersionProperty(object):
+
+ VERSION_RE = re.compile('^(?P<major_version>([0-9][0-9]*))'
+ '(\.(?P<minor_version>([0-9][0-9]*)))?'
+ '(\.(?P<fix_version>([0-9][0-9]*)))?'
+ '(\.(?P<qualifier>([0-9A-Za-z]+)))?'
+ '(\-(?P<build_version>[0-9])*)?$')
+
+ def __init__(self, version):
+ self.version = str(version)
+ match = self.VERSION_RE.match(self.version)
+ if not match:
+ ExceptionCollector.appendException(
+ InvalidTOSCAVersionPropertyException(what=(self.version)))
+ return
+ ver = match.groupdict()
+ if self.version in ['0', '0.0', '0.0.0']:
+ log.warning(_('Version assumed as not provided'))
+ self.version = None
+ self.minor_version = ver['minor_version']
+ self.major_version = ver['major_version']
+ self.fix_version = ver['fix_version']
+ self.qualifier = self._validate_qualifier(ver['qualifier'])
+ self.build_version = self._validate_build(ver['build_version'])
+ self._validate_major_version(self.major_version)
+
+ def _validate_major_version(self, value):
+ """Validate major version
+
+ Checks if only major version is provided and assumes
+ minor version as 0.
+ Eg: If version = 18, then it returns version = '18.0'
+ """
+
+ if self.minor_version is None and self.build_version is None and \
+ value != '0':
+ log.warning(_('Minor version assumed "0".'))
+ self.version = '.'.join([value, '0'])
+ return value
+
+ def _validate_qualifier(self, value):
+ """Validate qualifier
+
+ TOSCA version is invalid if a qualifier is present without the
+ fix version or with all of major, minor and fix version 0s.
+
+ For example, the following versions are invalid
+ 18.0.abc
+ 0.0.0.abc
+ """
+ if (self.fix_version is None and value) or \
+ (self.minor_version == self.major_version ==
+ self.fix_version == '0' and value):
+ ExceptionCollector.appendException(
+ InvalidTOSCAVersionPropertyException(what=(self.version)))
+ return value
+
+ def _validate_build(self, value):
+ """Validate build version
+
+ TOSCA version is invalid if build version is present without the
+ qualifier.
+ Eg: version = 18.0.0-1 is invalid.
+ """
+ if not self.qualifier and value:
+ ExceptionCollector.appendException(
+ InvalidTOSCAVersionPropertyException(what=(self.version)))
+ return value
+
+ def get_version(self):
+ return self.version
diff --git a/tosca2heat/tosca-parser/toscaparser/utils/yamlparser.py b/tosca2heat/tosca-parser/toscaparser/utils/yamlparser.py
new file mode 100644
index 0000000..713650d
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/utils/yamlparser.py
@@ -0,0 +1,86 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import codecs
+from collections import OrderedDict
+
+from six.moves import urllib
+import yaml
+
+from toscaparser.common.exception import ExceptionCollector
+from toscaparser.common.exception import URLException
+from toscaparser.utils.gettextutils import _
+
+
+if hasattr(yaml, 'CSafeLoader'):
+ yaml_loader = yaml.CSafeLoader
+else:
+ yaml_loader = yaml.SafeLoader
+
+
+def load_yaml(path, a_file=True):
+ f = None
+ try:
+ f = codecs.open(path, encoding='utf-8', errors='strict') if a_file \
+ else urllib.request.urlopen(path)
+ except urllib.error.URLError as e:
+ if hasattr(e, 'reason'):
+ msg = (_('Failed to reach server "%(path)s". Reason is: '
+ '%(reason)s.')
+ % {'path': path, 'reason': e.reason})
+ ExceptionCollector.appendException(URLException(what=msg))
+ return
+ elif hasattr(e, 'code'):
+ msg = (_('The server "%(path)s" couldn\'t fulfill the request. '
+ 'Error code: "%(code)s".')
+ % {'path': path, 'code': e.code})
+ ExceptionCollector.appendException(URLException(what=msg))
+ return
+ except Exception as e:
+ raise
+ return yaml.load(f.read(), Loader=yaml_loader)
+
+
+def simple_parse(tmpl_str):
+ try:
+ tpl = yaml.load(tmpl_str, Loader=yaml_loader)
+ except yaml.YAMLError as yea:
+ ExceptionCollector.appendException(ValueError(yea))
+ else:
+ if tpl is None:
+ tpl = {}
+ return tpl
+
+
+def ordered_load(stream, Loader=yaml.Loader, object_pairs_hook=OrderedDict):
+ class OrderedLoader(Loader):
+ pass
+
+ def construct_mapping(loader, node):
+ loader.flatten_mapping(node)
+ return object_pairs_hook(loader.construct_pairs(node))
+
+ OrderedLoader.add_constructor(
+ yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
+ construct_mapping)
+ return yaml.load(stream, OrderedLoader)
+
+
+def simple_ordered_parse(tmpl_str):
+ try:
+ tpl = ordered_load(tmpl_str)
+ except yaml.YAMLError as yea:
+ ExceptionCollector.appendException(ValueError(yea))
+ else:
+ if tpl is None:
+ tpl = {}
+ return tpl