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:
@@ -86,6 +86,8 @@ tosca.nodes.Compute:
|
|||||||
capabilities:
|
capabilities:
|
||||||
host:
|
host:
|
||||||
type: tosca.capabilities.Container
|
type: tosca.capabilities.Container
|
||||||
|
binding:
|
||||||
|
type: tosca.capabilities.network.Bindable
|
||||||
requirements:
|
requirements:
|
||||||
- attachment: tosca.nodes.BlockStorage
|
- attachment: tosca.nodes.BlockStorage
|
||||||
type: AttachTo
|
type: AttachTo
|
||||||
@@ -181,6 +183,133 @@ tosca.nodes.BlockStorage:
|
|||||||
attachment:
|
attachment:
|
||||||
type: tosca.capabilities.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.
|
# Relationship Type.
|
||||||
# A Relationship Type is a reusable entity that defines the type of one
|
# A Relationship Type is a reusable entity that defines the type of one
|
||||||
@@ -213,6 +342,14 @@ tosca.relationships.AttachTo:
|
|||||||
required: false
|
required: false
|
||||||
type: string
|
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.
|
# Capability Type.
|
||||||
# A Capability Type is a reusable entity that describes a kind of
|
# A Capability Type is a reusable entity that describes a kind of
|
||||||
@@ -266,6 +403,21 @@ tosca.capabilities.DatabaseEndpoint:
|
|||||||
tosca.capabilities.Attachment:
|
tosca.capabilities.Attachment:
|
||||||
derived_from: tosca.capabilities.Root
|
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.
|
# Interfaces Type.
|
||||||
# The Interfaces element describes a list of one or more interface
|
# The Interfaces element describes a list of one or more interface
|
||||||
|
|||||||
@@ -35,11 +35,14 @@ class EntityType(object):
|
|||||||
|
|
||||||
TOSCA_DEF = loader(TOSCA_DEF_FILE)
|
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.DependsOn',
|
||||||
'tosca.relationships.HostedOn',
|
'tosca.relationships.HostedOn',
|
||||||
'tosca.relationships.ConnectsTo',
|
'tosca.relationships.ConnectsTo',
|
||||||
'tosca.relationships.AttachTo')
|
'tosca.relationships.AttachTo',
|
||||||
|
'tosca.relationships.network.LinksTo',
|
||||||
|
'tosca.relationships.network.BindsTo')
|
||||||
|
|
||||||
NODE_PREFIX = 'tosca.nodes.'
|
NODE_PREFIX = 'tosca.nodes.'
|
||||||
RELATIONSHIP_PREFIX = 'tosca.relationships.'
|
RELATIONSHIP_PREFIX = 'tosca.relationships.'
|
||||||
|
|||||||
@@ -42,6 +42,15 @@ class NodeType(StatefulEntityType):
|
|||||||
relationship = {}
|
relationship = {}
|
||||||
requires = self.get_all_requirements()
|
requires = self.get_all_requirements()
|
||||||
if requires:
|
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
|
keyword = None
|
||||||
node_type = None
|
node_type = None
|
||||||
for req in requires:
|
for req in requires:
|
||||||
@@ -61,6 +70,14 @@ class NodeType(StatefulEntityType):
|
|||||||
if key == 'interfaces':
|
if key == 'interfaces':
|
||||||
continue
|
continue
|
||||||
else:
|
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)
|
relation = self._get_relation(key, value)
|
||||||
keyword = key
|
keyword = key
|
||||||
node_type = value
|
node_type = value
|
||||||
@@ -69,6 +86,27 @@ class NodeType(StatefulEntityType):
|
|||||||
relationship[rtype] = relatednode
|
relationship[rtype] = relatednode
|
||||||
return relationship
|
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):
|
def _get_relation(self, key, ndtype):
|
||||||
relation = None
|
relation = None
|
||||||
ntype = NodeType(ndtype)
|
ntype = NodeType(ndtype)
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ from translator.toscalib.elements.nodetype import NodeType
|
|||||||
from translator.toscalib.tests.base import TestCase
|
from translator.toscalib.tests.base import TestCase
|
||||||
compute_type = NodeType('tosca.nodes.Compute')
|
compute_type = NodeType('tosca.nodes.Compute')
|
||||||
component_type = NodeType('tosca.nodes.SoftwareComponent')
|
component_type = NodeType('tosca.nodes.SoftwareComponent')
|
||||||
|
network_type = NodeType('tosca.nodes.network.Network')
|
||||||
|
network_port_type = NodeType('tosca.nodes.network.Port')
|
||||||
|
|
||||||
|
|
||||||
class ToscaDefTest(TestCase):
|
class ToscaDefTest(TestCase):
|
||||||
@@ -22,14 +24,23 @@ class ToscaDefTest(TestCase):
|
|||||||
self.assertEqual(compute_type.type, "tosca.nodes.Compute")
|
self.assertEqual(compute_type.type, "tosca.nodes.Compute")
|
||||||
self.assertRaises(exception.InvalidTypeError, NodeType,
|
self.assertRaises(exception.InvalidTypeError, NodeType,
|
||||||
'tosca.nodes.Invalid')
|
'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):
|
def test_parent_type(self):
|
||||||
self.assertEqual(compute_type.parent_type.type, "tosca.nodes.Root")
|
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):
|
def test_capabilities(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
['tosca.capabilities.Container'],
|
sorted(['tosca.capabilities.Container',
|
||||||
[c.type for c in compute_type.capabilities])
|
'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):
|
def test_properties_def(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -59,6 +70,15 @@ class ToscaDefTest(TestCase):
|
|||||||
('tosca.relationships.HostedOn', ['tosca.capabilities.Container']),
|
('tosca.relationships.HostedOn', ['tosca.capabilities.Container']),
|
||||||
[(relation.type, relation.valid_targets) for
|
[(relation.type, relation.valid_targets) for
|
||||||
relation in list(component_type.relationship.keys())])
|
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):
|
def test_interfaces(self):
|
||||||
self.assertEqual(compute_type.interfaces, None)
|
self.assertEqual(compute_type.interfaces, None)
|
||||||
|
|||||||
@@ -157,8 +157,9 @@ class ToscaTemplateTest(TestCase):
|
|||||||
for tpl in tosca_tpl.nodetemplates:
|
for tpl in tosca_tpl.nodetemplates:
|
||||||
compute_type = NodeType(tpl.type)
|
compute_type = NodeType(tpl.type)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
['tosca.capabilities.Container'],
|
sorted(['tosca.capabilities.Container',
|
||||||
[c.type for c in compute_type.capabilities])
|
'tosca.capabilities.network.Bindable']),
|
||||||
|
sorted([c.type for c in compute_type.capabilities]))
|
||||||
|
|
||||||
def test_template_with_no_inputs(self):
|
def test_template_with_no_inputs(self):
|
||||||
tosca_tpl = self._load_template('test_no_inputs_in_template.yaml')
|
tosca_tpl = self._load_template('test_no_inputs_in_template.yaml')
|
||||||
|
|||||||
Reference in New Issue
Block a user