vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / modeling / functions.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 Mechanism for evaluating intrinsic functions.
18 """
19 from ..parser.exceptions import InvalidValueError
20 from ..parser.consumption import ConsumptionContext
21 from ..utils.collections import OrderedDict
22 from ..utils.type import full_type_name
23 from . import exceptions
24
25
26 class Function(object):
27     """
28     Base class for intrinsic functions. Serves as a placeholder for a value that should eventually
29     be derived by "evaluating" (calling) the function.
30
31     Note that this base class is provided as a convenience and you do not have to inherit it: any
32     object with an ``__evaluate__`` method would be treated similarly.
33     """
34
35     @property
36     def as_raw(self):
37         raise NotImplementedError
38
39     def __evaluate__(self, container_holder):
40         """
41         Evaluates the function if possible.
42
43         :rtype: :class:`Evaluation` (or any object with ``value`` and ``final`` properties)
44         :raises CannotEvaluateFunctionException: if cannot be evaluated at this time (do *not* just
45          return ``None``)
46         """
47
48         raise NotImplementedError
49
50     def __deepcopy__(self, memo):
51         # Circumvent cloning in order to maintain our state
52         return self
53
54
55 class Evaluation(object):
56     """
57     An evaluated :class:`Function` return value.
58
59     :ivar value: evaluated value
60     :ivar final: whether the value is final
61     :vartype final: boolean
62     """
63
64     def __init__(self, value, final=False):
65         self.value = value
66         self.final = final
67
68
69 def evaluate(value, container_holder, report_issues=False): # pylint: disable=too-many-branches
70     """
71     Recursively attempts to call ``__evaluate__``. If an evaluation occurred will return an
72     :class:`Evaluation`, otherwise it will be ``None``. If any evaluation is non-final, then the
73     entire evaluation will also be non-final.
74
75     The ``container_holder`` argument should have three properties: ``container`` should return
76     the model that contains the value, ``service`` should return the containing
77     :class:`~aria.modeling.models.Service` model or None, and ``service_template`` should return the
78     containing :class:`~aria.modeling.models.ServiceTemplate` model or ``None``.
79     """
80
81     evaluated = False
82     final = True
83
84     if hasattr(value, '__evaluate__'):
85         try:
86             evaluation = value.__evaluate__(container_holder)
87
88             # Verify evaluation structure
89             if (evaluation is None) \
90                 or (not hasattr(evaluation, 'value')) \
91                 or (not hasattr(evaluation, 'final')):
92                 raise InvalidValueError('bad __evaluate__ implementation: {0}'
93                                         .format(full_type_name(value)))
94
95             evaluated = True
96             value = evaluation.value
97             final = evaluation.final
98
99             # The evaluated value might itself be evaluable
100             evaluation = evaluate(value, container_holder, report_issues)
101             if evaluation is not None:
102                 value = evaluation.value
103                 if not evaluation.final:
104                     final = False
105         except exceptions.CannotEvaluateFunctionException:
106             pass
107         except InvalidValueError as e:
108             if report_issues:
109                 context = ConsumptionContext.get_thread_local()
110                 context.validation.report(e.issue)
111
112     elif isinstance(value, list):
113         evaluated_list = []
114         for v in value:
115             evaluation = evaluate(v, container_holder, report_issues)
116             if evaluation is not None:
117                 evaluated_list.append(evaluation.value)
118                 evaluated = True
119                 if not evaluation.final:
120                     final = False
121             else:
122                 evaluated_list.append(v)
123         if evaluated:
124             value = evaluated_list
125
126     elif isinstance(value, dict):
127         evaluated_dict = OrderedDict()
128         for k, v in value.iteritems():
129             evaluation = evaluate(v, container_holder, report_issues)
130             if evaluation is not None:
131                 evaluated_dict[k] = evaluation.value
132                 evaluated = True
133                 if not evaluation.final:
134                     final = False
135             else:
136                 evaluated_dict[k] = v
137         if evaluated:
138             value = evaluated_dict
139
140     return Evaluation(value, final) if evaluated else None