vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / orchestrator / context / common.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 Common code for contexts.
18 """
19
20 import logging
21 from contextlib import contextmanager
22 from functools import partial
23
24 import jinja2
25
26 from aria import (
27     logger as aria_logger,
28     modeling
29 )
30 from aria.storage import exceptions
31
32 from ...utils.uuid import generate_uuid
33
34
35 class BaseContext(object):
36     """
37     Base class for contexts.
38     """
39
40     INSTRUMENTATION_FIELDS = (
41         modeling.models.Service.inputs,
42         modeling.models.ServiceTemplate.inputs,
43         modeling.models.Policy.properties,
44         modeling.models.PolicyTemplate.properties,
45         modeling.models.Node.attributes,
46         modeling.models.Node.properties,
47         modeling.models.NodeTemplate.attributes,
48         modeling.models.NodeTemplate.properties,
49         modeling.models.Group.properties,
50         modeling.models.GroupTemplate.properties,
51         modeling.models.Capability.properties,
52         # TODO ARIA-279: modeling.models.Capability.attributes,
53         modeling.models.CapabilityTemplate.properties,
54         # TODO ARIA-279: modeling.models.CapabilityTemplate.attributes
55         modeling.models.Relationship.properties,
56         modeling.models.Artifact.properties,
57         modeling.models.ArtifactTemplate.properties,
58         modeling.models.Interface.inputs,
59         modeling.models.InterfaceTemplate.inputs,
60         modeling.models.Operation.inputs,
61         modeling.models.OperationTemplate.inputs
62     )
63
64     class PrefixedLogger(object):
65         def __init__(self, base_logger, task_id=None):
66             self._logger = base_logger
67             self._task_id = task_id
68
69         def __getattr__(self, attribute):
70             if attribute.upper() in logging._levelNames:
71                 return partial(self._logger_with_task_id, _level=attribute)
72             else:
73                 return getattr(self._logger, attribute)
74
75         def _logger_with_task_id(self, *args, **kwargs):
76             level = kwargs.pop('_level')
77             kwargs.setdefault('extra', {})['task_id'] = self._task_id
78             return getattr(self._logger, level)(*args, **kwargs)
79
80     def __init__(self,
81                  name,
82                  service_id,
83                  model_storage,
84                  resource_storage,
85                  execution_id,
86                  workdir=None,
87                  **kwargs):
88         super(BaseContext, self).__init__(**kwargs)
89         self._name = name
90         self._id = generate_uuid(variant='uuid')
91         self._model = model_storage
92         self._resource = resource_storage
93         self._service_id = service_id
94         self._workdir = workdir
95         self._execution_id = execution_id
96         self.logger = None
97
98     def _register_logger(self, level=None, task_id=None):
99         self.logger = self.PrefixedLogger(
100             logging.getLogger(aria_logger.TASK_LOGGER_NAME), task_id=task_id)
101         self.logger.setLevel(level or logging.DEBUG)
102         if not self.logger.handlers:
103             self.logger.addHandler(self._get_sqla_handler())
104
105     def _get_sqla_handler(self):
106         return aria_logger.create_sqla_log_handler(model=self._model,
107                                                    log_cls=modeling.models.Log,
108                                                    execution_id=self._execution_id)
109
110     def __repr__(self):
111         return (
112             '{name}(name={self.name}, '
113             'deployment_id={self._service_id}, '
114             .format(name=self.__class__.__name__, self=self))
115
116     @contextmanager
117     def logging_handlers(self, handlers=None):
118         handlers = handlers or []
119         try:
120             for handler in handlers:
121                 self.logger.addHandler(handler)
122             yield self.logger
123         finally:
124             for handler in handlers:
125                 self.logger.removeHandler(handler)
126
127     @property
128     def model(self):
129         """
130         Storage model API ("MAPI").
131         """
132         return self._model
133
134     @property
135     def resource(self):
136         """
137         Storage resource API ("RAPI").
138         """
139         return self._resource
140
141     @property
142     def service_template(self):
143         """
144         Service template model.
145         """
146         return self.service.service_template
147
148     @property
149     def service(self):
150         """
151         Service instance model.
152         """
153         return self.model.service.get(self._service_id)
154
155     @property
156     def name(self):
157         """
158         Operation name.
159         """
160         return self._name
161
162     @property
163     def id(self):
164         """
165         Operation ID.
166         """
167         return self._id
168
169     def download_resource(self, destination, path=None):
170         """
171         Download a service template resource from the storage resource API ("RAPI").
172         """
173         try:
174             self.resource.service.download(entry_id=str(self.service.id),
175                                            destination=destination,
176                                            path=path)
177         except exceptions.StorageError:
178             self.resource.service_template.download(entry_id=str(self.service_template.id),
179                                                     destination=destination,
180                                                     path=path)
181
182     def download_resource_and_render(self, destination, path=None, variables=None):
183         """
184         Downloads a service template resource from the resource storage and renders its content as a
185         Jinja template using the provided variables. ``ctx`` is available to the template without
186         providing it explicitly.
187         """
188         resource_content = self.get_resource(path=path)
189         resource_content = self._render_resource(resource_content=resource_content,
190                                                  variables=variables)
191         with open(destination, 'wb') as f:
192             f.write(resource_content)
193
194     def get_resource(self, path=None):
195         """
196         Reads a service instance resource as string from the resource storage.
197         """
198         try:
199             return self.resource.service.read(entry_id=str(self.service.id), path=path)
200         except exceptions.StorageError:
201             return self.resource.service_template.read(entry_id=str(self.service_template.id),
202                                                        path=path)
203
204     def get_resource_and_render(self, path=None, variables=None):
205         """
206         Reads a service instance resource as string from the resource storage and renders it as a
207         Jinja template using the provided variables. ``ctx`` is available to the template without
208         providing it explicitly.
209         """
210         resource_content = self.get_resource(path=path)
211         return self._render_resource(resource_content=resource_content, variables=variables)
212
213     def _render_resource(self, resource_content, variables):
214         variables = variables or {}
215         variables.setdefault('ctx', self)
216         resource_template = jinja2.Template(resource_content)
217         return resource_template.render(variables)