osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: PROPOSAL: conditional config constraints


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 <aled.sage@xxxxxxxxx> 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