| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """ |
| Common code for contexts. |
| """ |
| |
| import logging |
| from contextlib import contextmanager |
| from functools import partial |
| |
| import jinja2 |
| |
| from aria import ( |
| logger as aria_logger, |
| modeling |
| ) |
| from aria.storage import exceptions |
| |
| from ...utils.uuid import generate_uuid |
| |
| |
| class BaseContext(object): |
| """ |
| Base class for contexts. |
| """ |
| |
| INSTRUMENTATION_FIELDS = ( |
| modeling.models.Service.inputs, |
| modeling.models.ServiceTemplate.inputs, |
| modeling.models.Policy.properties, |
| modeling.models.PolicyTemplate.properties, |
| modeling.models.Node.attributes, |
| modeling.models.Node.properties, |
| modeling.models.NodeTemplate.attributes, |
| modeling.models.NodeTemplate.properties, |
| modeling.models.Group.properties, |
| modeling.models.GroupTemplate.properties, |
| modeling.models.Capability.properties, |
| # TODO ARIA-279: modeling.models.Capability.attributes, |
| modeling.models.CapabilityTemplate.properties, |
| # TODO ARIA-279: modeling.models.CapabilityTemplate.attributes |
| modeling.models.Relationship.properties, |
| modeling.models.Artifact.properties, |
| modeling.models.ArtifactTemplate.properties, |
| modeling.models.Interface.inputs, |
| modeling.models.InterfaceTemplate.inputs, |
| modeling.models.Operation.inputs, |
| modeling.models.OperationTemplate.inputs |
| ) |
| |
| class PrefixedLogger(object): |
| def __init__(self, base_logger, task_id=None): |
| self._logger = base_logger |
| self._task_id = task_id |
| |
| def __getattr__(self, attribute): |
| if attribute.upper() in logging._levelNames: |
| return partial(self._logger_with_task_id, _level=attribute) |
| else: |
| return getattr(self._logger, attribute) |
| |
| def _logger_with_task_id(self, *args, **kwargs): |
| level = kwargs.pop('_level') |
| kwargs.setdefault('extra', {})['task_id'] = self._task_id |
| return getattr(self._logger, level)(*args, **kwargs) |
| |
| def __init__(self, |
| name, |
| service_id, |
| model_storage, |
| resource_storage, |
| execution_id, |
| workdir=None, |
| **kwargs): |
| super(BaseContext, self).__init__(**kwargs) |
| self._name = name |
| self._id = generate_uuid(variant='uuid') |
| self._model = model_storage |
| self._resource = resource_storage |
| self._service_id = service_id |
| self._workdir = workdir |
| self._execution_id = execution_id |
| self.logger = None |
| |
| def _register_logger(self, level=None, task_id=None): |
| self.logger = self.PrefixedLogger( |
| logging.getLogger(aria_logger.TASK_LOGGER_NAME), task_id=task_id) |
| self.logger.setLevel(level or logging.DEBUG) |
| if not self.logger.handlers: |
| self.logger.addHandler(self._get_sqla_handler()) |
| |
| def _get_sqla_handler(self): |
| return aria_logger.create_sqla_log_handler(model=self._model, |
| log_cls=modeling.models.Log, |
| execution_id=self._execution_id) |
| |
| def __repr__(self): |
| return ( # pylint: disable=redundant-keyword-arg |
| u'{name}(name={self.name}, ' |
| u'deployment_id={self._service_id}, ' |
| .format(name=self.__class__.__name__, self=self)) |
| |
| @contextmanager |
| def logging_handlers(self, handlers): |
| original_handlers = self.logger.handlers |
| handlers = handlers or [] |
| try: |
| for handler in handlers: |
| self.logger.addHandler(handler) |
| for handler in original_handlers: |
| self.logger.removeHandler(handler) |
| yield self.logger |
| finally: |
| for handler in self.logger.handlers[:]: |
| self.logger.removeHandler(handler) |
| for handler in original_handlers: |
| self.logger.addHandler(handler) |
| |
| @property |
| def model(self): |
| """ |
| Storage model API ("MAPI"). |
| """ |
| return self._model |
| |
| @property |
| def resource(self): |
| """ |
| Storage resource API ("RAPI"). |
| """ |
| return self._resource |
| |
| @property |
| def service_template(self): |
| """ |
| Service template model. |
| """ |
| return self.service.service_template |
| |
| @property |
| def service(self): |
| """ |
| Service instance model. |
| """ |
| return self.model.service.get(self._service_id) |
| |
| @property |
| def name(self): |
| """ |
| Operation name. |
| """ |
| return self._name |
| |
| @property |
| def id(self): |
| """ |
| Operation ID. |
| """ |
| return self._id |
| |
| def download_resource(self, destination, path=None): |
| """ |
| Download a service template resource from the storage resource API ("RAPI"). |
| """ |
| try: |
| self.resource.service.download(entry_id=str(self.service.id), |
| destination=destination, |
| path=path) |
| except exceptions.StorageError: |
| self.resource.service_template.download(entry_id=str(self.service_template.id), |
| destination=destination, |
| path=path) |
| |
| def download_resource_and_render(self, destination, path=None, variables=None): |
| """ |
| Downloads a service template resource from the resource storage and renders its content as a |
| Jinja template using the provided variables. ``ctx`` is available to the template without |
| providing it explicitly. |
| """ |
| resource_content = self.get_resource(path=path) |
| resource_content = self._render_resource(resource_content=resource_content, |
| variables=variables) |
| with open(destination, 'wb') as f: |
| f.write(resource_content) |
| |
| def get_resource(self, path=None): |
| """ |
| Reads a service instance resource as string from the resource storage. |
| """ |
| try: |
| return self.resource.service.read(entry_id=str(self.service.id), path=path) |
| except exceptions.StorageError: |
| return self.resource.service_template.read(entry_id=str(self.service_template.id), |
| path=path) |
| |
| def get_resource_and_render(self, path=None, variables=None): |
| """ |
| Reads a service instance resource as string from the resource storage and renders it as a |
| Jinja template using the provided variables. ``ctx`` is available to the template without |
| providing it explicitly. |
| """ |
| resource_content = self.get_resource(path=path) |
| return self._render_resource(resource_content=resource_content, variables=variables) |
| |
| def _render_resource(self, resource_content, variables): |
| variables = variables or {} |
| variables.setdefault('ctx', self) |
| resource_template = jinja2.Template(resource_content) |
| return resource_template.render(variables) |