Handle interfaces directly defined on a TOSCA Compute node.

Change-Id: I0b6f3c5bfb557bdbe16d22f89c4a9c7da4d6030e
This commit is contained in:
Mathieu Velten 2016-04-11 10:09:24 +02:00
parent 3b7fe1d7e4
commit 1267ad19c0
7 changed files with 166 additions and 13 deletions

View File

@ -141,14 +141,22 @@ class HotResource(object):
# hosting_server is None if requirements is None
hosting_on_server = (hosting_server.name if
hosting_server else None)
if operation.name == reserve_current:
base_type = HotResource.get_base_type(
self.nodetemplate.type_definition).type
# handle interfaces directly defined on a compute
if hosting_on_server is None \
and base_type == 'tosca.nodes.Compute':
hosting_on_server = self.name
if operation.name == reserve_current and \
base_type != 'tosca.nodes.Compute':
deploy_resource = self
self.name = deploy_name
self.type = 'OS::Heat::SoftwareDeployment'
self.properties = {'config': {'get_resource': config_name},
'server': {'get_resource':
hosting_on_server}}
deploy_lookup[operation.name] = self
deploy_lookup[operation] = self
else:
sd_config = {'config': {'get_resource': config_name},
'server': {'get_resource':
@ -159,7 +167,7 @@ class HotResource(object):
'OS::Heat::SoftwareDeployment',
sd_config)
hot_resources.append(deploy_resource)
deploy_lookup[operation.name] = deploy_resource
deploy_lookup[operation] = deploy_resource
lifecycle_inputs = self._get_lifecycle_inputs(operation)
if lifecycle_inputs:
deploy_resource.properties['input_values'] = \
@ -169,24 +177,34 @@ class HotResource(object):
# in operations_deploy_sequence
# TODO(anyone): find some better way to encode this implicit sequence
group = {}
op_index_max = -1
for op, hot in deploy_lookup.items():
# position to determine potential preceding nodes
op_index = operations_deploy_sequence.index(op)
for preceding_op in \
op_index = operations_deploy_sequence.index(op.name)
if op_index > op_index_max:
op_index_max = op_index
for preceding_op_name in \
reversed(operations_deploy_sequence[:op_index]):
preceding_hot = deploy_lookup.get(preceding_op)
preceding_hot = deploy_lookup.get(
operations.get(preceding_op_name))
if preceding_hot:
hot.depends_on.append(preceding_hot)
hot.depends_on_nodes.append(preceding_hot)
group[preceding_hot] = hot
break
if op_index_max >= 0:
last_deploy = deploy_lookup.get(operations.get(
operations_deploy_sequence[op_index_max]))
else:
last_deploy = None
# save this dependency chain in the set of HOT resources
self.group_dependencies.update(group)
for hot in hot_resources:
hot.group_dependencies.update(group)
return hot_resources
return hot_resources, deploy_lookup, last_deploy
def handle_connectsto(self, tosca_source, tosca_target, hot_source,
hot_target, config_location, operation):

View File

@ -50,4 +50,4 @@ class ToscaBlockStorageAttachment(HotResource):
self.properties.pop('device')
def handle_life_cycle(self):
pass
return None, None, None

View File

@ -84,6 +84,14 @@ class ToscaCompute(HotResource):
('architecture', 'distribution', 'type', 'version')
toscatype = 'tosca.nodes.Compute'
ALLOWED_NOVA_SERVER_PROPS = \
('admin_pass', 'availability_zone', 'block_device_mapping',
'block_device_mapping_v2', 'config_drive', 'diskConfig', 'flavor',
'flavor_update_policy', 'image', 'image_update_policy', 'key_name',
'metadata', 'name', 'networks', 'personality', 'reservation_id',
'scheduler_hints', 'security_groups', 'software_config_transport',
'user_data', 'user_data_format', 'user_data_update_policy')
def __init__(self, nodetemplate):
super(ToscaCompute, self).__init__(nodetemplate,
type='OS::Nova::Server')
@ -98,7 +106,8 @@ class ToscaCompute(HotResource):
self.properties['user_data_format'] = 'SOFTWARE_CONFIG'
tosca_props = self.get_tosca_props()
for key, value in tosca_props.items():
self.properties[key] = value
if key in self.ALLOWED_NOVA_SERVER_PROPS:
self.properties[key] = value
# To be reorganized later based on new development in Glance and Graffiti
def translate_compute_flavor_and_image(self,

View File

@ -146,6 +146,9 @@ class TranslateNodeTemplates(object):
log.debug(_('Mapping between TOSCA nodetemplate and HOT resource.'))
self.hot_lookup = {}
self.policies = self.tosca.topology_template.policies
# stores the last deploy of generated behavior for a resource
# useful to satisfy underlying dependencies between interfaces
self.last_deploy_map = {}
def translate(self):
return self._translate_nodetemplates()
@ -219,9 +222,14 @@ class TranslateNodeTemplates(object):
# into multiple HOT resources and may change their name
lifecycle_resources = []
for resource in self.hot_resources:
expanded = resource.handle_life_cycle()
if expanded:
lifecycle_resources += expanded
expanded_resources, deploy_lookup, last_deploy = resource.\
handle_life_cycle()
if expanded_resources:
lifecycle_resources += expanded_resources
if deploy_lookup:
self.hot_lookup.update(deploy_lookup)
if last_deploy:
self.last_deploy_map[resource] = last_deploy
self.hot_resources += lifecycle_resources
# Handle configuration from ConnectsTo relationship in the TOSCA node:
@ -253,7 +261,9 @@ class TranslateNodeTemplates(object):
# if the source of dependency is a server and the
# relationship type is 'tosca.relationships.HostedOn',
# add dependency as properties.server
if node_depend.type == 'tosca.nodes.Compute' and \
base_type = HotResource.get_base_type(
node_depend.type_definition)
if base_type.type == 'tosca.nodes.Compute' and \
node.related[node_depend].type == \
node.type_definition.HOSTEDON:
self.hot_lookup[node].properties['server'] = \
@ -266,6 +276,13 @@ class TranslateNodeTemplates(object):
self.hot_lookup[node].depends_on_nodes.append(
self.hot_lookup[node_depend].top_of_chain())
last_deploy = self.last_deploy_map.get(
self.hot_lookup[node_depend])
if last_deploy and \
last_deploy not in self.hot_lookup[node].depends_on:
self.hot_lookup[node].depends_on.append(last_deploy)
self.hot_lookup[node].depends_on_nodes.append(last_deploy)
# handle hosting relationship
for resource in self.hot_resources:
resource.handle_hosting()
@ -297,6 +314,17 @@ class TranslateNodeTemplates(object):
for name, value in six.iteritems(inputs):
inputs[name] = self._translate_input(value, resource)
# remove resources without type defined
# for example a SoftwareComponent without interfaces
# would fall in this case
to_remove = []
for resource in self.hot_resources:
if resource.type is None:
to_remove.append(resource)
for resource in to_remove:
self.hot_resources.remove(resource)
return self.hot_resources
def _translate_input(self, input_value, resource):

View File

@ -0,0 +1,44 @@
heat_template_version: 2013-05-23
description: >
TOSCA template to test Compute node with interface
parameters: {}
resources:
softwarecomponent_depending_on_customcompute_install_create_deploy:
type: OS::Heat::SoftwareDeployment
properties:
config:
get_resource: softwarecomponent_depending_on_customcompute_install_create_config
server:
get_resource: server
depends_on:
- server_create_deploy
server:
type: OS::Nova::Server
properties:
flavor: m1.small
image: ubuntu-12.04-software-config-os-init
user_data_format: SOFTWARE_CONFIG
softwarecomponent_depending_on_customcompute_install_create_config:
type: OS::Heat::SoftwareConfig
properties:
config:
get_file: post_install.sh
group: script
server_create_config:
type: OS::Heat::SoftwareConfig
properties:
config:
get_file: install.sh
group: script
server_create_deploy:
type: OS::Heat::SoftwareDeployment
properties:
config:
get_resource: server_create_config
input_values:
install_path: /opt
server:
get_resource: server
outputs: {}

View File

@ -0,0 +1,48 @@
tosca_definitions_version: tosca_simple_yaml_1_0
description: TOSCA template to test Compute node with interface
node_types:
tosca.nodes.CustomCompute:
derived_from: tosca.nodes.Compute
properties:
install_path:
type: string
default: /opt
interfaces:
Standard:
create:
implementation: install.sh
inputs:
install_path: { get_property: [ SELF, install_path ] }
topology_template:
node_templates:
softwarecomponent_without_behavior:
type: tosca.nodes.SoftwareComponent
requirements:
- host: server
softwarecomponent_depending_on_customcompute_install:
type: tosca.nodes.SoftwareComponent
interfaces:
Standard:
create:
implementation: post_install.sh
requirements:
- host: server
server:
type: tosca.nodes.CustomCompute
capabilities:
host:
properties:
num_cpus: 1
mem_size: 1 GB
os:
properties:
type: Linux
distribution: Ubuntu
version: 12.04
architecture: x86_64

View File

@ -471,3 +471,9 @@ class ToscaHotTranslationTest(TestCase):
hot_file = '../tests/data/hot_output/hot_script_types.yaml'
params = {}
self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_interface_on_compute(self):
tosca_file = '../tests/data/test_tosca_interface_on_compute.yaml'
hot_file = '../tests/data/hot_output/hot_interface_on_compute.yaml'
params = {}
self._test_successful_translation(tosca_file, hot_file, params)