Merge "Add TOSCA networking features"
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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})
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
115
translator/hot/tosca/tosca_network_network.py
Normal file
115
translator/hot/tosca/tosca_network_network.py
Normal 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
|
||||
113
translator/hot/tosca/tosca_network_port.py
Normal file
113
translator/hot/tosca/tosca_network_port.py
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
41
translator/tests/data/tosca_one_server_one_network.yaml
Normal file
41
translator/tests/data/tosca_one_server_one_network.yaml
Normal 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
|
||||
|
||||
62
translator/tests/data/tosca_one_server_three_networks.yaml
Normal file
62
translator/tests/data/tosca_one_server_three_networks.yaml
Normal 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
|
||||
|
||||
36
translator/tests/data/tosca_server_on_existing_network.yaml
Normal file
36
translator/tests/data/tosca_server_on_existing_network.yaml
Normal 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
|
||||
|
||||
72
translator/tests/data/tosca_two_servers_one_network.yaml
Normal file
72
translator/tests/data/tosca_two_servers_one_network.yaml
Normal 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
|
||||
|
||||
228
translator/tests/test_network.py
Normal file
228
translator/tests/test_network.py
Normal 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)
|
||||
Reference in New Issue
Block a user