vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / parser / presentation / utils.py
1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements.  See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License.  You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 from types import FunctionType
17
18 from ...utils.formatting import safe_repr
19 from ...utils.type import full_type_name
20 from ..validation import Issue
21 from .null import NULL
22
23
24 def get_locator(*values):
25     """
26     Gets the first available locator.
27
28     :rtype: :class:`aria.parser.reading.Locator`
29     """
30
31     for v in values:
32         if hasattr(v, '_locator'):
33             locator = v._locator
34             if locator is not None:
35                 return locator
36     return None
37
38
39 def parse_types_dict_names(types_dict_names):
40     """
41     If the first element in the array is a function, extracts it out.
42     """
43
44     convert = None
45     if isinstance(types_dict_names[0], FunctionType):
46         convert = types_dict_names[0]
47         types_dict_names = types_dict_names[1:]
48     return types_dict_names, convert
49
50
51 def validate_primitive(value, cls, coerce=False):
52     """
53     Checks if the value is of the primitive type, optionally attempting to coerce it
54     if it is not.
55
56     :raises ValueError: if not a primitive type or if coercion failed.
57     """
58
59     if (cls is not None) and (value is not None) and (value is not NULL):
60         if (cls is unicode) or (cls is str): # These two types are interchangeable
61             valid = isinstance(value, basestring)
62         elif cls is int:
63             # In Python, a bool is an int
64             valid = isinstance(value, int) and not isinstance(value, bool)
65         else:
66             valid = isinstance(value, cls)
67         if not valid:
68             if coerce:
69                 value = cls(value)
70             else:
71                 raise ValueError('not a "%s": %s' % (full_type_name(cls), safe_repr(value)))
72     return value
73
74
75 def validate_no_short_form(context, presentation):
76     """
77     Makes sure that we can use short form definitions only if we allowed it.
78     """
79
80     if not hasattr(presentation, 'SHORT_FORM_FIELD') and not isinstance(presentation._raw, dict):
81         context.validation.report('short form not allowed for field "%s"' % presentation._fullname,
82                                   locator=presentation._locator,
83                                   level=Issue.BETWEEN_FIELDS)
84
85
86 def validate_no_unknown_fields(context, presentation):
87     """
88     Make sure that we can use unknown fields only if we allowed it.
89     """
90
91     if not getattr(presentation, 'ALLOW_UNKNOWN_FIELDS', False) \
92             and not context.validation.allow_unknown_fields \
93             and isinstance(presentation._raw, dict) \
94             and hasattr(presentation, 'FIELDS'):
95         for k in presentation._raw:
96             if k not in presentation.FIELDS:
97                 context.validation.report('field "%s" is not supported in "%s"'
98                                           % (k, presentation._fullname),
99                                           locator=presentation._get_child_locator(k),
100                                           level=Issue.BETWEEN_FIELDS)
101
102
103 def validate_known_fields(context, presentation):
104     """
105     Validates all known fields.
106     """
107
108     if hasattr(presentation, '_iter_fields'):
109         for _, field in presentation._iter_fields():
110             field.validate(presentation, context)
111
112
113 def get_parent_presentation(context, presentation, *types_dict_names):
114     """
115     Returns the parent presentation according to the ``derived_from`` field, or ``None`` if invalid.
116
117     Checks that we do not derive from ourselves and that we do not cause a circular hierarchy.
118
119     The arguments from the third onwards are used to locate a nested field under
120     ``service_template`` under the root presenter. The first of these can optionally be a function,
121     in which case it will be called to convert type names. This can be used to support shorthand
122     type names, aliases, etc.
123     """
124
125     type_name = presentation.derived_from
126
127     if type_name is None:
128         return None
129
130     types_dict_names, convert = parse_types_dict_names(types_dict_names)
131     types_dict = context.presentation.get('service_template', *types_dict_names) or {}
132
133     if convert:
134         type_name = convert(context, type_name, types_dict)
135
136     # Make sure not derived from self
137     if type_name == presentation._name:
138         return None
139     # Make sure derived from type exists
140     elif type_name not in types_dict:
141         return None
142     else:
143         # Make sure derivation hierarchy is not circular
144         hierarchy = [presentation._name]
145         presentation_copy = presentation
146         while presentation_copy.derived_from is not None:
147             derived_from = presentation_copy.derived_from
148             if convert:
149                 derived_from = convert(context, derived_from, types_dict)
150
151             if derived_from == presentation_copy._name or derived_from not in types_dict:
152                 return None
153             presentation_copy = types_dict[derived_from]
154             if presentation_copy._name in hierarchy:
155                 return None
156             hierarchy.append(presentation_copy._name)
157
158     return types_dict[type_name]
159
160
161 def report_issue_for_unknown_type(context, presentation, type_name, field_name, value=None):
162     if value is None:
163         value = getattr(presentation, field_name)
164     context.validation.report('"%s" refers to an unknown %s in "%s": %s'
165                               % (field_name, type_name, presentation._fullname, safe_repr(value)),
166                               locator=presentation._get_child_locator(field_name),
167                               level=Issue.BETWEEN_TYPES)
168
169
170 def report_issue_for_parent_is_self(context, presentation, field_name):
171     context.validation.report('parent type of "%s" is self' % presentation._fullname,
172                               locator=presentation._get_child_locator(field_name),
173                               level=Issue.BETWEEN_TYPES)
174
175
176 def report_issue_for_unknown_parent_type(context, presentation, field_name):
177     context.validation.report('unknown parent type "%s" in "%s"'
178                               % (getattr(presentation, field_name), presentation._fullname),
179                               locator=presentation._get_child_locator(field_name),
180                               level=Issue.BETWEEN_TYPES)
181
182
183 def report_issue_for_circular_type_hierarchy(context, presentation, field_name):
184     context.validation.report('"%s" of "%s" creates a circular type hierarchy'
185                               % (getattr(presentation, field_name), presentation._fullname),
186                               locator=presentation._get_child_locator(field_name),
187                               level=Issue.BETWEEN_TYPES)