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). > >
