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

  • 1.  New syntax for function calls

    Posted 03-16-2021 17:56
    This is an old topic, but worth resurrecting. The problem with the current syntax: mynode: type: MyType properties: name: { get_input: site } Is that locks away the function name from being used as a map key. What do I mean? Let's rewrite it with a different notation, just to emphasize that it is indeed a map: mynode: type: MyType properties: name: get_input: site Now imagine this definition: MyType: properties: name: type: map As you can see, the parser has no trivial way to distinguish "get_input" from being a function call vs. being a literal key in a map with a single key. There's another more subtle problem. if someone tries to call a non-existent function, they would get a confusing error, e.g.: mynode: type: MyType properties: name: { get_output: site } There's currently no "get_output" function in TOSCA. But, the error would not be about a non-existing function, it would be about trying to assign a map to something that is not a map. Things could get even worse if the property type actually is a map! The service template will be silently processed, and the user would not even know that the supposed function was not processed! It could lead to very hard-to-find bugs. I propose adding a prefix character to all function calls. I'll arbitrarily choose "!". E.g.: mynode: type: MyType properties: name: { !get_input: site } All these problems now disappear. When encountering a "!" prefix for a map with a single key, the TOSCA parser will expect it to be a function call and will emit a clear error if the function name is not recognized. You might be asking how to handle a literal map with a single key that really has a "!" prefix. Well, we can support escaping using a double prefix, e.g. mynode: type: MyType properties: name: !!not-a-function: site The double "!!" will become a single "!" and it will not be treated as a function call. This is deterministic and, as long as it's documented, should not be confusing, especially since it would likely be a very rare use case.


  • 2.  Re: [tosca] New syntax for function calls

    Posted 03-16-2021 20:01
    This is interesting idea but leading "!" is reserved in yaml for tags (see https://camel.readthedocs.io/en/latest/yamlref.html#tags ) and so these would always need to be quoted with is awkward. Also, I should note that since we currently accept any string with no constraints as a valid identifier any kind of syntax like this (or a syntax for generating template names like you previously proposed) are ambiguous. -- Adam á On Tue, Mar 16, 2021 at 10:56 AM Tal Liron < tliron@redhat.com > wrote: This is an old topic, but worth resurrecting. The problem with the current syntax: mynode: type: MyType properties: name: { get_input: site } Is that locks away the function name from being used as a map key. What do I mean? Let's rewrite it with a different notation, just to emphasize that it is indeed a map: mynode: type: MyType properties: name: get_input: site Now imagine this definition: MyType: properties: name: type: map As you can see, the parser has no trivial way to distinguish "get_input" from being a function call vs. being a literal key in a map with a single key. There's another more subtle problem. if someone tries to call a non-existent function, they would get a confusing error, e.g.: mynode: type: MyType properties: name: { get_output: site } There's currently no "get_output" function in TOSCA. But, the error would not be about a non-existing function, it would be about trying to assign a map to something that is not a map. Things could get even worse if the property type actually is a map! The service template will be silently processed, and the user would not even know that the supposed function was not processed! It could lead to very hard-to-find bugs. I propose adding a prefix character to all function calls. I'll arbitrarily choose "!". E.g.: mynode: type: MyType properties: name: { !get_input: site } All these problems now disappear. When encountering a "!" prefix for a map with a single key, the TOSCA parser will expect it to be a function call and will emit a clear error if the function name is not recognized. You might be asking how to handle a literal map with a single key that really has a "!" prefix. Well, we can support escaping using a double prefix, e.g. mynode: type: MyType properties: name: !!not-a-function: site The double "!!" will become a single "!" and it will not be treated as a function call. This is deterministic and, as long as it's documented, should not be confusing, especially since it would likely be a very rare use case.


  • 3.  Re: [tosca] New syntax for function calls

    Posted 03-16-2021 23:51
    Ah, you're right -- it's actually the double !! that would be a problem. We can choose a different character, like "@" or "%". I don't think this is a problem for "any string", as you say. Function calls can only exist within value assignments of properties, attributes, and parameters, and they must also be a YAML map with a single string key. On Tue, Mar 16, 2021 at 3:01 PM adam souzis < adam@souzis.com > wrote: This is interesting idea but leading "!" is reserved in yaml for tags (see https://camel.readthedocs.io/en/latest/yamlref.html#tags ) and so these would always need to be quoted with is awkward. Also, I should note that since we currently accept any string with no constraints as a valid identifier any kind of syntax like this (or a syntax for generating template names like you previously proposed) are ambiguous. -- Adam á On Tue, Mar 16, 2021 at 10:56 AM Tal Liron < tliron@redhat.com > wrote: This is an old topic, but worth resurrecting. The problem with the current syntax: mynode: type: MyType properties: name: { get_input: site } Is that locks away the function name from being used as a map key. What do I mean? Let's rewrite it with a different notation, just to emphasize that it is indeed a map: mynode: type: MyType properties: name: get_input: site Now imagine this definition: MyType: properties: name: type: map As you can see, the parser has no trivial way to distinguish "get_input" from being a function call vs. being a literal key in a map with a single key. There's another more subtle problem. if someone tries to call a non-existent function, they would get a confusing error, e.g.: mynode: type: MyType properties: name: { get_output: site } There's currently no "get_output" function in TOSCA. But, the error would not be about a non-existing function, it would be about trying to assign a map to something that is not a map. Things could get even worse if the property type actually is a map! The service template will be silently processed, and the user would not even know that the supposed function was not processed! It could lead to very hard-to-find bugs. I propose adding a prefix character to all function calls. I'll arbitrarily choose "!". E.g.: mynode: type: MyType properties: name: { !get_input: site } All these problems now disappear. When encountering a "!" prefix for a map with a single key, the TOSCA parser will expect it to be a function call and will emit a clear error if the function name is not recognized. You might be asking how to handle a literal map with a single key that really has a "!" prefix. Well, we can support escaping using a double prefix, e.g. mynode: type: MyType properties: name: !!not-a-function: site The double "!!" will become a single "!" and it will not be treated as a function call. This is deterministic and, as long as it's documented, should not be confusing, especially since it would likely be a very rare use case.


  • 4.  Re: [tosca] New syntax for function calls

    Posted 03-17-2021 12:07
    Good point, there isn't any ambiguity if there's a leading escape character. I was thing more about your example for node templates, e.g. "{ concat: [ site-, { get_variable: [ SITE, name ] } ] }" How do you know it's not a template with that name? BTW, for the issue you brought up about functions, in Unfurl I have a function called "q" (for "quote") that resolves to its value. That solves the problem in a similar way but doesn't introduce any new syntax. Adam á On Tue, Mar 16, 2021 at 4:50 PM Tal Liron < tliron@redhat.com > wrote: Ah, you're right -- it's actually the double !! that would be a problem. We can choose a different character, like "@" or "%". I don't think this is a problem for "any string", as you say. Function calls can only exist within value assignments of properties, attributes, and parameters, and they must also be a YAML map with a single string key. On Tue, Mar 16, 2021 at 3:01 PM adam souzis < adam@souzis.com > wrote: This is interesting idea but leading "!" is reserved in yaml for tags (see https://camel.readthedocs.io/en/latest/yamlref.html#tags ) and so these would always need to be quoted with is awkward. Also, I should note that since we currently accept any string with no constraints as a valid identifier any kind of syntax like this (or a syntax for generating template names like you previously proposed) are ambiguous. -- Adam á On Tue, Mar 16, 2021 at 10:56 AM Tal Liron < tliron@redhat.com > wrote: This is an old topic, but worth resurrecting. The problem with the current syntax: mynode: type: MyType properties: name: { get_input: site } Is that locks away the function name from being used as a map key. What do I mean? Let's rewrite it with a different notation, just to emphasize that it is indeed a map: mynode: type: MyType properties: name: get_input: site Now imagine this definition: MyType: properties: name: type: map As you can see, the parser has no trivial way to distinguish "get_input" from being a function call vs. being a literal key in a map with a single key. There's another more subtle problem. if someone tries to call a non-existent function, they would get a confusing error, e.g.: mynode: type: MyType properties: name: { get_output: site } There's currently no "get_output" function in TOSCA. But, the error would not be about a non-existing function, it would be about trying to assign a map to something that is not a map. Things could get even worse if the property type actually is a map! The service template will be silently processed, and the user would not even know that the supposed function was not processed! It could lead to very hard-to-find bugs. I propose adding a prefix character to all function calls. I'll arbitrarily choose "!". E.g.: mynode: type: MyType properties: name: { !get_input: site } All these problems now disappear. When encountering a "!" prefix for a map with a single key, the TOSCA parser will expect it to be a function call and will emit a clear error if the function name is not recognized. You might be asking how to handle a literal map with a single key that really has a "!" prefix. Well, we can support escaping using a double prefix, e.g. mynode: type: MyType properties: name: !!not-a-function: site The double "!!" will become a single "!" and it will not be treated as a function call. This is deterministic and, as long as it's documented, should not be confusing, especially since it would likely be a very rare use case.


  • 5.  Re: [tosca] New syntax for function calls

    Posted 03-17-2021 14:03
    Right, that proposal was weird for exactly that reason -- treating a name (a non-value) as a value. That's part of the reason I added a second version of that proposal, of using the "aliases" keyword in which actual values are expected. Can you show us an example from Unfurl of using "q"? On Wed, Mar 17, 2021 at 7:06 AM adam souzis < adam@souzis.com > wrote: Good point, there isn't any ambiguity if there's a leading escape character. I was thing more about your example for node templates, e.g. "{ concat: [ site-, { get_variable: [ SITE, name ] } ] }" How do you know it's not a template with that name? BTW, for the issue you brought up about functions, in Unfurl I have a function called "q" (for "quote") that resolves to its value. That solves the problem in a similar way but doesn't introduce any new syntax.


  • 6.  Re: [tosca] New syntax for function calls

    Posted 03-17-2021 14:08
    Sure, it's just a tosca function that returns its value, so to use your first example: mynode: type: MyType properties: name: { q: { get_input: site } } Though of course it much nicer written out like this: mynode: type: MyType properties: name: q: { get_input: site } á On Wed, Mar 17, 2021 at 7:02 AM Tal Liron < tliron@redhat.com > wrote: Right, that proposal was weird for exactly that reason -- treating a name (a non-value) as a value. That's part of the reason I added a second version of that proposal, of using the "aliases" keyword in which actual values are expected. Can you show us an example from Unfurl of using "q"? On Wed, Mar 17, 2021 at 7:06 AM adam souzis < adam@souzis.com > wrote: Good point, there isn't any ambiguity if there's a leading escape character. I was thing more about your example for node templates, e.g. "{ concat: [ site-, { get_variable: [ SITE, name ] } ] }" How do you know it's not a template with that name? BTW, for the issue you brought up about functions, in Unfurl I have a function called "q" (for "quote") that resolves to its value. That solves the problem in a similar way but doesn't introduce any new syntax.


  • 7.  Re: [tosca] New syntax for function calls

    Posted 03-17-2021 15:15
    As a side note -- we've tabled the proposal that TOSCA could be made more extensible than it already is by formally acknowledging that some implementations would add additional "custom" functions. It's a delicate issue. As Chris pointed out, it would limit portability if users indeed use such functions. On the other hand, ... there's nothing we can do to stop implementations from adding functions, and indeed it seems like a natural and "correct" way to add various features. TOSCA already supports metadata everywhere, which allows implementations to ... add any custom data. So, why not acknowledge in the specification that there may be additional functions in some implementations? We can at least provide guidelines for when new functions should be introduced and encourage more portable solutions. But we can also go a step further, and perhaps allow these custom functions to be "forward-declared", at least by name, so that other TOSCA processors would at least not consider these functions calls as errors. E.g.: tosca_definitions_version: tosca_2_0 functions: - q - get_output topology_template: ... On Wed, Mar 17, 2021 at 9:07 AM adam souzis < adam@souzis.com > wrote: Sure, it's just a tosca function that returns its value, so to use your first example: mynode: type: MyType properties: name: { q: { get_input: site } } Though of course it much nicer written out like this: mynode: type: MyType properties: name: q: { get_input: site } á On Wed, Mar 17, 2021 at 7:02 AM Tal Liron < tliron@redhat.com > wrote: Right, that proposal was weird for exactly that reason -- treating a name (a non-value) as a value. That's part of the reason I added a second version of that proposal, of using the "aliases" keyword in which actual values are expected. Can you show us an example from Unfurl of using "q"? On Wed, Mar 17, 2021 at 7:06 AM adam souzis < adam@souzis.com > wrote: Good point, there isn't any ambiguity if there's a leading escape character. I was thing more about your example for node templates, e.g. "{ concat: [ site-, { get_variable: [ SITE, name ] } ] }" How do you know it's not a template with that name? BTW, for the issue you brought up about functions, in Unfurl I have a function called "q" (for "quote") that resolves to its value. That solves the problem in a similar way but doesn't introduce any new syntax.


  • 8.  Re: New syntax for function calls

    Posted 04-06-2021 15:36
    As a corollary to my proposal for a prefix character for function names, I would add that we would need a prefix character for our "magic names", too, and for many of the same reasons. Here's a simple example that shows the problem: topology_template: node_templates: SELF: type: ServerPool properties: name: mypool IMPLEMENTATION: type: Server properties: name: nyname additional_name: { @get_property [ SELF, name ] } # here we mean ourselves pool_name: { @get_property [ SELF, name ] } # here we mean the node template named 'SELF' The above is obviously broken in TOSCA. Basically all the magic keywords cannot be used as template names. This doesn't sound like a big deal, but certain edge cases can be problematic, e.g. a TOSCA code generator. Let's fix this by using a prefix (which is again escapable by doubling): topology_template: node_templates: SELF: type: ServerPool properties: name: mypool IMPLEMENTATION: type: Server properties: name: nyname additional_name: { @get_property [ @self, name ] } # no ambiguity, magic name is prefixed pool_name: { @get_property [ SELF, name ] } # no ambiguity, it's a template name The escaping rule is very clear (use "@@" for anything that needs to begin with "@") and is deterministically possible to algortihmize into things like TOSCA generators without them having to be hardcoded with a list of forbidden magic names. Another aspect to this -- if we want to talk about allowing TOSCA to be extended by adding custom functions, it's very useful in the same context to talk about extending via custom magic names. From an implementation perspective they really are the same, there's just a simpler syntax allowed here for a zero argument function call. E.g. you can think of the "@self" magic name as syntactically equivalent to this: value: { @self: [] } I think it's worth allowing this if we already want to allow custom functions, as it can lead to cleaner syntax. For example, there would be a way here to recreate the Simple Profile's "HOST" magic name. This is a feature we removed from TOSCA 2.0 for good reasons -- it's extremely implementation-specific. Well, then, specific implementations of TOSCA could allow for such useful features by such grammatical extensions.


  • 9.  Re: New syntax for function calls

    Posted 04-20-2021 17:19
    We discussed this proposal in the ad hoc today. We generally agree that going with a prefix is the best choice, and that perhaps "$" would be the best prefix, as it would be least likely to cause conflicts. See YAML 1.2 and YAML 1.1 , specifically the "Indicators" section in the Index, as well as "Example 5.10" and "Example 5.9" (the grave character was added in YAML 1.2 as reserved for future use). YAML already stole all the best characters, so "$" remains. :) We discussed two approaches to parsing: "BROAD" PROPOSAL Any string value that begins with an unescaped "$" would be considered an "_expression_". This includes map keys, including a-map-with-a-single-string-key-that-has-a-list-as-its-value, which is our conventional function format. But this also leaves the door open to other kinds of special values, such as magic words and other special features. There's a lot of flexibility in this approach in that it can allow implementations based on anything you can do in YAML, including notations that we do not currently use in TOSCA. A few examples: # Using our current function signature my-property: { $get_env: [ USER ] } # A custom function signature: string argument my-property: { $get_env: USER } # A custom function signature: map argument my-property: { $get_env: { local: USER } } # A custom string my-property: $env.USER # A custom key my-property: key1: value1 key2: value2 $sorted: ascending # A custom list element my-property: - value1 - value2 - { $sorted: ascending } It might also be a good idea to disallow node template names from beginning with an unescaped "$". The reason is that a common use case for the "custom string" might be for "modelable entity names" in functions like $get_property and $get_attribute, namely the built-in $self, $source, and $target. This rule would thus avoid potential ambiguities. The pros of this "broad" approach are: Lots of flexibility! Many cool syntax varieties and features are possible. Straightforward parsing: any string beginning with an unescaped "$" is an _expression_ (meaning that it will not be treated as a string value). This does mean that users will have to pay attention and escape any actual string value beginning with "$". Though note that if they make a mistake they should get a clear error. The major con of this approach is the lack of a specified function syntax. The fact that TOSCA's built-in functions are all a-map-with-a-single-string-key-that-has-a-list-as-its-value would simply become our convention. However, it's really more than a convention in TOSCA right now, because TOSCA supports nested function calls: my-property: { $concat: [ { $get_property: [ $self, name ] }, -suffix ] } If we let "$" be entirely implementation-specific then the TOSCA parser won't know to look into the values (function arguments in this case) and parse them first and somehow embed that _expression_ evaluation. The workaround would be to say that the TOSCA parser *will* parse "$" values even if they are embedded inside other "$" values. This might sound obvious, but it's non-trivial: it means that custom implementations will not actually have complete control over their values. To me that's a reasonable compromise, even if it limits the flexibility a bit. "NARROW" PROPOSAL This is more conservative. The idea is to keep the current TOSCA syntactic conventions for function calls. So, the "$" prefixed strings would only apply to a-map-with-a-single-string-key-that-has-a-list-as-its-value. Additionally, we are assuming that every argument in the list is itself a value, which in turn could also be a "$" function call. We can furthermore specify that an unknown function name is *not* an error. This will ensure better portability than the "broad" proposal. A TOSCA parser encountering an unrecognized function can just assume that it returns a value of the correct type. It can go further and insert a function call stub (this is what Puccini does), which could then be implemented by the runtime environment itself. There is additionally another variant of this proposal that would allow for "special words". This is just syntactic sugar for function calls with no arguments, the ability to make these two equivalent: my-property: { $get_property: [ { $host: [] }, name ] } my-property: { $get_property: [ $host, name ] } Note that there's a risk with this variant of turning it into the "broad" proposal above, because this means that any bare string value (but not a map key) needs to be checked for the "$" prefix. The workaround is to restrict this syntactic sugar to be *only* for function arguments. So the following would *not* be a function call, because it's not a function argument: my-property: $host Also, again node template names should be disallowed from beginning with an unescaped "$". Pros: Keep TOSCA from becoming too weird. Better portability, as noted above. Clearer error messages. Cons: Not very straightforward parsing. The "broad" approach is straightforward. Too narrow. Why not allow the freedom that the "broad" approach allows? "COMBINED" PROPOSAL Bear with me here, this might sound complex but it really isn't very. :) The idea is to allow the use of "$" everywhere, just like the "broad" proposal. However, if the "$" is structured as a-map-with-a-single-string-key-that-has-a-list-as-its-value then will consider it specifically to be a function call, meaning that again unrecognized function names do not have to emit and error and can be implemented as stubs. This does mix some of the pros and cons of both approaches. MY THOUGHTS Implementations will do whatever they want anyway. However, I do think the idea of recognizing function calls, specifically, is an important and portable feature. Thus I am leaning on the "combined" proposal. On Tue, Apr 6, 2021 at 10:35 AM Tal Liron < tliron@redhat.com > wrote: As a corollary to my proposal for a prefix character for function names, I would add that we would need a prefix character for our "magic names", too, and for many of the same reasons. Here's a simple example that shows the problem: topology_template: node_templates: SELF: type: ServerPool properties: name: mypool IMPLEMENTATION: type: Server properties: name: nyname additional_name: { @get_property [ SELF, name ] } # here we mean ourselves pool_name: { @get_property [ SELF, name ] } # here we mean the node template named 'SELF' The above is obviously broken in TOSCA. Basically all the magic keywords cannot be used as template names. This doesn't sound like a big deal, but certain edge cases can be problematic, e.g. a TOSCA code generator. Let's fix this by using a prefix (which is again escapable by doubling): topology_template: node_templates: SELF: type: ServerPool properties: name: mypool IMPLEMENTATION: type: Server properties: name: nyname additional_name: { @get_property [ @self, name ] } # no ambiguity, magic name is prefixed pool_name: { @get_property [ SELF, name ] } # no ambiguity, it's a template name The escaping rule is very clear (use "@@" for anything that needs to begin with "@") and is deterministically possible to algortihmize into things like TOSCA generators without them having to be hardcoded with a list of forbidden magic names. Another aspect to this -- if we want to talk about allowing TOSCA to be extended by adding custom functions, it's very useful in the same context to talk about extending via custom magic names. From an implementation perspective they really are the same, there's just a simpler syntax allowed here for a zero argument function call. E.g. you can think of the "@self" magic name as syntactically equivalent to this: value: { @self: [] } I think it's worth allowing this if we already want to allow custom functions, as it can lead to cleaner syntax. For example, there would be a way here to recreate the Simple Profile's "HOST" magic name. This is a feature we removed from TOSCA 2.0 for good reasons -- it's extremely implementation-specific. Well, then, specific implementations of TOSCA could allow for such useful features by such grammatical extensions.