vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / parser / consumption / presentation.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 ...utils.threading import FixedThreadPoolExecutor
18 from ...utils.formatting import json_dumps, yaml_dumps
19 from ..loading import UriLocation
20 from ..reading import AlreadyReadException
21 from ..presentation import PresenterNotFoundError
22 from .consumer import Consumer
23
24
25 class Read(Consumer):
26     """
27     Reads the presentation, handling imports recursively.
28
29     It works by consuming a data source via appropriate :class:`~aria.parser.loading.Loader`,
30     :class:`~aria.parser.reading.Reader`, and :class:`~aria.parser.presentation.Presenter`
31     instances.
32
33     It supports agnostic raw data composition for presenters that have
34     ``_get_import_locations`` and ``_merge_import``.
35
36     To improve performance, loaders are called asynchronously on separate threads.
37
38     Note that parsing may internally trigger more than one loading/reading/presentation
39     cycle, for example if the agnostic raw data has dependencies that must also be parsed.
40     """
41
42     def consume(self):
43         if self.context.presentation.location is None:
44             self.context.validation.report('Presentation consumer: missing location')
45             return
46
47         presenter = None
48         imported_presentations = None
49
50         executor = FixedThreadPoolExecutor(size=self.context.presentation.threads,
51                                            timeout=self.context.presentation.timeout)
52         executor.print_exceptions = self.context.presentation.print_exceptions
53         try:
54             presenter = self._present(self.context.presentation.location, None, None, executor)
55             executor.drain()
56
57             # Handle exceptions
58             for e in executor.exceptions:
59                 self._handle_exception(e)
60
61             imported_presentations = executor.returns
62         finally:
63             executor.close()
64
65         # Merge imports
66         if (imported_presentations is not None) and hasattr(presenter, '_merge_import'):
67             for imported_presentation in imported_presentations:
68                 okay = True
69                 if hasattr(presenter, '_validate_import'):
70                     okay = presenter._validate_import(self.context, imported_presentation)
71                 if okay:
72                     presenter._merge_import(imported_presentation)
73
74         self.context.presentation.presenter = presenter
75
76     def dump(self):
77         if self.context.has_arg_switch('yaml'):
78             indent = self.context.get_arg_value_int('indent', 2)
79             raw = self.context.presentation.presenter._raw
80             self.context.write(yaml_dumps(raw, indent=indent))
81         elif self.context.has_arg_switch('json'):
82             indent = self.context.get_arg_value_int('indent', 2)
83             raw = self.context.presentation.presenter._raw
84             self.context.write(json_dumps(raw, indent=indent))
85         else:
86             self.context.presentation.presenter._dump(self.context)
87
88     def _handle_exception(self, e):
89         if isinstance(e, AlreadyReadException):
90             return
91         super(Read, self)._handle_exception(e)
92
93     def _present(self, location, origin_location, presenter_class, executor):
94         # Link the context to this thread
95         self.context.set_thread_local()
96
97         raw = self._read(location, origin_location)
98
99         if self.context.presentation.presenter_class is not None:
100             # The presenter class we specified in the context overrides everything
101             presenter_class = self.context.presentation.presenter_class
102         else:
103             try:
104                 presenter_class = self.context.presentation.presenter_source.get_presenter(raw)
105             except PresenterNotFoundError:
106                 if presenter_class is None:
107                     raise
108             # We'll use the presenter class we were given (from the presenter that imported us)
109             if presenter_class is None:
110                 raise PresenterNotFoundError('presenter not found')
111
112         presentation = presenter_class(raw=raw)
113
114         if presentation is not None and hasattr(presentation, '_link_locators'):
115             presentation._link_locators()
116
117         # Submit imports to executor
118         if hasattr(presentation, '_get_import_locations'):
119             import_locations = presentation._get_import_locations(self.context)
120             if import_locations:
121                 for import_location in import_locations:
122                     # The imports inherit the parent presenter class and use the current location as
123                     # their origin location
124                     import_location = UriLocation(import_location)
125                     executor.submit(self._present, import_location, location, presenter_class,
126                                     executor)
127
128         return presentation
129
130     def _read(self, location, origin_location):
131         if self.context.reading.reader is not None:
132             return self.context.reading.reader.read()
133         loader = self.context.loading.loader_source.get_loader(self.context.loading, location,
134                                                                origin_location)
135         reader = self.context.reading.reader_source.get_reader(self.context.reading, location,
136                                                                loader)
137         return reader.read()