Replies: 8 comments 8 replies
-
I believe that this is exactly the use case for which substitution mapping is the perfect solution, assuming we fix the issue with the requirement mapping syntax as identified in #92 (comment) Using current substitution mapping syntax, here is TOSCA for the top-level file from Tal's example (the consuming template using Tal's terminology):
The
In the substituting template, both the I believe this syntax is very elegant and very clear and a perfect use of substitution mapping. |
Beta Was this translation helpful? Give feedback.
-
A couple of comments:
|
Beta Was this translation helpful? Give feedback.
-
I am still being a bit quiet in the discussions, because as mentioned, we do these things in a different, and far simpler way, our fundamental concepts are quite different, and could not easily be ported into TOSCA. I am looking forward to the expanded example from @tliron, so when I better understand what you are trying to do, I will try to show what the same thing looks like with parameterization instead of substitution. |
Beta Was this translation helpful? Give feedback.
-
Here's a very very long full version of my previous example: tosca_definitions_version: tosca_2_0
capability_types:
ControlPlane:
properties:
protocol-version: { type: string, default: '1.0' }
attributes:
current-status: { type: string }
DataPlane:
properties:
protocol-version: { type: string, default: '1.0' }
attributes:
current-status: { type: string }
ManagementPlane:
properties:
protocol-version: { type: string, default: '1.0' }
attributes:
current-status: { type: string }
node_types:
HighCapacityEndpoint:
attributes:
mode: { type: string }
linked: { type: boolean }
capabilities:
control-plane1: ControlPlane
control-plane2: ControlPlane
control-plane3: ControlPlane
data-plane1: DataPlane
data-plane2: DataPlane
data-plane3: DataPlane
management-plane1: ManagementPlane
management-plane2: ManagementPlane
management-plane3: ManagementPlane
requirements:
- control-plane-up1: { capability: ControlPlane, count_range: [ 1, 1 ] }
- control-plane-up2: { capability: ControlPlane, count_range: [ 1, 1 ] }
- control-plane-down1: { capability: ControlPlane, count_range: [ 1, 1 ] }
- control-plane-down2: { capability: ControlPlane, count_range: [ 1, 1 ] }
- data-plane-up1: { capability: DataPlane, count_range: [ 1, 1 ] }
- data-plane-up2: { capability: DataPlane, count_range: [ 1, 1 ] }
- data-plane-down1: { capability: DataPlane, count_range: [ 1, 1 ] }
- data-plane-down2: { capability: DataPlane, count_range: [ 1, 1 ] }
- management-plane-up1: { capability: ManagementPlane, count_range: [ 1, 1 ] }
- management-plane-up2: { capability: ManagementPlane, count_range: [ 1, 1 ] }
- management-plane-down1: { capability: ManagementPlane, count_range: [ 1, 1 ] }
- management-plane-down2: { capability: ManagementPlane, count_range: [ 1, 1 ] }
LowCapacityEndpoint:
attributes:
mode: { type: string }
linked: { type: boolean }
capabilities:
control-plane1: ControlPlane
control-plane2: ControlPlane
data-plane1: DataPlane
data-plane2: DataPlane
management-plane1: ManagementPlane
management-plane2: ManagementPlane
requirements:
- control-plane-up: { capability: ControlPlane, count_range: [ 1, 1 ] }
- control-plane-down: { capability: ControlPlane, count_range: [ 1, 1 ] }
- data-plane-up: { capability: DataPlane, count_range: [ 1, 1 ] }
- data-plane-down: { capability: DataPlane, count_range: [ 1, 1 ] }
- management-plane-up: { capability: ManagementPlane, count_range: [ 1, 1 ] }
- management-plane-down: { capability: ManagementPlane, count_range: [ 1, 1 ] }
Converter:
attributes:
backhaul-mode: { type: string }
backhaul-linked: { type: boolean }
midhaul-mode: { type: string }
midhaul-linked: { type: boolean }
fronthaul-mode: { type: string }
fronthaul-linked: { type: boolean }
capabilities:
backhaul-control-plane1: ControlPlane
backhaul-control-plane2: ControlPlane
backhaul-control-plane3: ControlPlane
backhaul-data-plane1: DataPlane
backhaul-data-plane2: DataPlane
backhaul-data-plane3: DataPlane
backhaul-management-plane1: ManagementPlane
backhaul-management-plane2: ManagementPlane
backhaul-management-plane3: ManagementPlane
midhaul-control-plane1: ControlPlane
midhaul-control-plane2: ControlPlane
midhaul-data-plane1: DataPlane
midhaul-data-plane2: DataPlane
midhaul-management-plane1: ManagementPlane
midhaul-management-plane2: ManagementPlane
fronthaul-control-plane1: ControlPlane
fronthaul-control-plane2: ControlPlane
fronthaul-data-plane1: DataPlane
fronthaul-data-plane2: DataPlane
fronthaul-management-plane1: ManagementPlane
fronthaul-management-plane2: ManagementPlane
requirements:
- backhaul-control-plane-up1: ControlPlane
- backhaul-control-plane-up2: ControlPlane
- backhaul-control-plane-down1: ControlPlane
- backhaul-control-plane-down2: ControlPlane
- backhaul-data-plane-up1: ControlPlane
- backhaul-data-plane-up2: ControlPlane
- backhaul-data-plane-down1: ControlPlane
- backhaul-data-plane-down2: ControlPlane
- backhaul-management-plane-up1: ControlPlane
- backhaul-management-plane-up2: ControlPlane
- backhaul-management-plane-down1: ControlPlane
- backhaul-management-plane-down2: ControlPlane
- midhaul-control-plane-up: ControlPlane
- midhaul-control-plane-down: ControlPlane
- midhaul-data-plane-up: ControlPlane
- midhaul-data-plane-down: ControlPlane
- midhaul-management-plane-up: ControlPlane
- midhaul-management-plane-down: ControlPlane
- fronthaul-control-plane-up: ControlPlane
- fronthaul-control-plane-down: ControlPlane
- fronthaul-data-plane-up: ControlPlane
- fronthaul-data-plane-down: ControlPlane
- fronthaul-management-plane-up: ControlPlane
- fronthaul-management-plane-down: ControlPlane
service_template:
node_templates:
processor:
type: VM
requirements:
- internal-endpoint: backhaul-endpoint
- internal-endpoint: midhaul-endpoint
- internal-endpoint: fronthaul-endpoint
backhaul-endpoint:
type: HighCapacityEndpoint
midhaul-endpoint:
type: LowCapacityEndpoint
fronthaul-endpoint:
type: LowCapacityEndpoint
substitution_mappings:
node_type: Converter
attributes:
backhaul-mode: [ backhaul-endpoint, mode ]
backhaul-linked: [ backhaul-endpoint, linked ]
midhaul-mode: [ midhaul-endpoint, mode ]
midhaul-linked: [ midhaul-endpoint, linked ]
fronthaul-mode: [ fronthaul-endpoint, mode ]
fronthaul-linked: [ fronthaul-endpoint, linked ]
capabilities:
backhaul-control-plane1: [ backhaul-endpoint, control-plane1 ]
backhaul-control-plane2: [ backhaul-endpoint, control-plane2 ]
backhaul-control-plane3: [ backhaul-endpoint, control-plane3 ]
backhaul-data-plane1: [ backhaul-endpoint, data-plane1 ]
backhaul-data-plane2: [ backhaul-endpoint, data-plane2 ]
backhaul-data-plane3: [ backhaul-endpoint, data-plane3 ]
backhaul-management-plane1: [ backhaul-endpoint, management-plane1 ]
backhaul-management-plane2: [ backhaul-endpoint, management-plane2 ]
backhaul-management-plane3: [ backhaul-endpoint, management-plane3 ]
midhaul-control-plane1: [ midhaul-endpoint, control-plane1 ]
midhaul-control-plane2: [ midhaul-endpoint, control-plane2 ]
midhaul-data-plane1: [ midhaul-endpoint, data-plane1 ]
midhaul-data-plane2: [ midhaul-endpoint, data-plane2 ]
midhaul-management-plane1: [ midhaul-endpoint, management-plane1 ]
midhaul-management-plane2: [ midhaul-endpoint, management-plane2 ]
fronthaul-control-plane1: [ fronthaul-endpoint, control-plane1 ]
fronthaul-control-plane2: [ fronthaul-endpoint, control-plane2 ]
fronthaul-data-plane1: [ fronthaul-endpoint, data-plane1 ]
fronthaul-data-plane2: [ fronthaul-endpoint, data-plane2 ]
fronthaul-management-plane1: [ fronthaul-endpoint, management-plane1 ]
fronthaul-management-plane2: [ fronthaul-endpoint, management-plane2 ]
requirements:
backhaul-control-plane-up1: [ backhaul-endpoint, control-plane-up1 ]
backhaul-control-plane-up2: [ backhaul-endpoint, control-plane-up2 ]
backhaul-control-plane-down1: [ backhaul-endpoint, control-plane-down1 ]
backhaul-control-plane-down2: [ backhaul-endpoint, control-plane-down2 ]
backhaul-data-plane-up1: [ backhaul-endpoint, data-plane-up1 ]
backhaul-data-plane-up2: [ backhaul-endpoint, data-plane-up2 ]
backhaul-data-plane-down1: [ backhaul-endpoint, data-plane-down1 ]
backhaul-data-plane-down2: [ backhaul-endpoint, data-plane-down2 ]
backhaul-management-plane-up1: [ backhaul-endpoint, management-plane-up1 ]
backhaul-management-plane-up2: [ backhaul-endpoint, management-plane-up2 ]
backhaul-management-plane-down1: [ backhaul-endpoint, management-plane-down1 ]
backhaul-management-plane-down2: [ backhaul-endpoint, management-plane-down2 ]
midhaul-control-plane-up: [ midhaul-endpoint, control-plane-up ]
midhaul-control-plane-down: [ midhaul-endpoint, control-plane-down ]
midhaul-data-plane-up: [ midhaul-endpoint, data-plane-up ]
midhaul-data-plane-down: [ midhaul-endpoint, data-plane-down ]
midhaul-management-plane-up: [ midhaul-endpoint, management-plane-up ]
midhaul-management-plane-down: [ midhaul-endpoint, management-plane-down ]
fronthaul-control-plane-up: [ fronthaul-endpoint, control-plane-up ]
fronthaul-control-plane-down: [ fronthaul-endpoint, control-plane-down ]
fronthaul-data-plane-up: [ fronthaul-endpoint, data-plane-up ]
fronthaul-data-plane-down: [ fronthaul-endpoint, data-plane-down ]
fronthaul-management-plane-up: [ fronthaul-endpoint, management-plane-up ]
fronthaul-management-plane-down: [ fronthaul-endpoint, management-plane-down ] |
Beta Was this translation helpful? Give feedback.
-
I think the fundamental problem with substitution is that the TOSCA language doesn't allow node types as types of properties and inputs. What we want to express is that the abstract topology wants to pass the same network to two different abstract nodes, and inside the concrete substitution we may have multiple nodes that need to have relations to the same external node. With TOSCA today, the only way to express that is to define sufficiently distinct capabilities that the node can be uniquely identified by a corresponding set of requirements. That tends to explode into a huge set of individual capabilities and associated requirements. Today an input or property can have a simple type like So at the abstract level, This is how I do it in our language, and it works really well. It is easy to understand and easy to use because it aligns with well known parameter passing principles of other languages. The way we do it with requirements inside the substituting templates that match the outside capabilities can work nicely in some cases (and our language has a function for that, of course), but in a lot of cases, like Tal's above, it creates a strong coupling between the context of the abstract node and the definition of the substituting template. This reminds me of the I'm afraid that Tal's bespoke capabilities ( This doesn't mean that I have a full solution to how to have nodes-as-values and node-types-as-value-types in TOSCA - that would require a fairly major change of the language - so definitely not something we can achieve for TOSCA 2.0. |
Beta Was this translation helpful? Give feedback.
-
I think we're confusing two concepts: requirement fulfillment and substitution mapping.
I continue to believe that this is very elegant. All we need is (simple) enhancements to the @pmbruun, would it be possible to create a picture for the scenario you described above? That would help to guide the discussion during our Wednesday meetings. |
Beta Was this translation helpful? Give feedback.
-
I've given this a lot of thought (and work!) and think the key is to make "facades" first-class citizens in TOSCA, just like we did for profiles. I think it works well with our "mental model". Feature Proposal: Facades and ImplementationsTop-level keyname:
|
Beta Was this translation helpful? Give feedback.
-
I see the facade proposal from Tal as either a "collaboration" or a merge between two service templates.
|
Beta Was this translation helpful? Give feedback.
-
I am here resurrecting an issue discussed on the mailing list in Apr 2021 (this thread). Pasting the email here with minor fixes:
I think what we need here is a way for the providing service to "expose" features and also for the consuming template to "inject" them. These
features thus become "shared" between both services. And I think Adam's proposal is the right starting point, something that looks more like a node template than a node type, something that can be constructed rather than "mapped".
One major problem with the current grammar is that mappings are one-to-one, but real world use cases are ... more complicated. But also more simple in terms of defining what users want. Here's a simple example: imagine a providing service that has two nodes, an application and a database, and that both of these can be installed on the same server. The consuming service doesn't care that internally the providing service comprises several nodes, all it wants to do is specify "install this (whole) service on this server". There is no way to do this with substitution mapping, because you can only map the installation requirement of either node template, not both of them at once. There's this mismatch between "mapping" and the control of the actual features we need.
Allow me to try to solve this with some back-of-the-napkin brainstorming by building on Adam's proposal and my idea of "exposing":
If you follow this example you'll see that rather than substituting a single node, we are instead "exposing" two nodes from the providing
service. Once exposed they are essentially "shared" between the two services. The node template names are different but as long as the matching can be done correctly (by policy?) they should end up referring to the same exact node representations. Also note that the node types have to be the same or derive from each other. Of course references to the base type won't be able to access features of the derived type, but that is intended by design. So the consuming service only knows that this is an (abstract) "Application", while the providing template uses "WebApplication" and refers to additional properties and attributes. On the flip side, the providing service knows that it connects to an (abstract) "Machine", while the consuming service provides a concrete sub-type, "VirtualMachine".
The magic of sharing means that we can indeed install both the app and db nodes on the same server. And we're no longer talking about "substitution nodes" but rather a more open sharing of one or more nodes between the two services.
Beta Was this translation helpful? Give feedback.
All reactions