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
8 # http://www.apache.org/licenses/LICENSE-2.0
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.
20 from . import exceptions
21 from .parser import consumption
22 from .parser.loading.location import UriLocation
23 from .orchestrator import topology
32 self._model_storage = model_storage
33 self._resource_storage = resource_storage
34 self._plugin_manager = plugin_manager
37 def model_storage(self):
38 return self._model_storage
41 def resource_storage(self):
42 return self._resource_storage
45 def plugin_manager(self):
46 return self._plugin_manager
48 def validate_service_template(self, service_template_path):
49 self._parse_service_template(service_template_path)
51 def create_service_template(self, service_template_path, service_template_dir,
52 service_template_name):
53 context = self._parse_service_template(service_template_path)
54 service_template = context.modeling.template
55 service_template.name = service_template_name
56 self.model_storage.service_template.put(service_template)
57 self.resource_storage.service_template.upload(
58 entry_id=str(service_template.id), source=service_template_dir)
59 return service_template.id
61 def delete_service_template(self, service_template_id):
62 service_template = self.model_storage.service_template.get(service_template_id)
63 if service_template.services:
64 raise exceptions.DependentServicesError(
65 'Can\'t delete service template `{0}` - service template has existing services'
66 .format(service_template.name))
68 self.model_storage.service_template.delete(service_template)
69 self.resource_storage.service_template.delete(entry_id=str(service_template.id))
71 def create_service(self, service_template_id, inputs, service_name=None):
72 service_template = self.model_storage.service_template.get(service_template_id)
74 storage_session = self.model_storage._all_api_kwargs['session']
75 # setting no autoflush for the duration of instantiation - this helps avoid dependency
76 # constraints as they're being set up
77 with storage_session.no_autoflush:
78 topology_ = topology.Topology()
79 service = topology_.instantiate(
80 service_template, inputs=inputs, plugins=self.model_storage.plugin.list())
81 topology_.coerce(service, report_issues=True)
83 topology_.validate(service)
84 topology_.satisfy_requirements(service)
85 topology_.coerce(service, report_issues=True)
87 topology_.validate_capabilities(service)
88 topology_.assign_hosts(service)
89 topology_.configure_operations(service)
90 topology_.coerce(service, report_issues=True)
91 if topology_.dump_issues():
92 raise exceptions.InstantiationError('Failed to instantiate service template `{0}`'
93 .format(service_template.name))
95 storage_session.flush() # flushing so service.id would auto-populate
96 service.name = service_name or '{0}_{1}'.format(service_template.name, service.id)
97 self.model_storage.service.put(service)
100 def delete_service(self, service_id, force=False):
101 service = self.model_storage.service.get(service_id)
103 active_executions = [e for e in service.executions if e.is_active()]
104 if active_executions:
105 raise exceptions.DependentActiveExecutionsError(
106 'Can\'t delete service `{0}` - there is an active execution for this service. '
107 'Active execution ID: {1}'.format(service.name, active_executions[0].id))
110 available_nodes = [str(n.id) for n in service.nodes.itervalues() if n.is_available()]
112 raise exceptions.DependentAvailableNodesError(
113 'Can\'t delete service `{0}` - there are available nodes for this service. '
114 'Available node IDs: {1}'.format(service.name, ', '.join(available_nodes)))
116 self.model_storage.service.delete(service)
119 def _parse_service_template(service_template_path):
120 context = consumption.ConsumptionContext()
121 context.presentation.location = UriLocation(service_template_path)
122 # Most of the parser uses the topology package in order to manipulate the models.
123 # However, here we use the Consumer mechanism, but this should change in the future.
124 consumption.ConsumerChain(
128 consumption.Validate,
129 consumption.ServiceTemplate
131 if context.validation.dump_issues():
132 raise exceptions.ParsingError('Failed to parse service template')