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:
|
||||
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
|
||||
|
||||
@@ -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.'
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user