You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@brooklyn.apache.org by Aled Sage <al...@gmail.com> on 2018/09/18 16:05:04 UTC

PROPOSAL: conditional config constraints

Hi all,

I'd like to add support for more sophisticated config constraints, where 
there are inter-dependencies between config keys. I'd like the blueprint 
composer web-console to understand (a small number of) these, and thus 
to give feedback to the user about what is required and whether their 
blueprint is valid.

For example, a blueprint that requires exactly one of config X or config 
Y. Another example: config X2 is required if and only if config X1 is 
supplied.

There are a few questions / decision points:

  1. What constraints should we support out-of-the-box?
  2. What naming convention do we use, so that the UI can parse + 
understand these?
  3. Should we support multiple constraints (we do in the REST api, but 
not currently in the Java API or in the Blueprint Composer UI)

---
I suggest we support things like:

     constraints:
       - requiredUnless("Y")
       - forbiddenIf("Y")

and:

     constraints:
       - requiredIf("X1")
       - forbiddenUnless("X1")

The structure of this string would be:

     {required,forbidden}{If,Unless}("<config>")

     requiredIf("X1"):      value is required if config X1 is set; 
otherwise optional.
     forbiddenUnless("X1"): value must be null if config X1 is not set; 
otherwise optional.
     requiredUnless("Y"):   value is required if config Y is not set; 
otherwise optional.
     forbiddenIf("Y"):      value must be null if config Y is set; 
otherwise optional.

I don't think we want to get too sophisticated. For example, do *not* 
support "must match regex '[a-z]+' unless config Y is present". I don't 
think we should create a full-blown DSL for this!

---
Implementation notes:

We already have the basis of this in our Java code. We support a 
predicate of type 
`org.apache.brooklyn.core.objs.BrooklynObjectPredicate`, which has the 
additional method `boolean apply(T input, BrooklynObject context)`. The 
`BrooklynObject` could be an entity, or location, etc. An implementation 
of this predicate can therefore lookup other config key's values, when 
validating the value.

For the UI, the Blueprint Composer calls:

http://localhost:8081/v1/catalog/bundles/<bundle>/<version>/types/<blueprint>/latest

This returns things like:

     "config": [
       {
         "name": "myPredicate",
         "type": "java.lang.String",
         "reconfigurable": false,
         "label": "myPredicate",
         "pinned": false,
         "constraints": [
           "MyPredicateToString()"
         ],
         "links": {}
       },
       ...

The constraint returned here is the toString() of the predicate.

In the UI [1], there is currently some very simple logic to interpret 
this string for particular types of constraint.

Aled

[1] 
brooklyn-ui/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js


Re: PROPOSAL: conditional config constraints

Posted by Thomas Bouron <th...@cloudsoftcorp.com>.
+1 great addition!

I'm also in favour of returning YAML instead of plain string, will make the
UI work way easier.
Alex, I just eyeballed your PR, looks good but left a comment and question
there.

Best.

On Fri, 21 Sep 2018 at 12:34 Alex Heneveld <al...@cloudsoftcorp.com>
wrote:

>
> +1
>
> I've implemented this for the server side at
> https://github.com/apache/brooklyn-server/pull/999 .
>
> One minor tweak to Aled's proposal, I think we should output a
> structured YAML rather than the toString, so clients don't have to do
> complex parsing.  IE instead of sending the string syntax
> `requiredUnless("X")` we'd send `requiredUnless: X`.  (On input we can
> accept either representation, a toString or yaml.)
>
> Will add support in the UI next (new PR obviously).
>
> Best
> Alex
>
>
> On 21/09/2018 09:08, Geoff Macartney wrote:
> > Hi Aled,
> >
> > I'd say go for it, that looks like something that could be valuable in
> > various cases.
> > I take it your example of "exactly one of config X or config Y" would be
> > expressed
> > along the lines of a parallel set of constraints between each config -
> >
> > On X:
> >       constraints:
> >         - requiredUnless("Y")
> >         - forbiddenIf("Y")
> >
> > On Y:
> >       constraints:
> >         - requiredUnless("X")
> >         - forbiddenIf("X")
> >
> > Geoff
> >
> >
> > On Tue, 18 Sep 2018 at 17:05 Aled Sage <al...@gmail.com> wrote:
> >
> >> Hi all,
> >>
> >> I'd like to add support for more sophisticated config constraints, where
> >> there are inter-dependencies between config keys. I'd like the blueprint
> >> composer web-console to understand (a small number of) these, and thus
> >> to give feedback to the user about what is required and whether their
> >> blueprint is valid.
> >>
> >> For example, a blueprint that requires exactly one of config X or config
> >> Y. Another example: config X2 is required if and only if config X1 is
> >> supplied.
> >>
> >> There are a few questions / decision points:
> >>
> >>    1. What constraints should we support out-of-the-box?
> >>    2. What naming convention do we use, so that the UI can parse +
> >> understand these?
> >>    3. Should we support multiple constraints (we do in the REST api, but
> >> not currently in the Java API or in the Blueprint Composer UI)
> >>
> >> ---
> >> I suggest we support things like:
> >>
> >>       constraints:
> >>         - requiredUnless("Y")
> >>         - forbiddenIf("Y")
> >>
> >> and:
> >>
> >>       constraints:
> >>         - requiredIf("X1")
> >>         - forbiddenUnless("X1")
> >>
> >> The structure of this string would be:
> >>
> >>       {required,forbidden}{If,Unless}("<config>")
> >>
> >>       requiredIf("X1"):      value is required if config X1 is set;
> >> otherwise optional.
> >>       forbiddenUnless("X1"): value must be null if config X1 is not set;
> >> otherwise optional.
> >>       requiredUnless("Y"):   value is required if config Y is not set;
> >> otherwise optional.
> >>       forbiddenIf("Y"):      value must be null if config Y is set;
> >> otherwise optional.
> >>
> >> I don't think we want to get too sophisticated. For example, do *not*
> >> support "must match regex '[a-z]+' unless config Y is present". I don't
> >> think we should create a full-blown DSL for this!
> >>
> >> ---
> >> Implementation notes:
> >>
> >> We already have the basis of this in our Java code. We support a
> >> predicate of type
> >> `org.apache.brooklyn.core.objs.BrooklynObjectPredicate`, which has the
> >> additional method `boolean apply(T input, BrooklynObject context)`. The
> >> `BrooklynObject` could be an entity, or location, etc. An implementation
> >> of this predicate can therefore lookup other config key's values, when
> >> validating the value.
> >>
> >> For the UI, the Blueprint Composer calls:
> >>
> >> http://localhost:8081/v1/catalog/bundles/
> >> <bundle>/<version>/types/<blueprint>/latest
> >>
> >> This returns things like:
> >>
> >>       "config": [
> >>         {
> >>           "name": "myPredicate",
> >>           "type": "java.lang.String",
> >>           "reconfigurable": false,
> >>           "label": "myPredicate",
> >>           "pinned": false,
> >>           "constraints": [
> >>             "MyPredicateToString()"
> >>           ],
> >>           "links": {}
> >>         },
> >>         ...
> >>
> >> The constraint returned here is the toString() of the predicate.
> >>
> >> In the UI [1], there is currently some very simple logic to interpret
> >> this string for particular types of constraint.
> >>
> >> Aled
> >>
> >> [1]
> >>
> >>
> brooklyn-ui/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
> >>
> >>
>
> --

Thomas Bouron
Senior Software Engineer

*Cloudsoft <https://cloudsoft.io/> *| Bringing Business to the Cloud

GitHub: https://github.com/tbouron
Twitter: https://twitter.com/eltibouron

Need a hand with AWS? Get a Free Consultation.

Re: PROPOSAL: conditional config constraints

Posted by Alex Heneveld <al...@cloudsoftcorp.com>.
+1

I've implemented this for the server side at 
https://github.com/apache/brooklyn-server/pull/999 .

One minor tweak to Aled's proposal, I think we should output a 
structured YAML rather than the toString, so clients don't have to do 
complex parsing.  IE instead of sending the string syntax 
`requiredUnless("X")` we'd send `requiredUnless: X`.  (On input we can 
accept either representation, a toString or yaml.)

Will add support in the UI next (new PR obviously).

Best
Alex


On 21/09/2018 09:08, Geoff Macartney wrote:
> Hi Aled,
>
> I'd say go for it, that looks like something that could be valuable in
> various cases.
> I take it your example of "exactly one of config X or config Y" would be
> expressed
> along the lines of a parallel set of constraints between each config -
>
> On X:
>       constraints:
>         - requiredUnless("Y")
>         - forbiddenIf("Y")
>
> On Y:
>       constraints:
>         - requiredUnless("X")
>         - forbiddenIf("X")
>
> Geoff
>
>
> On Tue, 18 Sep 2018 at 17:05 Aled Sage <al...@gmail.com> wrote:
>
>> Hi all,
>>
>> I'd like to add support for more sophisticated config constraints, where
>> there are inter-dependencies between config keys. I'd like the blueprint
>> composer web-console to understand (a small number of) these, and thus
>> to give feedback to the user about what is required and whether their
>> blueprint is valid.
>>
>> For example, a blueprint that requires exactly one of config X or config
>> Y. Another example: config X2 is required if and only if config X1 is
>> supplied.
>>
>> There are a few questions / decision points:
>>
>>    1. What constraints should we support out-of-the-box?
>>    2. What naming convention do we use, so that the UI can parse +
>> understand these?
>>    3. Should we support multiple constraints (we do in the REST api, but
>> not currently in the Java API or in the Blueprint Composer UI)
>>
>> ---
>> I suggest we support things like:
>>
>>       constraints:
>>         - requiredUnless("Y")
>>         - forbiddenIf("Y")
>>
>> and:
>>
>>       constraints:
>>         - requiredIf("X1")
>>         - forbiddenUnless("X1")
>>
>> The structure of this string would be:
>>
>>       {required,forbidden}{If,Unless}("<config>")
>>
>>       requiredIf("X1"):      value is required if config X1 is set;
>> otherwise optional.
>>       forbiddenUnless("X1"): value must be null if config X1 is not set;
>> otherwise optional.
>>       requiredUnless("Y"):   value is required if config Y is not set;
>> otherwise optional.
>>       forbiddenIf("Y"):      value must be null if config Y is set;
>> otherwise optional.
>>
>> I don't think we want to get too sophisticated. For example, do *not*
>> support "must match regex '[a-z]+' unless config Y is present". I don't
>> think we should create a full-blown DSL for this!
>>
>> ---
>> Implementation notes:
>>
>> We already have the basis of this in our Java code. We support a
>> predicate of type
>> `org.apache.brooklyn.core.objs.BrooklynObjectPredicate`, which has the
>> additional method `boolean apply(T input, BrooklynObject context)`. The
>> `BrooklynObject` could be an entity, or location, etc. An implementation
>> of this predicate can therefore lookup other config key's values, when
>> validating the value.
>>
>> For the UI, the Blueprint Composer calls:
>>
>> http://localhost:8081/v1/catalog/bundles/
>> <bundle>/<version>/types/<blueprint>/latest
>>
>> This returns things like:
>>
>>       "config": [
>>         {
>>           "name": "myPredicate",
>>           "type": "java.lang.String",
>>           "reconfigurable": false,
>>           "label": "myPredicate",
>>           "pinned": false,
>>           "constraints": [
>>             "MyPredicateToString()"
>>           ],
>>           "links": {}
>>         },
>>         ...
>>
>> The constraint returned here is the toString() of the predicate.
>>
>> In the UI [1], there is currently some very simple logic to interpret
>> this string for particular types of constraint.
>>
>> Aled
>>
>> [1]
>>
>> brooklyn-ui/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
>>
>>


Re: PROPOSAL: conditional config constraints

Posted by Aled Sage <al...@gmail.com>.
Hi Geoff, all,

You're example is correct - that is what I'd write. I don't think 
there's a short way to convey this info without using two such 
predicates, or implementing a full-blown DSL.

I wondered about including an "iff" (i.e. "if and only if"), but that 
doesn't add much. For example, e.g. "forbiddenIff("Y")` doesn't tell us 
it's required if Y is not defined. Simiarly, `requiredIffNot("Y")` would 
not tell us it's forbidden if Y is defined.

I'll push ahead with the proposal from my original email, starting with 
the server-side.

Aled


On 21/09/2018 09:08, Geoff Macartney wrote:
> Hi Aled,
>
> I'd say go for it, that looks like something that could be valuable in
> various cases.
> I take it your example of "exactly one of config X or config Y" would be
> expressed
> along the lines of a parallel set of constraints between each config -
>
> On X:
>       constraints:
>         - requiredUnless("Y")
>         - forbiddenIf("Y")
>
> On Y:
>       constraints:
>         - requiredUnless("X")
>         - forbiddenIf("X")
>
> Geoff
>
>
> On Tue, 18 Sep 2018 at 17:05 Aled Sage <al...@gmail.com> wrote:
>
>> Hi all,
>>
>> I'd like to add support for more sophisticated config constraints, where
>> there are inter-dependencies between config keys. I'd like the blueprint
>> composer web-console to understand (a small number of) these, and thus
>> to give feedback to the user about what is required and whether their
>> blueprint is valid.
>>
>> For example, a blueprint that requires exactly one of config X or config
>> Y. Another example: config X2 is required if and only if config X1 is
>> supplied.
>>
>> There are a few questions / decision points:
>>
>>    1. What constraints should we support out-of-the-box?
>>    2. What naming convention do we use, so that the UI can parse +
>> understand these?
>>    3. Should we support multiple constraints (we do in the REST api, but
>> not currently in the Java API or in the Blueprint Composer UI)
>>
>> ---
>> I suggest we support things like:
>>
>>       constraints:
>>         - requiredUnless("Y")
>>         - forbiddenIf("Y")
>>
>> and:
>>
>>       constraints:
>>         - requiredIf("X1")
>>         - forbiddenUnless("X1")
>>
>> The structure of this string would be:
>>
>>       {required,forbidden}{If,Unless}("<config>")
>>
>>       requiredIf("X1"):      value is required if config X1 is set;
>> otherwise optional.
>>       forbiddenUnless("X1"): value must be null if config X1 is not set;
>> otherwise optional.
>>       requiredUnless("Y"):   value is required if config Y is not set;
>> otherwise optional.
>>       forbiddenIf("Y"):      value must be null if config Y is set;
>> otherwise optional.
>>
>> I don't think we want to get too sophisticated. For example, do *not*
>> support "must match regex '[a-z]+' unless config Y is present". I don't
>> think we should create a full-blown DSL for this!
>>
>> ---
>> Implementation notes:
>>
>> We already have the basis of this in our Java code. We support a
>> predicate of type
>> `org.apache.brooklyn.core.objs.BrooklynObjectPredicate`, which has the
>> additional method `boolean apply(T input, BrooklynObject context)`. The
>> `BrooklynObject` could be an entity, or location, etc. An implementation
>> of this predicate can therefore lookup other config key's values, when
>> validating the value.
>>
>> For the UI, the Blueprint Composer calls:
>>
>> http://localhost:8081/v1/catalog/bundles/
>> <bundle>/<version>/types/<blueprint>/latest
>>
>> This returns things like:
>>
>>       "config": [
>>         {
>>           "name": "myPredicate",
>>           "type": "java.lang.String",
>>           "reconfigurable": false,
>>           "label": "myPredicate",
>>           "pinned": false,
>>           "constraints": [
>>             "MyPredicateToString()"
>>           ],
>>           "links": {}
>>         },
>>         ...
>>
>> The constraint returned here is the toString() of the predicate.
>>
>> In the UI [1], there is currently some very simple logic to interpret
>> this string for particular types of constraint.
>>
>> Aled
>>
>> [1]
>>
>> brooklyn-ui/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
>>
>>


Re: PROPOSAL: conditional config constraints

Posted by Geoff Macartney <ge...@gmail.com>.
Hi Aled,

I'd say go for it, that looks like something that could be valuable in
various cases.
I take it your example of "exactly one of config X or config Y" would be
expressed
along the lines of a parallel set of constraints between each config -

On X:
     constraints:
       - requiredUnless("Y")
       - forbiddenIf("Y")

On Y:
     constraints:
       - requiredUnless("X")
       - forbiddenIf("X")

Geoff


On Tue, 18 Sep 2018 at 17:05 Aled Sage <al...@gmail.com> wrote:

> Hi all,
>
> I'd like to add support for more sophisticated config constraints, where
> there are inter-dependencies between config keys. I'd like the blueprint
> composer web-console to understand (a small number of) these, and thus
> to give feedback to the user about what is required and whether their
> blueprint is valid.
>
> For example, a blueprint that requires exactly one of config X or config
> Y. Another example: config X2 is required if and only if config X1 is
> supplied.
>
> There are a few questions / decision points:
>
>   1. What constraints should we support out-of-the-box?
>   2. What naming convention do we use, so that the UI can parse +
> understand these?
>   3. Should we support multiple constraints (we do in the REST api, but
> not currently in the Java API or in the Blueprint Composer UI)
>
> ---
> I suggest we support things like:
>
>      constraints:
>        - requiredUnless("Y")
>        - forbiddenIf("Y")
>
> and:
>
>      constraints:
>        - requiredIf("X1")
>        - forbiddenUnless("X1")
>
> The structure of this string would be:
>
>      {required,forbidden}{If,Unless}("<config>")
>
>      requiredIf("X1"):      value is required if config X1 is set;
> otherwise optional.
>      forbiddenUnless("X1"): value must be null if config X1 is not set;
> otherwise optional.
>      requiredUnless("Y"):   value is required if config Y is not set;
> otherwise optional.
>      forbiddenIf("Y"):      value must be null if config Y is set;
> otherwise optional.
>
> I don't think we want to get too sophisticated. For example, do *not*
> support "must match regex '[a-z]+' unless config Y is present". I don't
> think we should create a full-blown DSL for this!
>
> ---
> Implementation notes:
>
> We already have the basis of this in our Java code. We support a
> predicate of type
> `org.apache.brooklyn.core.objs.BrooklynObjectPredicate`, which has the
> additional method `boolean apply(T input, BrooklynObject context)`. The
> `BrooklynObject` could be an entity, or location, etc. An implementation
> of this predicate can therefore lookup other config key's values, when
> validating the value.
>
> For the UI, the Blueprint Composer calls:
>
> http://localhost:8081/v1/catalog/bundles/
> <bundle>/<version>/types/<blueprint>/latest
>
> This returns things like:
>
>      "config": [
>        {
>          "name": "myPredicate",
>          "type": "java.lang.String",
>          "reconfigurable": false,
>          "label": "myPredicate",
>          "pinned": false,
>          "constraints": [
>            "MyPredicateToString()"
>          ],
>          "links": {}
>        },
>        ...
>
> The constraint returned here is the toString() of the predicate.
>
> In the UI [1], there is currently some very simple logic to interpret
> this string for particular types of constraint.
>
> Aled
>
> [1]
>
> brooklyn-ui/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
>
>