diff options
Diffstat (limited to 'azure/aria/aria-extension-cloudify/src/aria/aria/core.py')
-rw-r--r-- | azure/aria/aria-extension-cloudify/src/aria/aria/core.py | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/core.py b/azure/aria/aria-extension-cloudify/src/aria/aria/core.py new file mode 100644 index 0000000..e364f48 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/aria/core.py @@ -0,0 +1,133 @@ +# 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. + +""" +ARIA core module. +""" + +from . import exceptions +from .parser import consumption +from .parser.loading.location import UriLocation +from .orchestrator import topology + + +class Core(object): + + def __init__(self, + model_storage, + resource_storage, + plugin_manager): + self._model_storage = model_storage + self._resource_storage = resource_storage + self._plugin_manager = plugin_manager + + @property + def model_storage(self): + return self._model_storage + + @property + def resource_storage(self): + return self._resource_storage + + @property + def plugin_manager(self): + return self._plugin_manager + + def validate_service_template(self, service_template_path): + self._parse_service_template(service_template_path) + + def create_service_template(self, service_template_path, service_template_dir, + service_template_name): + context = self._parse_service_template(service_template_path) + service_template = context.modeling.template + service_template.name = service_template_name + self.model_storage.service_template.put(service_template) + self.resource_storage.service_template.upload( + entry_id=str(service_template.id), source=service_template_dir) + return service_template.id + + def delete_service_template(self, service_template_id): + service_template = self.model_storage.service_template.get(service_template_id) + if service_template.services: + raise exceptions.DependentServicesError( + 'Can\'t delete service template `{0}` - service template has existing services' + .format(service_template.name)) + + self.model_storage.service_template.delete(service_template) + self.resource_storage.service_template.delete(entry_id=str(service_template.id)) + + def create_service(self, service_template_id, inputs, service_name=None): + service_template = self.model_storage.service_template.get(service_template_id) + + storage_session = self.model_storage._all_api_kwargs['session'] + # setting no autoflush for the duration of instantiation - this helps avoid dependency + # constraints as they're being set up + with storage_session.no_autoflush: + topology_ = topology.Topology() + service = topology_.instantiate( + service_template, inputs=inputs, plugins=self.model_storage.plugin.list()) + topology_.coerce(service, report_issues=True) + + topology_.validate(service) + topology_.satisfy_requirements(service) + topology_.coerce(service, report_issues=True) + + topology_.validate_capabilities(service) + topology_.assign_hosts(service) + topology_.configure_operations(service) + topology_.coerce(service, report_issues=True) + if topology_.dump_issues(): + raise exceptions.InstantiationError('Failed to instantiate service template `{0}`' + .format(service_template.name)) + + storage_session.flush() # flushing so service.id would auto-populate + service.name = service_name or '{0}_{1}'.format(service_template.name, service.id) + self.model_storage.service.put(service) + return service + + def delete_service(self, service_id, force=False): + service = self.model_storage.service.get(service_id) + + active_executions = [e for e in service.executions if e.is_active()] + if active_executions: + raise exceptions.DependentActiveExecutionsError( + 'Can\'t delete service `{0}` - there is an active execution for this service. ' + 'Active execution ID: {1}'.format(service.name, active_executions[0].id)) + + if not force: + available_nodes = [str(n.id) for n in service.nodes.itervalues() if n.is_available()] + if available_nodes: + raise exceptions.DependentAvailableNodesError( + 'Can\'t delete service `{0}` - there are available nodes for this service. ' + 'Available node IDs: {1}'.format(service.name, ', '.join(available_nodes))) + + self.model_storage.service.delete(service) + + @staticmethod + def _parse_service_template(service_template_path): + context = consumption.ConsumptionContext() + context.presentation.location = UriLocation(service_template_path) + # Most of the parser uses the topology package in order to manipulate the models. + # However, here we use the Consumer mechanism, but this should change in the future. + consumption.ConsumerChain( + context, + ( + consumption.Read, + consumption.Validate, + consumption.ServiceTemplate + )).consume() + if context.validation.dump_issues(): + raise exceptions.ParsingError('Failed to parse service template') + return context |