Hi Geoff,

I think long-term you're example would be covered by "Defining an Effector as a Sequence of Tasks". That topic needs a lot more (separate!) discussion, but in brief the idea is that an effector definition is a first-class concept in the yaml (rather than using "entity.initializers"); there would be yaml-support for defining a sequence of tasks (e.g. execute some bash, do a http call, make an effector call, etc). The yaml for "make an effector call" might end up looking similar to this DSL discussion, but the context in which it would be used is very different.

---
I think the key question for this discussion is: should we support effector-invocation via the DSL *for config values*?

If so:

1. What use-case(s) are we trying to support?
2. Should the effector be executed every time the config value is
   retrieved, or only once (and the result stored for subsequent lookups)?
3. Should it be relied upon for side-effects (e.g. the CA certificate
   request example etc)?
4. Or should it only be used for effectors that are getters/lookups?

For (3), I now lean towards the use of the EntityInitializer (and longer term the "sequence of tasks" approach).

For (4), I'm not sure what a good use-case is (e.g. why can't we set a sensor with that value, which might require extending the "source" entity to add an additional "sensor feed" that retrieves the value for us).

For (2), I'm not sure what is most intuitive to users who are reading/writing the blueprint yaml. It could be argued either way, which suggests different users will expect different things! Therefore I'd want to avoid relying on side-effects that you only want to happen once!

Aled


On 02/03/2017 10:30, Geoff Macartney wrote:
I don't think we should just be thinking about a use-case like the CA
server, which is maybe more limited in behaviour than the more general idea
here of being able to call effectors.

In particular, what if you wanted to embed the effector invocation on some
entity within the code for an effector of your own entity?   i.e. you have
an effector on entity A that does some stuff when invoked, including
invoking an effector on entity B?  (And maybe using the result when
calculating its own result instead of storing it in a sensor).

Is that something we'd want to support?    Is it a "stage 2" thing we would
add later on, some time after implementing the EntityInitializer approach?

G

On Wed, 1 Mar 2017 at 12:32 Alex Heneveld <[email protected]>
wrote:

An `EntityInitializer` for this purpose is a nice alternative pattern --
better than the child entity I suggested at #155 -- until we have sequence
effector YAML.  Is there anything `$brooklyn:effector` gives us that an
initializer wouldn't do in a cleaner way?

Best
Alex


On 1 March 2017 at 11:54, Aled Sage <[email protected]> wrote:

Hi all,

I'd like to resurrect the discussion of whether the yaml DSL should
support invoking effectors.

See https://github.com/apache/brooklyn-server/pull/155. (That was merged,
but Alex will revert it while we discuss if we want it, and if so then how
it would behave).

If folk have additional use-cases and opinions to share, that would be
very useful!

---

Below is what Andrew wrote in his email "[PROPOSAL] Enabling Effective
Effectors" on 30/05/2016, but it wasn't properly discussed then.

    ## Calling Effectors

    The YAML blueprint specification allows entities to be defined with
    sensors
    and to access the value of sensors for use in configuration. However,
    although an entity can include effectors defined in the Java classes,
or
    using scripting languages (see above) and SSH commands, it is not
    possible
    to execute effectors and retrieve their results anywhere in a
blueprint.
    The code in [brooklyn-server#155](
    https://github.com/apache/brooklyn-server/pull/155) implements a new
    function for the `DslComponent` class that can execute an effector on
an
    entity and evaluates to its return value. This new function is used as
    follows:

    ```YAML
    $brooklyn:entity("other").effector("findInformation"):
       args:
         arg1: "value"
         arg2: 3.14159d
         arg3: $brooklyn:attributeWhenReady("host.address")
    ```

    Here we see the effector `findInformation` being evaluated with three
    arguments, on the entity with id `other`. One of the arguments is an
    `attributeWhenReady` call, thus causing the execution to be delayed
    until
    the sensor data is available.

---
Alex's philosophical objection in https://github.com/apache/broo
klyn-server/pull/155#issuecomment-283077136 is copied below for your
convenience):

    right, so the use case is one entity wanting to get information from
    another. is there no way this can be accommodated using sensors? my
    philosophical objection is that we're introducing first-class
    support for a new class of dependency injection:

     1. simplest - static: DEP.x is set to a constant
     2. blocking - sensor: DEP.x can wait if a value isn't ready yet, ie
        it is a promise, $brooklyn:entity(SRC).attributeWhenReady(...),
        which once resolved is always taken as the value
     3. triggering - effector: every lookup to DEP.x invokes a call
        somewhere eg $brooklyn:entity(SRC).effector(...)

    A widespread use of (3) scares me [Alex] and it's worth avoiding
    this if at all possible. it also means lookups aren't idempotent
    (which is why the SideEffecting marker is introduced here, but it
    isn't going to work.

    could your [use-case] be solved another way, if not with waiting on
    a sensor, by the config pointing at the source entity rather than
    the key value itself, and whenever it is accessed there is code
    which invokes the effector to get the key on that source entity?


---
I believe the original use-case that motivated this was setting up a
docker host, with certificates dynamically generated by a CA Server
(Certificate Authority).

The blueprint has a CA Server entity and several Docker Host entities. For
setting up each Docker Host, we want a new certifiacte that is signed by
the CA. We want to put the certificate files onto the Docker Host (so that
the Docker Engine is correctly configured for TLS).

There is an effector on the CA entity, to send it a Certificate Signing
Request (CSR), and thus to get back a new certificate.

One solution in pure-yaml blueprints (simplified slightly for clarity in
this discussion) would be to have a "certificate" config key on the Docker
Host entity. This would be set to a value like:

    brooklyn.config:
       certificateData:
    $brooklyn:entity("ca").effector("requestCertificate"):
           args:
             ip: $brooklyn:config("host.address")

Part of the setup script would use this config key, and create a file
using its value.

When the config key was evaluated for the first time, it would execute the
effector and thus get a new certificate. Subsequent lookups of the config
key would use the same value (rather than invoking the effector multiple
times).

Note the significant difference compared to Alex's summary, where Alex
suggested the effector would be invoked every time the config key value
was
retrieved.

===
Below are some alternative ways to solve the above use-case. I don't want
us to get too distracted in this discussion of "yaml DSL for invoking
effectors". However, if we reach agreement that one of these alternative
is
better then we can ignore the use-case that I've described above.

_*Resort to Java*_
We could resort to writing some Java code (e.g. write an
"EntityInitializer" that called the requestCertificate effector, and set
the result as a sensor; this could be added to the Docker Host entity. The
rest of the Docker Host blueprint would use attributeWhenReady on the
"certificateData" sensor.

There could be a generic EntityInitializer for invoking a given effector
on a given entity, and setting a sensor with the result.

_*Defining an Effector as a Sequence of Tasks*_
Longer term, we could add YAML support for describing a sequence of tasks.
The basic Docker Host entity would be extended so that its "start"
effector
first invoked a task, which would call the "requestCertificate" effector
on
the CA (and probably set the result as a sensor or config key).



Reply via email to