Merge "Add TOSCA networking features"

This commit is contained in:
Jenkins
2015-04-09 15:20:15 +00:00
committed by Gerrit Code Review
15 changed files with 944 additions and 6 deletions

View File

@@ -12,9 +12,12 @@
# under the License.
import six
from translator.toscalib.functions import GetInput
from translator.toscalib.nodetemplate import NodeTemplate
from translator.toscalib.utils.gettextutils import _
SECTIONS = (TYPE, PROPERTIES, MEDADATA, DEPENDS_ON, UPDATE_POLICY,
DELETION_POLICY) = \
('type', 'properties', 'metadata',
@@ -40,11 +43,16 @@ class HotResource(object):
self.metadata = metadata
if depends_on:
self.depends_on = depends_on
self.depends_on_nodes = depends_on
else:
self.depends_on = []
self.depends_on_nodes = []
self.update_policy = update_policy
self.deletion_policy = deletion_policy
self.group_dependencies = {}
# if hide_resource is set to true, then this resource will not be
# generated in the output yaml.
self.hide_resource = False
def handle_properties(self):
# the property can hold a value or the intrinsic function get_input
@@ -133,6 +141,7 @@ class HotResource(object):
preceding_hot = deploy_lookup.get(preceding_op)
if preceding_hot:
hot.depends_on.append(preceding_hot)
hot.depends_on_nodes.append(preceding_hot)
group[preceding_hot] = hot
break
@@ -143,6 +152,9 @@ class HotResource(object):
return hot_resources
def handle_expansion(self):
pass
def handle_hosting(self):
# handle hosting server for the OS:HEAT::SoftwareDeployment
# from the TOSCA nodetemplate, traverse the relationship chain
@@ -228,3 +240,12 @@ class HotResource(object):
# if translation is needed for the particular attribute
raise Exception(_("No translation in TOSCA type {0} for attribute "
"{1}").format(self.nodetemplate.type, attribute))
def _get_tosca_props(self, properties):
tosca_props = {}
for prop in self.nodetemplate.properties:
if isinstance(prop.value, GetInput):
tosca_props[prop.name] = {'get_param': prop.value.input_name}
else:
tosca_props[prop.name] = prop.value
return tosca_props

View File

@@ -52,6 +52,7 @@ class HotTemplate(object):
# Resources
all_resources = {}
for resource in self.resources:
if not resource.hide_resource:
all_resources.update(resource.get_dict_output())
dict_output.update({self.RESOURCES: all_resources})

View File

@@ -47,7 +47,11 @@ IMAGES = {'ubuntu-software-config-os-init': {'architecture': 'x86_64',
'cirros-0.3.1-x86_64-uec': {'architecture': 'x86_64',
'type': 'Linux',
'distribution': 'CirrOS',
'version': '0.3.1'}}
'version': '0.3.1'},
'cirros-0.3.2-x86_64-uec': {'architecture': 'x86_64',
'type': 'Linux',
'distribution': 'CirrOS',
'version': '0.3.2'}}
class ToscaCompute(HotResource):
@@ -58,12 +62,14 @@ class ToscaCompute(HotResource):
def __init__(self, nodetemplate):
super(ToscaCompute, self).__init__(nodetemplate,
type='OS::Nova::Server')
# List with associated hot port resources with this server
self.assoc_port_resources = []
pass
def handle_properties(self):
self.properties = self.translate_compute_flavor_and_image(
self.properties.update(self.translate_compute_flavor_and_image(
self.nodetemplate.properties,
self.nodetemplate.get_capability('os'))
self.nodetemplate.get_capability('os')))
self.properties['user_data_format'] = 'SOFTWARE_CONFIG'
# TODO(anyone): handle user key
# hardcoded here for testing

View File

@@ -0,0 +1,115 @@
#
# 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
from translator.toscalib.common.exception import InvalidPropertyValueError
class ToscaNetwork(HotResource):
'''Translate TOSCA node type tosca.nodes.network.Network.'''
toscatype = 'tosca.nodes.network.Network'
SUBNET_SUFFIX = '_subnet'
NETWORK_PROPS = ['network_name', 'network_id', 'segmentation_id']
SUBNET_PROPS = ['ip_version', 'cidr', 'start_ip', 'end_ip', 'gateway_ip']
existing_resource_id = None
def __init__(self, nodetemplate):
super(ToscaNetwork, self).__init__(nodetemplate,
type='OS::Neutron::Net')
pass
def handle_properties(self):
tosca_props = self._get_tosca_props(self.nodetemplate.properties)
net_props = {}
for key, value in tosca_props.items():
if key in self.NETWORK_PROPS:
if key == 'network_name':
# If CIDR is specified network_name should
# be used as the name for the new network.
if 'cidr' in tosca_props.keys():
net_props['name'] = value
# If CIDR is not specified network_name will be used
# to lookup existing network. If network_id is specified
# together with network_name then network_id should be
# used to lookup the network instead
elif 'network_id' not in tosca_props.keys():
self.hide_resource = True
self.existing_resource_id = value
break
elif key == 'network_id':
self.hide_resource = True
self.existing_resource_id = value
break
elif key == 'segmentation_id':
net_props['segmentation_id'] = \
tosca_props['segmentation_id']
# Hardcode to vxlan for now until we add the network type
# and physical network to the spec.
net_props['value_specs'] = {'provider:segmentation_id':
value, 'provider:network_type':
'vxlan'}
self.properties = net_props
def handle_expansion(self):
# If the network resource should not be output (they are hidden),
# there is no need to generate subnet resource
if self.hide_resource:
return
tosca_props = self._get_tosca_props(self.nodetemplate.properties)
subnet_props = {}
ip_pool_start = None
ip_pool_end = None
for key, value in tosca_props.items():
if key in self.SUBNET_PROPS:
if key == 'start_ip':
ip_pool_start = value
elif key == 'end_ip':
ip_pool_end = value
elif key == 'dhcp_enabled':
subnet_props['enable_dhcp'] = value
else:
subnet_props[key] = value
if 'network_id' in tosca_props:
subnet_props['network'] = tosca_props['network_id']
else:
subnet_props['network'] = '{ get_resource: %s }' % (self.name)
# Handle allocation pools
# Do this only if both start_ip and end_ip are provided
# If one of them is missing throw an exception.
if ip_pool_start and ip_pool_end:
allocation_pool = {}
allocation_pool['start'] = ip_pool_start
allocation_pool['end'] = ip_pool_end
allocation_pools = [allocation_pool]
subnet_props['allocation_pools'] = allocation_pools
elif ip_pool_start:
raise InvalidPropertyValueError(what='start_ip')
elif ip_pool_end:
raise InvalidPropertyValueError(what='end_ip')
subnet_resource_name = self.name + self.SUBNET_SUFFIX
hot_resources = [HotResource(self.nodetemplate,
type='OS::Neutron::Subnet',
name=subnet_resource_name,
properties=subnet_props)]
return hot_resources

View File

@@ -0,0 +1,113 @@
#
# 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 ToscaNetworkPort(HotResource):
'''Translate TOSCA node type tosca.nodes.network.Port.'''
toscatype = 'tosca.nodes.network.Port'
def __init__(self, nodetemplate):
super(ToscaNetworkPort, self).__init__(nodetemplate,
type='OS::Neutron::Port')
# Default order
self.order = 0
pass
def _generate_networks_for_compute(self, port_resources):
'''Generate compute networks property list from the port resources.'''
networks = []
for resource in port_resources:
networks.append({'port': '{ get_resource: %s }' % (resource.name)})
return networks
def _insert_sorted_resource(self, resources, resource):
'''Insert a resource in the list of resources and keep the order.'''
lo = 0
hi = len(resources)
while lo < hi:
mid = (lo + hi) // 2
if resource.order < resources[mid].order:
hi = mid
else:
lo = mid + 1
resources.insert(lo, resource)
def handle_properties(self):
tosca_props = self._get_tosca_props(self.nodetemplate.properties)
port_props = {}
for key, value in tosca_props.items():
if key == 'ip_address':
fixed_ip = []
fixed_ip['ip_address'] = value
fixed_ip['subnet'] = ''
port_props['fixed_ips'] = [fixed_ip]
elif key == 'order':
self.order = value
#TODO(sdmonov). Need to implement the properties below
elif key == 'is_default':
pass
elif key == 'ip_range_start':
pass
elif key == 'ip_range_end':
pass
else:
port_props[key] = value
# Get the nodetype relationships
relationships = {relation.type: node for relation, node in
self.nodetemplate.relationships.items()}
# Check for LinksTo relations. If found add a network property with
# the network name into the port
links_to = None
if 'tosca.relationships.network.LinksTo' in relationships:
links_to = relationships['tosca.relationships.network.LinksTo']
network_resource = None
for hot_resource in self.depends_on_nodes:
if links_to.name == hot_resource.name:
network_resource = hot_resource
break
if network_resource.existing_resource_id:
port_props['network'] =\
str(network_resource.existing_resource_id)
self.depends_on = None
else:
port_props['network'] = '{ get_resource: %s }'\
% (links_to.name)
# Check for BindsTo relationship. If found add network to the networks
# property of the corresponding compute resource
binds_to = None
if 'tosca.relationships.network.BindsTo' in relationships:
binds_to = relationships['tosca.relationships.network.BindsTo']
compute_resource = None
for hot_resource in self.depends_on_nodes:
if binds_to.name == hot_resource.name:
compute_resource = hot_resource
break
if compute_resource:
port_resources = compute_resource.assoc_port_resources
self._insert_sorted_resource(port_resources, self)
#TODO(sdmonov). Using generate networks every time we add a
# network is not the fastest way to do the things. We should
# do this only once at the end.
networks = self._generate_networks_for_compute(port_resources)
compute_resource.properties['networks'] = networks
self.properties = port_props

View File

@@ -12,6 +12,7 @@
# under the License.
import six
from translator.hot.tosca.tosca_block_storage import ToscaBlockStorage
from translator.hot.tosca.tosca_block_storage_attachment import (
ToscaBlockStorageAttachment
@@ -19,6 +20,8 @@ from translator.hot.tosca.tosca_block_storage_attachment import (
from translator.hot.tosca.tosca_compute import ToscaCompute
from translator.hot.tosca.tosca_database import ToscaDatabase
from translator.hot.tosca.tosca_dbms import ToscaDbms
from translator.hot.tosca.tosca_network_network import ToscaNetwork
from translator.hot.tosca.tosca_network_port import ToscaNetworkPort
from translator.hot.tosca.tosca_nodejs import ToscaNodejs
from translator.hot.tosca.tosca_webserver import ToscaWebserver
from translator.hot.tosca.tosca_wordpress import ToscaWordpress
@@ -27,6 +30,7 @@ from translator.toscalib.functions import GetInput
from translator.toscalib.functions import GetProperty
from translator.toscalib.relationship_template import RelationshipTemplate
SECTIONS = (TYPE, PROPERTIES, REQUIREMENTS, INTERFACES, LIFECYCLE, INPUT) = \
('type', 'properties', 'requirements',
'interfaces', 'lifecycle', 'input')
@@ -51,7 +55,9 @@ TOSCA_TO_HOT_TYPE = {'tosca.nodes.Compute': ToscaCompute,
'tosca.nodes.Database': ToscaDatabase,
'tosca.nodes.WebApplication.WordPress': ToscaWordpress,
'tosca.nodes.BlockStorage': ToscaBlockStorage,
'tosca.nodes.SoftwareComponent.Nodejs': ToscaNodejs}
'tosca.nodes.SoftwareComponent.Nodejs': ToscaNodejs,
'tosca.nodes.network.Network': ToscaNetwork,
'tosca.nodes.network.Port': ToscaNetworkPort}
TOSCA_TO_HOT_REQUIRES = {'container': 'server', 'host': 'server',
'dependency': 'depends_on', "connects": 'depends_on'}
@@ -74,6 +80,17 @@ class TranslateNodeTemplates():
def translate(self):
return self._translate_nodetemplates()
def _recursive_handle_properties(self, resource):
'''Recursively handle the properties of the depens_on_nodes nodes.'''
# Use of hashtable (dict) here should be faster?
if resource in self.processed_resources:
return
self.processed_resources.append(resource)
for depend_on in resource.depends_on_nodes:
self._recursive_handle_properties(depend_on)
resource.handle_properties()
def _translate_nodetemplates(self):
suffix = 0
@@ -126,13 +143,29 @@ class TranslateNodeTemplates():
self.hot_lookup[node].depends_on.append(
self.hot_lookup[node_depend].top_of_chain())
self.hot_lookup[node].depends_on_nodes.append(
self.hot_lookup[node_depend].top_of_chain())
# handle hosting relationship
for resource in self.hot_resources:
resource.handle_hosting()
# handle built-in properties of HOT resources
# if a resource depends on other resources,
# their properties needs to be handled first.
# Use recursion to handle the properties of the
# dependent nodes in correct order
self.processed_resources = []
for resource in self.hot_resources:
resource.handle_properties()
self._recursive_handle_properties(resource)
# handle resources that need to expand to more then one HOT resource
expansion_resources = []
for resource in self.hot_resources:
expanded = resource.handle_expansion()
if expanded:
expansion_resources += expanded
self.hot_resources += expansion_resources
# Resolve function calls: GetProperty, GetAttribute, GetInput
# at this point, all the HOT resources should have been created

View File

@@ -0,0 +1,43 @@
heat_template_version: 2013-05-23
description: >
TOSCA simple profile with 1 network and 1 attached server
outputs: {}
parameters:
network_name:
default: net1
description: Network name
type: string
resources:
my_network:
properties:
name:
get_param: network_name
type: OS::Neutron::Net
my_network_subnet:
properties:
allocation_pools:
- end: 192.168.0.200
start: 192.168.0.50
cidr: 192.168.0.0/24
gateway_ip: 192.168.0.1
ip_version: 4
network: { get_resource: my_network}
type: OS::Neutron::Subnet
my_port:
depends_on:
- my_network
properties:
network: { get_resource: my_network}
type: OS::Neutron::Port
my_server:
properties:
flavor: m1.small
image: cirros-0.3.2-x86_64-uec
key_name: userkey
networks:
- port: { get_resource: my_port}
user_data_format: SOFTWARE_CONFIG
type: OS::Nova::Server

View File

@@ -0,0 +1,68 @@
heat_template_version: 2013-05-23
description: >
TOSCA simple profile with 3 networks and 1 attached server
outputs: {}
parameters: {}
resources:
my_network1:
properties:
name: net1
type: OS::Neutron::Net
my_network1_subnet:
properties:
cidr: 192.168.1.0/24
ip_version: 4
network: { get_resource: my_network1 }
type: OS::Neutron::Subnet
my_network2:
properties:
name: net2
type: OS::Neutron::Net
my_network2_subnet:
properties:
cidr: 192.168.2.0/24
ip_version: 4
network: { get_resource: my_network2 }
type: OS::Neutron::Subnet
my_network3:
properties:
name: net3
type: OS::Neutron::Net
my_network3_subnet:
properties:
cidr: 192.168.3.0/24
ip_version: 4
network: { get_resource: my_network3 }
type: OS::Neutron::Subnet
my_port1:
depends_on:
- my_network1
properties:
network: { get_resource: my_network1 }
type: OS::Neutron::Port
my_port2:
depends_on:
- my_network2
properties:
network: { get_resource: my_network2 }
type: OS::Neutron::Port
my_port3:
depends_on:
- my_network3
properties:
network: { get_resource: my_network3 }
type: OS::Neutron::Port
my_server:
properties:
flavor: m1.small
image: cirros-0.3.2-x86_64-uec
key_name: userkey
networks:
- port: { get_resource: my_port1 }
- port: { get_resource: my_port2 }
- port: { get_resource: my_port3 }
user_data_format: SOFTWARE_CONFIG
type: OS::Nova::Server

View File

@@ -0,0 +1,27 @@
heat_template_version: 2013-05-23
description: >
TOSCA simple profile with 1 server attached to existing network
outputs: {}
parameters:
network_name:
default: net1
description: Network name
type: string
resources:
my_port:
properties:
network: {get_param: network_name}
type: OS::Neutron::Port
my_server:
properties:
flavor: m1.small
image: cirros-0.3.2-x86_64-uec
key_name: userkey
networks:
- port:
Ref: my_port
user_data_format: SOFTWARE_CONFIG
type: OS::Nova::Server

View File

@@ -0,0 +1,72 @@
heat_template_version: 2013-05-23
description: >
TOSCA simple profile with 1 network and 2 attached servers
outputs: {}
parameters:
network_cidr:
default: 10.0.0.0/24
description: CIDR for the network
type: string
network_end_ip:
default: 10.0.0.150
description: End IP for the allocation pool
type: string
network_name:
default: net1
description: Network name
type: string
network_start_ip:
default: 10.0.0.100
description: Start IP for the allocation pool
type: string
resources:
my_network:
properties:
name:
get_param: network_name
type: OS::Neutron::Net
my_network_subnet:
properties:
allocation_pools:
- end:
get_param: network_end_ip
start:
get_param: network_start_ip
cidr:
get_param: network_cidr
ip_version: 4
network: { get_resource: my_network}
type: OS::Neutron::Subnet
my_port:
depends_on:
- my_network
properties:
network: { get_resource: my_network}
type: OS::Neutron::Port
my_port2:
depends_on:
- my_network
properties:
network: { get_resource: my_network}
type: OS::Neutron::Port
my_server:
properties:
flavor: m1.small
image: cirros-0.3.2-x86_64-uec
key_name: userkey
networks:
- port: { get_resource: my_port}
user_data_format: SOFTWARE_CONFIG
type: OS::Nova::Server
my_server2:
properties:
flavor: m1.small
image: cirros-0.3.2-x86_64-uec
key_name: userkey
networks:
- port: { get_resource: my_port2}
user_data_format: SOFTWARE_CONFIG
type: OS::Nova::Server

View File

@@ -0,0 +1,41 @@
tosca_definitions_version: tosca_simple_yaml_1_0_0
description: >
TOSCA simple profile with 1 network and 1 attached server
inputs:
network_name:
type: string
description: Network name
node_templates:
my_server:
type: tosca.nodes.Compute
properties:
disk_size: 10
num_cpus: 1
mem_size: 512
capabilities:
os:
properties:
architecture: x86_64
type: Linux
distribution: CirrOS
version: 0.3.2
my_network:
type: tosca.nodes.network.Network
properties:
ip_version: 4
cidr: '192.168.0.0/24'
network_name: { get_input: network_name }
start_ip: '192.168.0.50'
end_ip: '192.168.0.200'
gateway_ip: '192.168.0.1'
my_port:
type: tosca.nodes.network.Port
requirements:
- binding: my_server
- link: my_network

View File

@@ -0,0 +1,62 @@
tosca_definitions_version: tosca_simple_yaml_1_0_0
description: >
TOSCA simple profile with 3 networks and 1 attached server
node_templates:
my_server:
type: tosca.nodes.Compute
properties:
disk_size: 10
num_cpus: 1
mem_size: 512
capabilities:
os:
properties:
architecture: x86_64
type: Linux
distribution: CirrOS
version: 0.3.2
my_network1:
type: tosca.nodes.network.Network
properties:
cidr: '192.168.1.0/24'
network_name: net1
my_network2:
type: tosca.nodes.network.Network
properties:
cidr: '192.168.2.0/24'
network_name: net2
my_network3:
type: tosca.nodes.network.Network
properties:
cidr: '192.168.3.0/24'
network_name: net3
my_port1:
type: tosca.nodes.network.Port
properties:
order: 0
requirements:
- binding: my_server
- link: my_network1
my_port2:
type: tosca.nodes.network.Port
properties:
order: 1
requirements:
- binding: my_server
- link: my_network2
my_port3:
type: tosca.nodes.network.Port
properties:
order: 2
requirements:
- binding: my_server
- link: my_network3

View File

@@ -0,0 +1,36 @@
tosca_definitions_version: tosca_simple_yaml_1_0_0
description: >
TOSCA simple profile with 1 server attached to existing network
inputs:
network_name:
type: string
description: Network name
node_templates:
my_server:
type: tosca.nodes.Compute
properties:
disk_size: 10
num_cpus: 1
mem_size: 512
capabilities:
os:
properties:
architecture: x86_64
type: Linux
distribution: CirrOS
version: 0.3.2
my_network:
type: tosca.nodes.network.Network
properties:
network_name: { get_input: network_name }
my_port:
type: tosca.nodes.network.Port
requirements:
- binding: my_server
- link: my_network

View File

@@ -0,0 +1,72 @@
tosca_definitions_version: tosca_simple_yaml_1_0_0
description: >
TOSCA simple profile with 1 network and 2 attached servers
inputs:
network_name:
type: string
description: Network name
network_cidr:
type: string
default: 10.0.0.0/24
description: CIDR for the network
network_start_ip:
type: string
default: 10.0.0.100
description: Start IP for the allocation pool
network_end_ip:
type: string
default: 10.0.0.150
description: End IP for the allocation pool
node_templates:
my_server:
type: tosca.nodes.Compute
properties:
disk_size: 10
num_cpus: 1
mem_size: 512
capabilities:
os:
properties:
architecture: x86_64
type: Linux
distribution: CirrOS
version: 0.3.2
my_server2:
type: tosca.nodes.Compute
properties:
disk_size: 10
num_cpus: 1
mem_size: 512
capabilities:
os:
properties:
architecture: x86_64
type: Linux
distribution: CirrOS
version: 0.3.2
my_network:
type: tosca.nodes.network.Network
properties:
ip_version: 4
cidr: { get_input: network_cidr }
network_name: { get_input: network_name }
start_ip: { get_input: network_start_ip }
end_ip: { get_input: network_end_ip }
my_port:
type: tosca.nodes.network.Port
requirements:
- binding: my_server
- link: my_network
my_port2:
type: tosca.nodes.network.Port
requirements:
- binding: my_server2
- link: my_network

View File

@@ -0,0 +1,228 @@
# 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 os
from translator.hot.tosca_translator import TOSCATranslator
from translator.tests.base import TestCase
from translator.toscalib.tosca_template import ToscaTemplate
import translator.toscalib.utils.yamlparser
class ToscaNetworkTest(TestCase):
parsed_params = {'network_name': 'net1'}
def test_translate_single_network_single_server(self):
'''TOSCA template with single Network and single Compute.'''
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'data/tosca_one_server_one_network.yaml')
tosca = ToscaTemplate(tosca_tpl)
translate = TOSCATranslator(tosca, self.parsed_params)
output = translate.translate()
expected_resource_1 = {'type': 'OS::Neutron::Net',
'properties':
{'name': {'get_param': 'network_name'}
}}
expected_resource_2 = {'type': 'OS::Neutron::Subnet',
'properties':
{'cidr': '192.168.0.0/24',
'ip_version': 4,
'allocation_pools': [{'start': '192.168.0.50',
'end': '192.168.0.200'}],
'gateway_ip': '192.168.0.1',
'network': {'get_resource': 'my_network'}
}}
expected_resource_3 = {'type': 'OS::Neutron::Port',
'depends_on': ['my_network'],
'properties':
{'network': {'get_resource': 'my_network'}
}}
expected_resource_4 = [{'port': {'get_resource': 'my_port'}}]
output_dict = translator.toscalib.utils.yamlparser.simple_parse(output)
resources = output_dict.get('resources')
self.assertIn('my_network', resources.keys())
self.assertIn('my_network_subnet', resources.keys())
self.assertIn('my_port', resources.keys())
self.assertIn('my_server', resources.keys())
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.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)
def test_translate_single_network_two_computes(self):
'''TOSCA template with single Network and two Computes.'''
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'data/tosca_two_servers_one_network.yaml')
tosca = ToscaTemplate(tosca_tpl)
translate = TOSCATranslator(tosca, self.parsed_params)
output = translate.translate()
expected_resource_1 = {'type': 'OS::Neutron::Net',
'properties':
{'name': {'get_param': 'network_name'}
}}
expected_resource_2 = {'type': 'OS::Neutron::Subnet',
'properties':
{'cidr': {'get_param': 'network_cidr'},
'ip_version': 4,
'allocation_pools': [{'start': {'get_param':
'network_start_ip'},
'end': {'get_param':
'network_end_ip'
}}],
'network': {'get_resource': 'my_network'}
}}
expected_resource_3 = {'type': 'OS::Neutron::Port',
'depends_on': ['my_network'],
'properties':
{'network': {'get_resource': 'my_network'}
}}
expected_resource_4 = [{'port': {'get_resource': 'my_port'}}]
expected_resource_5 = [{'port': {'get_resource': 'my_port2'}}]
output_dict = translator.toscalib.utils.yamlparser.simple_parse(output)
resources = output_dict.get('resources')
self.assertIn('my_network', resources.keys())
self.assertIn('my_network_subnet', resources.keys())
self.assertIn('my_port', resources.keys())
self.assertIn('my_port2', resources.keys())
self.assertIn('my_server', resources.keys())
self.assertIn('my_server2', resources.keys())
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)
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.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)
def test_translate_server_existing_network(self):
'''TOSCA template with 1 server attached to existing network.'''
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'data/tosca_server_on_existing_network.yaml')
tosca = ToscaTemplate(tosca_tpl)
translate = TOSCATranslator(tosca, self.parsed_params)
output = translate.translate()
expected_resource_1 = {'type': 'OS::Neutron::Port',
'properties':
{'network': {'get_param': 'network_name'}
}}
expected_resource_2 = [{'port': {'get_resource': 'my_port'}}]
output_dict = translator.toscalib.utils.yamlparser.simple_parse(output)
resources = output_dict.get('resources')
self.assertItemsEqual(resources.keys(), ['my_server', 'my_port'])
self.assertEqual(resources.get('my_port'), expected_resource_1)
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_2)
def test_translate_three_networks_single_server(self):
'''TOSCA template with three Networks and single Compute.'''
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'data/tosca_one_server_three_networks.yaml')
tosca = ToscaTemplate(tosca_tpl)
translate = TOSCATranslator(tosca, self.parsed_params)
output = translate.translate()
output_dict = translator.toscalib.utils.yamlparser.simple_parse(output)
resources = output_dict.get('resources')
for net_num in range(1, 4):
net_name = 'my_network%d' % (net_num)
subnet_name = '%s_subnet' % (net_name)
port_name = 'my_port%d' % (net_num)
expected_resource_net = {'type': 'OS::Neutron::Net',
'properties':
{'name': 'net%d' % (net_num)
}}
expected_resource_subnet = {'type': 'OS::Neutron::Subnet',
'properties':
{'cidr': '192.168.%d.0/24' % (net_num),
'ip_version': 4,
'network': {'get_resource': net_name}
}}
expected_resource_port = {'type': 'OS::Neutron::Port',
'depends_on': [net_name],
'properties':
{'network': {'get_resource': net_name}
}}
self.assertIn(net_name, resources.keys())
self.assertIn(subnet_name, resources.keys())
self.assertIn(port_name, resources.keys())
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)
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')
expected_srv_networks = [{'port': {'get_resource': 'my_port1'}},
{'port': {'get_resource': 'my_port2'}},
{'port': {'get_resource': 'my_port3'}}]
self.assertEqual(translated_resource, expected_srv_networks)