TOSCA generator translation for individual TOSCA type.

Each TOSCA abstract type is handled by a separate generator. These contain the
necessary logic to implement the abstract type as concrete Heat resource type.
In this set, only the server type requires custom handling.
All the other types are software config and are handled by the super class.
The WordPress type is a custom type and will be moved to a separate place

Partially implements blueprint heat-translator-tosca
Change-Id: Ida687e6eed53e1edfdc611bc3d27704d9d9f3d67
O
This commit is contained in:
Ton Ngo 2014-06-10 12:20:16 -07:00
parent 89c397901c
commit 40a9ce5629
6 changed files with 249 additions and 0 deletions

View File

View File

@ -0,0 +1,138 @@
#
# 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.
from translator.hot.syntax.hot_resource import HotResource
# A design issue to be resolved is how to translate the generic TOSCA server
# properties to OpenStack flavors and images. At the Atlanta design summit,
# there was discussion on using Glance to store metadata and Graffiti to
# describe artifacts. We will follow these projects to see if they can be
# leveraged for this TOSCA translation.
# For development purpose at this time, we temporarily hardcode a list of
# flavors and images here
FLAVORS = {'m1.xlarge': {'mem_size': 16384, 'disk_size': 160, 'num_cpus': 8},
'm1.large': {'mem_size': 8192, 'disk_size': 80, 'num_cpus': 4},
'm1.medium': {'mem_size': 4096, 'disk_size': 40, 'num_cpus': 2},
'm1.small': {'mem_size': 2048, 'disk_size': 20, 'num_cpus': 1},
'm1.tiny': {'mem_size': 512, 'disk_size': 1, 'num_cpus': 1},
'm1.micro': {'mem_size': 128, 'disk_size': 0, 'num_cpus': 1},
'm1.nano': {'mem_size': 64, 'disk_size': 0, 'num_cpus': 1}}
IMAGES = {'fedora-amd64-heat-config': {'os_arch': 'x86_64',
'os_type': 'Linux',
'os_distribution': 'Fedora',
'os_version': '18'},
'F18-x86_64-cfntools': {'os_arch': 'x86_64',
'os_type': 'Linux',
'os_distribution': 'Fedora',
'os_version': '19'},
'Fedora-x86_64-20-20131211.1-sda': {'os_arch': 'x86_64',
'os_type': 'Linux',
'os_distribution': 'Fedora',
'os_version': '20'},
'cirros-0.3.1-x86_64-uec': {'os_arch': 'x86_64',
'os_type': 'Linux',
'os_distribution': 'CirrOS',
'os_version': '0.3.1'}}
class ToscaCompute(HotResource):
'''Translate TOSCA node type tosca.nodes.Compute.'''
toscatype = 'tosca.nodes.Compute'
def __init__(self, nodetemplate):
super(ToscaCompute, self).__init__(nodetemplate,
type='OS::Nova::Server')
pass
def handle_properties(self):
self.properties = self.translate_compute_flavor_and_image(
self.nodetemplate.properties)
self.properties['user_data_format'] = 'SOFTWARE_CONFIG'
# TODO(anyone): handle user key
# hardcoded here for testing
self.properties['key_name'] = 'userkey'
# To be reorganized later based on new development in Glance and Graffiti
def translate_compute_flavor_and_image(self, properties):
hot_properties = {}
tosca_props = {}
for prop in properties:
tosca_props[prop.name] = prop.value
flavor = self._best_flavor(tosca_props)
image = self._best_image(tosca_props)
hot_properties['flavor'] = flavor
hot_properties['image'] = image
# TODO(anyone): consider adding the flavor or image as a template
# parameter if no match is found.
return hot_properties
def _best_flavor(self, properties):
# start with all flavors
match_all = FLAVORS.keys()
# TODO(anyone): Handle the case where the value contains something like
# get_input instead of a value.
# flavors that fit the CPU count
cpu = properties.get('num_cpus')
match_cpu = self._match_flavors(match_all, FLAVORS, 'num_cpus', cpu)
# flavors that fit the mem size
mem = properties.get('mem_size')
match_cpu_mem = self._match_flavors(match_cpu, FLAVORS,
'mem_size', mem)
# flavors that fit the disk size
disk = properties.get('disk_size')
match_cpu_mem_disk = self._match_flavors(match_cpu_mem, FLAVORS,
'disk_size', disk)
# for now just pick the first flavor
# the selection can be based on some heuristic, e.g. pick one with the
# least resource
if len(match_cpu_mem_disk):
return match_cpu_mem_disk[0]
def _best_image(self, properties):
match_all = IMAGES.keys()
os_arch = properties.get('os_arch')
match_arch = self._match_images(match_all, IMAGES, 'os_arch', os_arch)
os_type = properties.get('os_type')
match_type = self._match_images(match_arch, IMAGES, 'os_type', os_type)
os_distribution = properties.get('os_distribution')
match_distribution = self._match_images(match_type, IMAGES,
'os_distribution',
os_distribution)
os_version = properties.get('os_version')
match_version = self._match_images(match_distribution, IMAGES,
'os_version', os_version)
if len(match_version):
return match_version[0]
def _match_flavors(self, this_list, this_dict, attr, size):
if not size:
return this_list
matching_flavors = []
for flavor in this_list:
if this_dict[flavor][attr] >= size:
matching_flavors.append(flavor)
return matching_flavors
def _match_images(self, this_list, this_dict, attr, prop):
if not prop:
return this_list
matching_images = []
for image in this_list:
if this_dict[image][attr] == str(prop):
matching_images.append(image)
return matching_images

View File

@ -0,0 +1,27 @@
#
# 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.
from translator.hot.syntax.hot_resource import HotResource
class ToscaDatabase(HotResource):
'''Translate TOSCA node type tosca.nodes.Database.'''
toscatype = 'tosca.nodes.Database'
def __init__(self, nodetemplate):
super(ToscaDatabase, self).__init__(nodetemplate)
pass
def handle_properties(self):
pass

View File

@ -0,0 +1,27 @@
#
# 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.
from translator.hot.syntax.hot_resource import HotResource
class ToscaDbms(HotResource):
'''Translate TOSCA node type tosca.nodes.DBMS.'''
toscatype = 'tosca.nodes.DBMS'
def __init__(self, nodetemplate):
super(ToscaDbms, self).__init__(nodetemplate)
pass
def handle_properties(self):
pass

View File

@ -0,0 +1,27 @@
#
# 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.
from translator.hot.syntax.hot_resource import HotResource
class ToscaWebserver(HotResource):
'''Translate TOSCA node type tosca.nodes.WebServer.'''
toscatype = 'tosca.nodes.WebServer'
def __init__(self, nodetemplate):
super(ToscaWebserver, self).__init__(nodetemplate)
pass
def handle_properties(self):
pass

View File

@ -0,0 +1,30 @@
#
# 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.
from translator.hot.syntax.hot_resource import HotResource
class ToscaWordpress(HotResource):
'''Translate TOSCA node type tosca.nodes.WebApplication.WordPress.'''
# TODO(anyone): this is a custom TOSCA type so it should be kept separate
# from the TOSCA base types; need to come up with a scheme so new custom
# types can be added by users.
toscatype = 'tosca.nodes.WebApplication.WordPress'
def __init__(self, nodetemplate):
super(ToscaWordpress, self).__init__(nodetemplate)
pass
def handle_properties(self):
pass