OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

tosca message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: RE: [tosca] Groups - Rules for derivations, refinements, and assignments uploaded


This is a very good discussion, especially since it highlights the different perspectives weâre all bringing to the table. Without commenting on specifics, Iâd like to highlight my own biases:

 

1.       Tal stated that âTOSCA is not a programming language, but a modeling languageâ. I would like to respectfully disagree with that. I strongly believe weâre underselling TOSCA if we strictly position it as a modeling language, since:

a.       It doesnât do justice to the orchestration/management features of the language.

b.      As a modeling language, it arguably isnât as good as other languages such as YANG.

2.       I also donât think we should position TOSCA as an âorchestrationâ language (even though âorchestrationâ is in the name J ):

a.       As Tal has pointed out, there are a number of mature domain-specific orchestrators out there

b.      But more importantly, orchestration isnât the biggest challenge in the scheme of things. From the numbers Iâve seen, less than 10% of service-related OPEX is spent on service orchestration, while more than 90% is spent on ongoing service lifecycle management.

3.       Based on that, Iâve been positioning TOSCA as âa language for model-driven service lifecycle managementâ. Whatâs key here is the âmodel-drivenâ, since that is what differentiates TOSCA and makes it unique: it allows for a management paradigm where management actions are performed on instances of a model of a service first, and then âpropagated/syncâdâ to the actual systems that are used to provide the service. This is an entirely new management paradigm, and that that is absolutely necessary for management of systems that are largely virtual (since the traditional management paradigm of talking directly to components no longer works when those components are abstract/virtual).

 

For this paradigm to work, then, the âcontractâ or âinterfaceâ that is the most important is the interface between the orchestrator and the service instance model. This interface must support *ALL* of the orchestrator functions, not just the creation of service topologies. As Calin and I have discussed on a number of occasions, those orchestrator functions include:

 

         âInstantiatingâ a service instance model from a service template, using a set of provided input values

         âdecomposingâ the service into sub-services. In TOSCA, this is done using substitution mapping

         âresource allocationâ, which in TOSCA is done by fulfilling dangling requirements using resources that are presumably managed in some sort of resource inventory

         âservice activationâ which starts the service by running workflows that invoke interface operations, where those interface operations are âimplementedâ by artifacts bundled with the service package.

         âclosed-loop automationâ which involves listening for events and invoking policies in response to those events.

 

To ensure âcorrectnessâ of these orchestrator features, it is very important to have well-defined âcontractsâ between the orchestrator (and the âartifactsâ invoked by the orchestrator) and the instance model. Those âcontractsâ are provided by the various âtypesâ in TOSCA.

 

While all of the TOSCA types are important (since they all play a role in the lifecycle management process), I believe it should be clear that the Node Type is the most important of them all, since the Node Type defines the âFaÃadeâ (I use the word faÃade to avoid using âinterfaceâ, which already has meaning in TOSCA) to modeled service components.

 

         Without Node Types, it is not possible to have contracts between the orchestrator and the entities on which the orchestrator operates.

         If a Node Type defines a âFaÃadeâ, then that faÃade can be extended by defining derived node types. However, this derivation process should not be allowed to change the âcontractâ of its base class, since it would result in incorrect or unpredictable orchestration behavior.

         While capabilities are important, they are only important for modeling entities managed in a resource inventory. Their usefulness in service templates is limited. If a service designer knows exactly which components need to be used at design them, then there is no need to use requirements/capabilities; just define relationships directly. However, if resource allocation needs to be done at orchestration time, then dangling requirements should be used. However, those dangling requirements will be fulfilled from an inventory, and service templates should not be involved.

 

I look forward to continuing this discussion.

 

 

Chris

 

 

From: tosca@lists.oasis-open.org [mailto:tosca@lists.oasis-open.org] On Behalf Of Calin Curescu
Sent: Thursday, August 29, 2019 8:47 AM
To: Tal Liron <tliron@redhat.com>
Cc: tosca@lists.oasis-open.org
Subject: Re: [tosca] Groups - Rules for derivations, refinements, and assignments uploaded

 

Hi Tal,

 

This is indeed a long email â, but it brings up very relevant issues and a very good read. Please find my comments inline.

 

BR,

/Calin

 

From: <tosca@lists.oasis-open.org> on behalf of Tal Liron <tliron@redhat.com>
Date: Tuesday, 27 August 2019 at 20:42
To: Calin Curescu <calin.curescu@ericsson.com>
Cc: "tosca@lists.oasis-open.org" <tosca@lists.oasis-open.org>
Subject: Re: [tosca] Groups - Rules for derivations, refinements, and assignments uploaded

 

Thank you, Calin, for taking a first stab at this crucial topic!

 

I'd like to try to clarify and expand on some comments I made in the discussion today. Prepare for a long email. :)

 

There are many different flavors of handling the interplay of re-usability and contracts, each with far-reaching implications and vitally different rationales. Let's examine a few representative examples.

 

Consider a relatively strict flavor: Java. Java's modus operandi is centered on design-time adherence to interfaces and signatures. Java won't let you compile a class unless it implements the method signatures of its interfaces, including all declared thrown exceptions, and instance casting is enforced at the byte-code level. This strictness has given Java a reputation for reliability: users have the reassurance of knowing that implementations match specifications. If you can't improve on code by extending an interface, then you have to create a new interface, e.g. MyInterfaceVersion2, and either support both or provide runtime warnings to users. This design-time strictness also allows for powerful code refactoring with IDEs.

 

But, this strictness also makes it very hard to change large, integrated systems comprising interacting parts. Essentially, in Java the compilation phase functions like a required unit test. One consequence is that there is a lot of "DLL hell" in Java, whereby changes to one library can cause cascading compilation breakage. This has given the language a reputation for inflexibility and slow development progress. It's often very hard to test out ideas without changing a lot of code, and because of the compilation checks this means that you might have to change code in 3rd-party libraries. We have seen the Java community, and the language itself, evolve to work around the strictness. For example, annotations (and IoC generally) have allowed for "dynamic" formation and testing of contracts at runtime, turning it from a design issue to a configuration issue. Meta-systems like OSGi and Java 8 modules have separated contracts from code itself. But it's all still complicated and difficult.

 

And now consider Python: a "dynamic" object-oriented language that doesn't have interfaces, allows for multiple inheritance, runtime monkey-patching of classes, etc. This doesn't mean that strictness is impossible, it just means that it's in the hands of the programmer: it's up to you to decide what a contract means and when and how to enforce it. It could be by providing a set of compliance tests, doing runtime checks, and there indeed are libraries that can help. This inherent looseness has given Python a reputation for speed of development at the expense of reliability. Breakage can often be discovered only in runtime, and only in certain situations. There's no compiler to provide that initial sanity check.

 

And now consider Go, which is somewhere in between. Go is strictly typed, in some ways more so than Java. It also relies strongly on interfaces and signatures and does runtime byte-code checks. But, it does not do design-time checks for interfaces. You can declare an interface anywhere and anytime and even name it whatever you want. You can declare it repeatedly in different codebases that do not have to know about each other. And you don't even have to declare its implementation: you just implement it. It's an ad-hoc contract, but the language runtime does provide a mechanism to enforce it. This balance ends up being very practical, allowing the "Java advantage" to be used when needed. We don't get the powerful code refactoring abilities of Java, but the pros could very well outweigh the cons. And Go does something else that's different from both Java and Python: it is not object-oriented. Contracts are made *only* of interfaces and signatures, not "classes", and there is indeed no inheritance built into the language. Re-usability is in the hands of the programmer: you can assemble types together to create something that looks like inheritance, but Go won't dictate how. (Note: Haskell could also be used as an example here, but it's harder to compare it to Java and Python.)

 

[CC] I would like to bring up a fundamental difference between TOSCA and programming languages.

-          Usually, when you have a derivation in programming, the base type is contained in the extended type. This allows the extended type to be used where the base type is used. If redefined, the fields of the base type are not overwritten, they are hidden. In the constructor, or at any time we can set and access these hidden fields via special methods ( in e.g. Java via the super keyword; in Go via the struct name (I think, I am not good with Go)). So one could claim that a derived type never deletes from a base type, it always extends.

-          In TOSCA we cannot keep several versions (one per derived type) for properties/attributes. We cannot use special methods (i.e. super keyword) to access these fields based on the type context. We have only two choices: to inherit unchanged or overwrite.

o   The âinherit unchangedâ seems too restrictive, letâs explore next if there is anything better

o   The âfreely overwriteâ seems too permissive, as the property/attribute of the base type is rewritten, and its original type/structure is deleted. Now, this much more disruptive then in the programming language case where the original filed is just hidden. Here in TOSCA, we would lose the initial type/structure which ensures that we would never be able to somehow use the derived type in the context of the base type since it cannot hold the entirety of the information required by the base type (i.e. the base type is not a subset of the derived type anymore). Note that this rule is never broken in the case of programming languages.

  Then the question is:  can we further claim that the derived type still really inherits from the base type if it is incompatible? As I cannot rely on the derived type to be usable in the context of the base type, then I might as well create a totally new type and use the copy/paste mechanics YAML to copy some stuff from one type to another (i.e. the & and *)

o   The âcompatible overwriteâ path. The idea here is to preserve the possibility of the derived type to be used in the context of the base type (i.e. Could I assign a property/attribute value of a derived type to a property/attribute of the base type?). Basically the idea is that the subset of fields of the derived type that I can match to the base type can be copied there. The most unrestricted rules that can be found that fulfill this are as follows:

  For fields that are defined in the base type, in the derived type I can use a constrained/subset of the value set of the base type. Obviously any value that is ok for the field in the derived type will be also ok for the same field of the base type.

  Fields that are not defined in the base type can be freely defined, as they donât matter in this assignment.

 

 

Before I go too far with this analogy, let's underscore that TOSCA is not a programming language, but a modeling language. The contracts thus involve three parties: 1) the modeler, who creates a set of types ("profile") to represent cloud features, 2) the architect, who assembles those models into topologies that represent resources, and 3) the orchestrator, which makes them a reality. The ideal constructs are, respectively: 1) types, 2) templates, and 3) instances. The complexity we are dealing with in this discussion involves the fact that the architect is also a bit of a modeler in that the architect might also need to declare types. This is necessary because of TOSCA's design, specifically how node templates must adhere to their node type. And because the architect's node type must make use of modeler's types, the rules of derivation become so critical to the architect's work. So I think the better we understand the relationship between the modeler and architect roles, the clearer we'll understand how to formulate derivation rules for TOSCA.

 

[CC] I agree with the contracts/roles. I think the discussion is mostly between several modellers (that create/derive types at different timepoints) and the architect that creates the templates. The orchestrator is just a passive participant, since it only follows (hopefully in a unequivocal and portable way the specifications)

 

I'll try to take a stab at this. Where do strict contracts help us? They are *necessary* between the modeler and the orchestrator, because models are only useful insofar as they can be implemented. They are also necessary between the modeler and the architect, because the architect's palette can only use realistic models, which can only be used together in specific ways. Any strictness that exceeds those rationales will be limiting, even crippling.

 

A few years ago I worked out my own version of a "TOSCA 2.0" vision. I wasn't intentionally channeling Go, but there is some convergence. One argument I make there that could be relevant to this discussion is how to think about contracts. Without making the sweeping changes I advocate there (I argue against an object-oriented approach in TOSCA), let's think of this in terms of TOSCA 1.X. Specifically, consider this: capability types are much more important than node types. A TOSCA node template must have a node type, and that node type can have any number of capabilities. And it's the capabilities that are important in the creation the topology graph: requirements are the "plug" that connects to the capability "socket". The capability is the *actual* contract here: the node type is really just a container for multiple contracts. Relatedly, I have argued elsewhere that the best kinds of TOSCA profiles don't have many node types, or indeed none at all. Instead they define many capability types and associated relationship types. Service template architects can then create their own node types that are in effect "assemblages" of capabilities. They do not have to worry about inheriting a base node type. They don't need to "deprecate" a capability -- they simply don't include it in their custom node type. This matches how real-world hardware and software resources work, in that they can do some things and not other things. A computer might have a GPU or might not. As would a VM, or a container. A network might have IPv6 capabilities but no IPv4. A VNF might be able to handle both routing and firewalls but not VPNs. A PNF could have the same set of abilities, as would a CNF, despite lacking others. A database server might support relational databases, or graph databases, or both. You could handle these distinctions by creating various node types for all combinations -- NetworkWithBothIPv6andIPv4, NetworkWithOnlyIPv6, etc. -- but obviously the capability construct is the right way to do this. The node type is also the container for other kinds of contracts, too -- interfaces and notifications. But there, too, you can add whichever interfaces and notifications are relevant to your custom type, so it's still an "assemblage" in this sense. Another way to put this: the node type is a really just a syntactical convenience, rather than an architectural reality. The reality is what the node is able to do (capabilities), including in relation to other nodes. You could imagine TOSCA without node types, just node templates where you declare capabilities, interfaces, and notifications. It's more verbose, but could be functionally the same.

 

[CC] I agree that the real contracts are embodied by the capabilities (as targets for the relationships, basically setting up the topology) and interfaces (as the available operations for workflows and notifications for external events). As these contracts mean something by name (i.e. the capability type name and the interface type name) the proposal was to keep them unchanged in a derivation of a node or relationship type. Note that in TOSCA the operation and notification implementation and input and output parameters are not considered part of the interface contract so they should be freely changeable.

 

What I am arguing for here is that strict derivation rules are important for capability types, relationship types, and interface types, because they are the critical contracts. But they are not useful for node types, which is where architects need to do their work out of grammatical necessity. I would like to see a complete overhaul of TOSCA grammar (see my "vision"), but barring that, I think it's important that we allow for node type derivation to be non-strict: to allow overriding anything with anything, essentially treating it more like a re-usable assemblage ("copy-paste") than a hierarchical type. Let architects do their work (Ã la Python) without fighting the language (Ã la Java).

 

[CC] I gave an argument above why I think in TOSCA overwriting (that is more than overriding) is more disruptive than in programming languages.

My reason for having derivation rules for properties/attribute/parameters is that I can assign a derived type value to a base type by just copying the subset of relevant values. The reason for having derivation rules for node and relationship types is that I can use a derived type node by means of a node_filter selection instead of a base type node. Moreover, in this case, the get_property or get_attribute work if I apply them on a derived type node instead of a base type node.

Reasons for vendors for having derivation rules for nodes is that they can allow extension nodes in they system (by another department or organization) while still relying that they fit in place of the base type.

 

[CC] Also, I can note that having rules for node and relationship type derivation does not collide with a framework built on heavy capabilities usage as you describe above. Basically, in such framework one does not need to use node derivation at all, just include the right capabilities.  So both worlds would be happy. On the other hand, if we allow full overwrite in node derivation what would that gain compared to just defining a new node type?

 

This will have implications for other parts of TOSCA, because it would mean that we can no longer rely on a node type as a contract. Examples: we shouldn't have "valid_source_types" in capability types; we shouldn't have "node" (which is a node type) in requirement definitions (although you could specify a node template name in requirement assignments); and substitution mapping should not specify a node type, but instead just have mappings of capabilities, requirements, interfaces, etc. In tandem with these changes, we should also beef up how we specify requirements. The current "node_filter" works on properties. But what's really important is which contracts are provided by the node. There should be a way to say that the target node should have capabilities X, Y, Z (or derivatives) and/or certain interfaces/notifications.

 

I totally agree with your proposal to have a node_filter that works on capabilities and interfaces. I think that would improve TOSCA in general.

 

Sorry for being so verbose! I hope this will contribute to the discussion. What I'm trying to say is that before formulating derivation rules we should understand the basic contracts we want the language to handle.

 

 

 

 

 

 

On Mon, Aug 26, 2019 at 8:21 AM Calin Curescu <calin.curescu@ericsson.com> wrote:

Document Name: Rules for derivations, refinements, and assignments


Description
TOSCA specification until 2.0 has not explicitly specified what
redefinitions are allowed during derivation/refinement and how they
interact with assignments, leaving implementations to decide how to do it
and to deal with the ensuing confusion and lack of portability.

This is a proposal to clearly define such rules in the TOSCA language
specification.
Download Latest Revision
Public Download Link


Submitter: Dr. Calin Curescu
Group: OASIS Topology and Orchestration Specification for Cloud Applications (TOSCA) TC
Folder: Working Documents
Date submitted: 2019-08-26 06:20:52

 



[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]