Fix host server assignment for resources with multi-node dependency

An additional check was introduced for determining the host node to
verify the type of relationship, and assign a node as host only if
a 'tosca.relationships.HostedOn' relationship exists between the
two nodes. A test case is also added.

Change-Id: Iec5d0f70b092dd2a09c514e0f28e638abdb25997
Closes-Bug: #1455263
This commit is contained in:
Vahid Hashemian 2015-05-14 15:57:05 -07:00
parent e2143adbf8
commit d98ecc8691
5 changed files with 253 additions and 14 deletions

View File

@ -157,9 +157,12 @@ class TranslateNodeTemplates(object):
# the TOSCA template
for node in self.nodetemplates:
for node_depend in node.related_nodes:
# if the source of dependency is a server, add dependency
# as properties.get_resource
if node_depend.type == 'tosca.nodes.Compute':
# 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 \
node.related[node_depend].type == \
node.type_definition.HOSTEDON:
self.hot_lookup[node].properties['server'] = \
{'get_resource': self.hot_lookup[node_depend].name}
# for all others, add dependency as depends_on

View File

@ -10,8 +10,10 @@
# License for the specific language governing permissions and limitations
# under the License.
import json
import os
from translator.common.utils import CompareUtils
from translator.hot.tosca_translator import TOSCATranslator
from translator.tests.base import TestCase
from translator.toscalib.tosca_template import ToscaTemplate
@ -48,7 +50,7 @@ class ToscaNetworkTest(TestCase):
}}
expected_resource_3 = {'type': 'OS::Neutron::Port',
'depends_on': ['my_network'],
'depends_on': ['my_server', 'my_network'],
'properties':
{'network': {'get_resource': 'my_network'}
}}
@ -67,7 +69,11 @@ class ToscaNetworkTest(TestCase):
self.assertEqual(resources.get('my_network'), expected_resource_1)
self.assertEqual(resources.get('my_network_subnet'),
expected_resource_2)
self.assertEqual(resources.get('my_port'), expected_resource_3)
diff = CompareUtils.diff_dicts(resources.get('my_port'),
expected_resource_3)
self.assertEqual({}, diff, '<difference> : ' +
json.dumps(diff, indent=4, separators=(', ', ': ')))
self.assertIn('properties', resources.get('my_server'))
self.assertIn('networks', resources.get('my_server').get('properties'))
@ -107,14 +113,20 @@ class ToscaNetworkTest(TestCase):
}}
expected_resource_3 = {'type': 'OS::Neutron::Port',
'depends_on': ['my_network'],
'depends_on': ['my_server', 'my_network'],
'properties':
{'network': {'get_resource': 'my_network'}
}}
expected_resource_4 = [{'port': {'get_resource': 'my_port'}}]
expected_resource_4 = {'type': 'OS::Neutron::Port',
'depends_on': ['my_server2', 'my_network'],
'properties':
{'network': {'get_resource': 'my_network'}
}}
expected_resource_5 = [{'port': {'get_resource': 'my_port2'}}]
expected_resource_5 = [{'port': {'get_resource': 'my_port'}}]
expected_resource_6 = [{'port': {'get_resource': 'my_port2'}}]
output_dict = translator.toscalib.utils.yamlparser.simple_parse(output)
@ -130,21 +142,29 @@ class ToscaNetworkTest(TestCase):
self.assertEqual(resources.get('my_network'), expected_resource_1)
self.assertEqual(resources.get('my_network_subnet'),
expected_resource_2)
self.assertEqual(resources.get('my_port'), expected_resource_3)
self.assertEqual(resources.get('my_port2'), expected_resource_3)
diff = CompareUtils.diff_dicts(resources.get('my_port'),
expected_resource_3)
self.assertEqual({}, diff, '<difference> : ' +
json.dumps(diff, indent=4, separators=(', ', ': ')))
diff = CompareUtils.diff_dicts(resources.get('my_port2'),
expected_resource_4)
self.assertEqual({}, diff, '<difference> : ' +
json.dumps(diff, indent=4, separators=(', ', ': ')))
self.assertIn('properties', resources.get('my_server'))
self.assertIn('networks', resources.get('my_server').get('properties'))
translated_resource = resources.get('my_server').\
get('properties').get('networks')
self.assertEqual(translated_resource, expected_resource_4)
self.assertEqual(translated_resource, expected_resource_5)
self.assertIn('properties', resources.get('my_server2'))
self.assertIn('networks', resources.get('my_server2').
get('properties'))
translated_resource = resources.get('my_server2').\
get('properties').get('networks')
self.assertEqual(translated_resource, expected_resource_5)
self.assertEqual(translated_resource, expected_resource_6)
def test_translate_server_existing_network(self):
'''TOSCA template with 1 server attached to existing network.'''
@ -210,7 +230,7 @@ class ToscaNetworkTest(TestCase):
}
expected_resource_port = {'type': 'OS::Neutron::Port',
'depends_on': [net_name],
'depends_on': ['my_server', net_name],
'properties':
{'network': {'get_resource': net_name}}}
@ -221,7 +241,12 @@ class ToscaNetworkTest(TestCase):
self.assertEqual(resources.get(net_name), expected_resource_net)
self.assertEqual(resources.get(subnet_name),
expected_resource_subnet)
self.assertEqual(resources.get(port_name), expected_resource_port)
diff = CompareUtils.diff_dicts(resources.get(port_name),
expected_resource_port)
self.assertEqual({}, diff, '<difference> : ' +
json.dumps(diff, indent=4,
separators=(', ', ': ')))
self.assertIn('properties', resources.get('my_server'))
self.assertIn('networks', resources.get('my_server').get('properties'))

View File

@ -44,3 +44,14 @@ class ToscaHotTranslationTest(TestCase):
{})
self.assertEqual({}, diff, '<difference> : ' +
json.dumps(diff, indent=4, separators=(', ', ': ')))
def test_hot_translate_host_assignment(self):
tosca_file = \
'../toscalib/tests/data/test_host_assignment.yaml'
hot_file = '../toscalib/tests/data/hot_output/' \
'hot_host_assignment.yaml'
diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
hot_file,
{})
self.assertEqual({}, diff, '<difference> : ' +
json.dumps(diff, indent=4, separators=(', ', ': ')))

View File

@ -0,0 +1,120 @@
heat_template_version: 2013-05-23
description: >
A template to test host assignment for translated hot resources.
It makes sure if a resource depends on multiple hosts only the
one with the "HostedOn" relationship is picked as the host. In
this template, the translated resource 'app_collectd_create_deploy'
would depend on 'logstash_server' and 'app_server'. But it would
have "HostedOn" relationship with 'app_server', and that server
would be its host.
parameters: {}
resources:
app_server:
type: OS::Nova::Server
properties:
flavor: m1.medium
image: ubuntu-software-config-os-init
key_name: userkey
user_data_format: SOFTWARE_CONFIG
logstash_server:
type: OS::Nova::Server
properties:
flavor: m1.medium
image: ubuntu-software-config-os-init
key_name: userkey
user_data_format: SOFTWARE_CONFIG
app_collectd_create_config:
type: OS::Heat::SoftwareConfig
properties:
config:
get_file: collectd/create.sh
group: script
app_collectd_create_deploy:
type: OS::Heat::SoftwareDeployment
properties:
config:
get_resource: app_collectd_create_config
server:
get_resource: app_server
depends_on:
- logstash_start_deploy
app_collectd_configure_config:
type: OS::Heat::SoftwareConfig
properties:
config:
get_file: collectd/config.py
group: script
app_collectd_configure_deploy:
type: OS::Heat::SoftwareDeployment
properties:
config:
get_resource: app_collectd_configure_config
input_values:
logstash_ip:
get_attr:
- logstash_server
- networks
- private
- 0
server:
get_resource: app_server
depends_on:
- app_collectd_create_deploy
app_collectd_start_config:
type: OS::Heat::SoftwareConfig
properties:
config:
get_file: collectd/start.sh
group: script
app_collectd_start_deploy:
type: OS::Heat::SoftwareDeployment
properties:
config:
get_resource: app_collectd_start_config
server:
get_resource: app_server
depends_on:
- app_collectd_configure_deploy
logstash_create_config:
type: OS::Heat::SoftwareConfig
properties:
config:
get_file: logstash/create.sh
group: script
logstash_create_deploy:
type: OS::Heat::SoftwareDeployment
properties:
config:
get_resource: logstash_create_config
server:
get_resource: logstash_server
logstash_start_config:
type: OS::Heat::SoftwareConfig
properties:
config:
get_file: logstash/start.sh
group: script
logstash_start_deploy:
type: OS::Heat::SoftwareDeployment
properties:
config:
get_resource: logstash_start_config
server:
get_resource: logstash_server
depends_on:
- logstash_create_deploy
outputs: {}

View File

@ -0,0 +1,80 @@
tosca_definitions_version: tosca_simple_yaml_1_0_0
description: >
A template to test host assignment for translated hot resources.
It makes sure if a resource depends on multiple hosts only the
one with the "HostedOn" relationship is picked as the host. In
this template, the translated resource 'app_collectd_create_deploy'
would depend on 'logstash_server' and 'app_server'. But it would
have "HostedOn" relationship with 'app_server', and that server
would be its host.
imports:
- custom_types/logstash.yaml
- custom_types/collectd.yaml
- custom_types/rsyslog.yaml
- custom_types/elasticsearch.yaml
dsl_definitions:
host_capabilities: &host_capabilities
# compute properties (flavor)
disk_size: 10 GB
num_cpus: 1
mem_size: 4096 MB
os_capabilities: &os_capabilities
architecture: x86_64
type: Linux
distribution: Ubuntu
version: 14.04
topology_template:
node_templates:
app_collectd:
type: tosca.nodes.SoftwareComponent.Collectd
requirements:
- host:
node: app_server
- log_endpoint:
node: logstash
capability: log_endpoint
relationship:
type: tosca.relationships.ConnectsTo
interfaces:
Configure:
pre_configure_target:
implementation: logstash/configure_collectd.py
interfaces:
tosca.interfaces.node.lifecycle.Standard:
create: collectd/create.sh
configure:
implementation: collectd/config.py
inputs:
logstash_ip: { get_attribute: [logstash_server, private_address] }
start: collectd/start.sh
logstash:
type: tosca.nodes.SoftwareComponent.Logstash
requirements:
- host:
node: logstash_server
interfaces:
tosca.interfaces.node.lifecycle.Standard:
create: logstash/create.sh
start: logstash/start.sh
app_server:
type: tosca.nodes.Compute
capabilities:
os:
properties: *os_capabilities
host:
properties: *host_capabilities
logstash_server:
type: tosca.nodes.Compute
capabilities:
os:
properties: *os_capabilities
host:
properties: *host_capabilities