OASIS Topology and Orchestration Specification for Cloud Applications (TOSCA) TC

Expand all | Collapse all

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

  • 1.  Re: [tosca] Groups - Rules for derivations, refinements, and assignments uploaded

    Posted 08-29-2019 15:47




    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.


    The inherit unchanged seems too restrictive, let s explore next
    if there is anything better 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 *)




    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




     









  • 2.  RE: [tosca] Groups - Rules for derivations, refinements, and assignments uploaded

    Posted 08-29-2019 18:00




    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