murano/contrib/plugins/cloudify_plugin/murano_cloudify_plugin/cloudify_tosca_package.py

188 lines
5.7 KiB
Python

# Licensed 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.
import six
import yaml
from murano.common.helpers import path
from murano.packages import exceptions
from murano.packages import package_base
RESOURCES_DIR_NAME = 'Resources/'
class YAQL(object):
def __init__(self, expr):
self.expr = expr
class Dumper(yaml.SafeDumper):
pass
def yaql_representer(dumper, data):
return dumper.represent_scalar(u'!yaql', data.expr)
Dumper.add_representer(YAQL, yaql_representer)
class CloudifyToscaPackage(package_base.PackageBase):
def __init__(self, format_name, runtime_version, source_directory,
manifest):
super(CloudifyToscaPackage, self).__init__(
format_name, runtime_version, source_directory, manifest)
self._entry_point = manifest.get('EntryPoint', 'main.yaml')
self._generated_class = None
self._generated_ui = None
@property
def classes(self):
return self.full_name,
@property
def requirements(self):
return {
'org.getcloudify.murano': '0'
}
@property
def ui(self):
if not self._generated_ui:
self._generated_ui = self._generate_ui()
return self._generated_ui
def get_class(self, name):
if name != self.full_name:
raise exceptions.PackageClassLoadError(
name, 'Class not defined in this package')
if not self._generated_class:
self._generated_class = self._generate_class()
return self._generated_class, '<generated code>'
def _generate_class(self):
inputs, outputs = self._get_inputs_outputs()
class_code = {
'Name': self.full_name,
'Extends': 'org.getcloudify.murano.CloudifyApplication',
'Properties': self._generate_properties(inputs, outputs),
'Methods': {
'describe': self._generate_describe_method(inputs),
'updateOutputs': self._generate_update_outputs_method(outputs)
}
}
return yaml.dump(class_code, Dumper=Dumper, default_style='"')
@staticmethod
def _generate_properties(inputs, outputs):
contracts = {}
for name, value in six.iteritems(inputs):
prop = {
'Contract': YAQL('$.string().notNull()'),
'Usage': 'In'
}
if 'default' in value:
prop['Default'] = value['default']
contracts[name] = prop
for name in six.iterkeys(outputs):
contracts[name] = {
'Contract': YAQL('$.string()'),
'Usage': 'Out'
}
return contracts
def _generate_describe_method(self, inputs):
input_values = {
name: YAQL('$.' + name)
for name in six.iterkeys(inputs)
}
return {
'Body': [{
'Return': {
'entryPoint': self._entry_point,
'inputs': input_values
}
}]
}
@staticmethod
def _generate_update_outputs_method(outputs):
assignments = [
{YAQL('$.' + name): YAQL('$outputs.get({0})'.format(name))}
for name in six.iterkeys(outputs)
]
return {
'Arguments': [{
'outputs': {
'Contract': {
YAQL('$.string().notNull()'): YAQL('$')
}
}
}],
'Body': assignments
}
def _get_inputs_outputs(self):
entry_point_path = path.secure_join(
self.source_directory, RESOURCES_DIR_NAME, self._entry_point)
with open(entry_point_path) as blueprint:
data = yaml.safe_load(blueprint)
return data.get('inputs') or {}, data.get('outputs') or {}
def _generate_application_ui_section(self, inputs, package_name=None,
package_version=None):
section = {
key: YAQL(
'$.appConfiguration.' + key) for key in six.iterkeys(inputs)
}
section.update({
'?': {
'type': self.full_name
}
})
if package_name:
section['?']['package'] = package_name
if package_version:
section['?']['classVersion'] = package_version
return section
@staticmethod
def _generate_form_ui_section(inputs):
fields = [
{
'name': key,
'label': key.title().replace('_', ' '),
'type': 'string',
'required': True,
'description': value.get('description', key)
} for key, value in six.iteritems(inputs)
]
return [{
'appConfiguration': {
'fields': fields
}
}]
def _generate_ui(self):
inputs, outputs = self._get_inputs_outputs()
ui = {
'Version': '2.2',
'Application': self._generate_application_ui_section(
inputs, self.full_name, str(self.version)),
'Forms': self._generate_form_ui_section(inputs)
}
return yaml.dump(ui, Dumper=Dumper, default_style='"')