Add TOSCA networking definiton

1. Add the TOSCA networking features definiton to TOSCA_definition.yaml:
  - tosca.nodes.network.Network
  - tosca.nodes.network.Port
  - tosca.capabilities.network.Linkable
  - tosca.capabilities.network.Bindable
  - tosca.relations.network.LinksTo
  - tosca.relations.network.BindsTo

2. Add support for implicit declaration of requirements by type.

For example:

tosca.nodes.network.Network:
  derived_from: tosca.nodes.Root
........
  requirements:
    - binding:
         type: tosca.capabilities.network.Bindable
    - link:
         type: tosca.capabilities.network.Linkable
........

Change-Id: I34c7c9091d05bff4641937fe72b56e7a7b57a1e6
Partially-implements: blueprint tosca-networking
This commit is contained in:
Simeon Monov
2015-02-17 20:30:04 +01:00
parent e43cf00688
commit 07ffe574af
5 changed files with 220 additions and 6 deletions

View File

@@ -86,6 +86,8 @@ tosca.nodes.Compute:
capabilities:
host:
type: tosca.capabilities.Container
binding:
type: tosca.capabilities.network.Bindable
requirements:
- attachment: tosca.nodes.BlockStorage
type: AttachTo
@@ -181,6 +183,133 @@ tosca.nodes.BlockStorage:
attachment:
type: tosca.capabilities.Attachment
tosca.nodes.network.Network:
derived_from: tosca.nodes.Root
description: >
The TOSCA Network node represents a simple, logical network service.
properties:
ip_version:
type: integer
required: no
default: 4
constraints:
- valid_values: [ 4, 6 ]
description: >
The IP version of the requested network. Valid values are 4 for ipv4
or 6 for ipv6.
cidr:
type: string
required: no
description: >
The cidr block of the requested network.
start_ip:
type: string
required: no
description: >
The IP address to be used as the start of a pool of addresses within
the full IP range derived from the cidr block.
end_ip:
type: string
required: no
description: >
The IP address to be used as the end of a pool of addresses within
the full IP range derived from the cidr block.
gateway_ip:
type: string
required: no
description: >
The gateway IP address.
network_name:
type: string
required: no
description: >
An identifier that represents an existing Network instance in the
underlying cloud infrastructure or can be used as the name of the
newly created network. If network_name is provided and no other
properties are provided (with exception of network_id), then an
existing network instance will be used. If network_name is provided
alongside with more properties then a new network with this name will
be created.
network_id:
type: string
required: no
description: >
An identifier that represents an existing Network instance in the
underlying cloud infrastructure. This property is mutually exclusive
with all other properties except network_name. This can be used alone
or together with network_name to identify an existing network.
segmentation_id:
type: string
required: no
description: >
A segmentation identifier in the underlying cloud infrastructure.
E.g. VLAN ID, GRE tunnel ID, etc..
dhcp_enabled:
type: boolean
required: no
default: true
description: >
Indicates should DHCP service be enabled on the network or not.
capabilities:
link:
type: tosca.capabilities.network.Linkable
tosca.nodes.network.Port:
derived_from: tosca.nodes.Root
description: >
The TOSCA Port node represents a logical entity that associates between
Compute and Network normative types. The Port node type effectively
represents a single virtual NIC on the Compute node instance.
properties:
ip_address:
type: string
required: no
description: >
Allow the user to set a static IP.
order:
type: integer
required: no
default: 0
constraints:
- greater_or_equal: 0
description: >
The order of the NIC on the compute instance (e.g. eth2).
is_default:
type: boolean
required: no
default: false
description: >
If is_default=true this port will be used for the default gateway
route. Only one port that is associated to single compute node can
set as is_default=true.
ip_range_start:
type: string
required: no
description: >
Defines the starting IP of a range to be allocated for the compute
instances that are associated with this Port.
ip_range_end:
type: string
required: no
description: >
Defines the ending IP of a range to be allocated for the compute
instances that are associated with this Port.
attributes:
ip_address:
type: string
requirements:
- binding:
description: >
Binding requirement expresses the relationship between Port and
Compute nodes. Effectevely it indicates that the Port will be
attached to specific Compute node instance
type: tosca.capabilities.network.Bindable
- link:
description: >
Link requirement expresses the relationship between Port and Network
nodes. It indicates which network this port will connect to.
type: tosca.capabilities.network.Linkable
##########################################################################
# Relationship Type.
# A Relationship Type is a reusable entity that defines the type of one
@@ -213,6 +342,14 @@ tosca.relationships.AttachTo:
required: false
type: string
tosca.relationships.network.LinksTo:
derived_from: tosca.relationships.DependsOn
valid_targets: [ tosca.capabilities.network.Linkable ]
tosca.relationships.network.BindsTo:
derived_from: tosca.relationships.DependsOn
valid_targets: [ tosca.capabilities.network.Bindable ]
##########################################################################
# Capability Type.
# A Capability Type is a reusable entity that describes a kind of
@@ -266,6 +403,21 @@ tosca.capabilities.DatabaseEndpoint:
tosca.capabilities.Attachment:
derived_from: tosca.capabilities.Root
tosca.capabilities.network.Linkable:
derived_from: tosca.capabilities.Root
description: >
A node type that includes the Linkable capability indicates that it can
be pointed by tosca.relationships.network.LinksTo relationship type, which
represents an association relationship between Port and Network node types.
tosca.capabilities.network.Bindable:
derived_from: tosca.capabilities.Root
description: >
A node type that includes the Bindable capability indicates that it can
be pointed by tosca.relationships.network.BindsTo relationship type, which
represents a network association relationship between Port and Compute node
types.
##########################################################################
# Interfaces Type.
# The Interfaces element describes a list of one or more interface

View File

@@ -35,11 +35,14 @@ class EntityType(object):
TOSCA_DEF = loader(TOSCA_DEF_FILE)
RELATIONSHIP_TYPE = (DEPENDSON, HOSTEDON, CONNECTSTO, ATTACHTO) = \
RELATIONSHIP_TYPE = (DEPENDSON, HOSTEDON, CONNECTSTO, ATTACHTO,
LINKSTO, BINDSTO) = \
('tosca.relationships.DependsOn',
'tosca.relationships.HostedOn',
'tosca.relationships.ConnectsTo',
'tosca.relationships.AttachTo')
'tosca.relationships.AttachTo',
'tosca.relationships.network.LinksTo',
'tosca.relationships.network.BindsTo')
NODE_PREFIX = 'tosca.nodes.'
RELATIONSHIP_PREFIX = 'tosca.relationships.'

View File

@@ -42,6 +42,15 @@ class NodeType(StatefulEntityType):
relationship = {}
requires = self.get_all_requirements()
if requires:
# NOTE(sdmonov): Check if requires is a dict.
# If it is a dict convert it to a list of dicts.
# This is needed because currently the code below supports only
# lists as requirements definition. The following check will
# make sure if a map (dict) was provided it will be converted to
# a list before proceeding to the parsing.
if isinstance(requires, dict):
requires = [{key: value} for key, value in requires.items()]
keyword = None
node_type = None
for req in requires:
@@ -61,6 +70,14 @@ class NodeType(StatefulEntityType):
if key == 'interfaces':
continue
else:
# If value is a dict and has a type key we need
# to lookup the node type using the capability type
if isinstance(value, dict) and \
'type' in value:
captype = value['type']
value = \
self._get_node_type_by_cap(key, captype)
relation = self._get_relation(key, value)
keyword = key
node_type = value
@@ -69,6 +86,27 @@ class NodeType(StatefulEntityType):
relationship[rtype] = relatednode
return relationship
def _get_node_type_by_cap(self, key, cap):
'''Find the node type that has the provided capability
This method will lookup all node types if they have the
provided capability.
'''
# Filter the node types
node_types = [node_type for node_type in self.TOSCA_DEF.keys()
if node_type.startswith(self.NODE_PREFIX) and
node_type != 'tosca.nodes.Root']
for node_type in node_types:
node_def = self.TOSCA_DEF[node_type]
if isinstance(node_def, dict) and 'capabilities' in node_def:
node_caps = node_def['capabilities']
for value in node_caps.values():
if isinstance(value, dict) and \
'type' in value and value['type'] == cap:
return node_type
def _get_relation(self, key, ndtype):
relation = None
ntype = NodeType(ndtype)

View File

@@ -15,6 +15,8 @@ from translator.toscalib.elements.nodetype import NodeType
from translator.toscalib.tests.base import TestCase
compute_type = NodeType('tosca.nodes.Compute')
component_type = NodeType('tosca.nodes.SoftwareComponent')
network_type = NodeType('tosca.nodes.network.Network')
network_port_type = NodeType('tosca.nodes.network.Port')
class ToscaDefTest(TestCase):
@@ -22,14 +24,23 @@ class ToscaDefTest(TestCase):
self.assertEqual(compute_type.type, "tosca.nodes.Compute")
self.assertRaises(exception.InvalidTypeError, NodeType,
'tosca.nodes.Invalid')
self.assertEqual(network_type.type, "tosca.nodes.network.Network")
self.assertEqual(network_port_type.type, "tosca.nodes.network.Port")
def test_parent_type(self):
self.assertEqual(compute_type.parent_type.type, "tosca.nodes.Root")
self.assertEqual(network_type.parent_type.type, "tosca.nodes.Root")
self.assertEqual(network_port_type.parent_type.type,
"tosca.nodes.Root")
def test_capabilities(self):
self.assertEqual(
['tosca.capabilities.Container'],
[c.type for c in compute_type.capabilities])
sorted(['tosca.capabilities.Container',
'tosca.capabilities.network.Bindable']),
sorted([c.type for c in compute_type.capabilities]))
self.assertEqual(
['tosca.capabilities.network.Linkable'],
[c.type for c in network_type.capabilities])
def test_properties_def(self):
self.assertEqual(
@@ -59,6 +70,15 @@ class ToscaDefTest(TestCase):
('tosca.relationships.HostedOn', ['tosca.capabilities.Container']),
[(relation.type, relation.valid_targets) for
relation in list(component_type.relationship.keys())])
self.assertIn(
('tosca.relationships.network.BindsTo', 'tosca.nodes.Compute'),
[(relation.type, node.type) for
relation, node in network_port_type.relationship.items()])
self.assertIn(
('tosca.relationships.network.LinksTo',
'tosca.nodes.network.Network'),
[(relation.type, node.type) for
relation, node in network_port_type.relationship.items()])
def test_interfaces(self):
self.assertEqual(compute_type.interfaces, None)

View File

@@ -157,8 +157,9 @@ class ToscaTemplateTest(TestCase):
for tpl in tosca_tpl.nodetemplates:
compute_type = NodeType(tpl.type)
self.assertEqual(
['tosca.capabilities.Container'],
[c.type for c in compute_type.capabilities])
sorted(['tosca.capabilities.Container',
'tosca.capabilities.network.Bindable']),
sorted([c.type for c in compute_type.capabilities]))
def test_template_with_no_inputs(self):
tosca_tpl = self._load_template('test_no_inputs_in_template.yaml')