vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / parser / presentation / field_validators.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
17 from ..validation import Issue
18 from .utils import (parse_types_dict_names, report_issue_for_unknown_type,
19                     report_issue_for_parent_is_self, report_issue_for_unknown_parent_type,
20                     report_issue_for_circular_type_hierarchy)
21
22
23 def type_validator(type_name, *types_dict_names):
24     """
25     Makes sure that the field refers to an existing type defined in the root presenter.
26
27     The arguments from the second onwards are used to locate a nested field under
28     ``service_template`` under the root presenter. The first of these can optionally be a function,
29     in which case it will be called to convert type names. This can be used to support shorthand
30     type names, aliases, etc.
31
32     Can be used with the :func:`field_validator` decorator.
33     """
34
35     types_dict_names, convert = parse_types_dict_names(types_dict_names)
36
37     def validator_fn(field, presentation, context):
38         field.default_validate(presentation, context)
39
40         # Make sure type exists
41         value = getattr(presentation, field.name)
42         if value is not None:
43             types_dict = context.presentation.get('service_template', *types_dict_names) or {}
44
45             if convert:
46                 value = convert(context, value, types_dict)
47
48             if value not in types_dict:
49                 report_issue_for_unknown_type(context, presentation, type_name, field.name)
50
51     return validator_fn
52
53
54 def list_type_validator(type_name, *types_dict_names):
55     """
56     Makes sure that the field's elements refer to existing types defined in the root presenter.
57
58     Assumes that the field is a list.
59
60     The arguments from the second onwards are used to locate a nested field under
61     ``service_template`` under the root presenter. The first of these can optionally be a function,
62     in which case it will be called to convert type names. This can be used to support shorthand
63     type names, aliases, etc.
64
65     Can be used with the :func:`field_validator` decorator.
66     """
67
68     types_dict_names, convert = parse_types_dict_names(types_dict_names)
69
70     def validator_fn(field, presentation, context):
71         field.default_validate(presentation, context)
72
73         # Make sure types exist
74         values = getattr(presentation, field.name)
75         if values is not None:
76             types_dict = context.presentation.get('service_template', *types_dict_names) or {}
77
78             for value in values:
79                 if convert:
80                     value = convert(context, value, types_dict)
81
82                 if value not in types_dict:
83                     report_issue_for_unknown_type(context, presentation, type_name, field.name)
84
85     return validator_fn
86
87
88 def list_length_validator(length):
89     """
90     Makes sure the field has exactly a specific number of elements.
91
92     Assumes that the field is a list.
93
94     Can be used with the :func:`field_validator` decorator.
95     """
96
97     def validator_fn(field, presentation, context):
98         field.default_validate(presentation, context)
99
100         # Make sure list has exactly the length
101         values = getattr(presentation, field.name)
102         if isinstance(values, list):
103             if len(values) != length:
104                 context.validation.report('field "%s" does not have exactly %d elements in "%s"'
105                                           % (field.name, length, presentation._fullname),
106                                           locator=presentation._get_child_locator(field.name),
107                                           level=Issue.FIELD)
108
109     return validator_fn
110
111
112 def derived_from_validator(*types_dict_names):
113     """
114     Makes sure that the field refers to a valid parent type defined in the root presenter.
115
116     Checks that we do not derive from ourselves and that we do not cause a circular hierarchy.
117
118     The arguments are used to locate a nested field under ``service_template`` under the root
119     presenter. The first of these can optionally be a function, in which case it will be called to
120     convert type names. This can be used to support shorthand type names, aliases, etc.
121
122     Can be used with the :func:`field_validator` decorator.
123     """
124
125     types_dict_names, convert = parse_types_dict_names(types_dict_names)
126
127     def validator_fn(field, presentation, context):
128         field.default_validate(presentation, context)
129
130         value = getattr(presentation, field.name)
131         if value is not None:
132             types_dict = context.presentation.get('service_template', *types_dict_names) or {}
133
134             if convert:
135                 value = convert(context, value, types_dict)
136
137             # Make sure not derived from self
138             if value == presentation._name:
139                 report_issue_for_parent_is_self(context, presentation, field.name)
140             # Make sure derived from type exists
141             elif value not in types_dict:
142                 report_issue_for_unknown_parent_type(context, presentation, field.name)
143             else:
144                 # Make sure derivation hierarchy is not circular
145                 hierarchy = [presentation._name]
146                 presentation_tmp = presentation
147                 while presentation_tmp.derived_from is not None:
148                     derived_from = presentation_tmp.derived_from
149                     if convert:
150                         derived_from = convert(context, derived_from, types_dict)
151
152                     if derived_from == presentation_tmp._name:
153                         # This should cause a validation issue at that type
154                         break
155                     elif derived_from not in types_dict:
156                         # This should cause a validation issue at that type
157                         break
158                     presentation_tmp = types_dict[derived_from]
159                     if presentation_tmp._name in hierarchy:
160                         report_issue_for_circular_type_hierarchy(context, presentation, field.name)
161                         break
162                     hierarchy.append(presentation_tmp._name)
163
164     return validator_fn