Design pattern for inter bundle dependencies

64 views
Skip to first unread message

Yann Soubeyrand

unread,
Oct 23, 2016, 11:39:11 AM10/23/16
to help-cfengine
Hi,

I need to write a policy to install Apache and some webapps using virtual hosts. I'd like to organise my policy having a bundle for Apache and a bundle per webapps. The problem is that I need the apache package to be installed before I deploy the webapps in order to give to the apache user ownership on some files of the webapps, but I also need the apache service being started after having deployed all the webapps in order to take into account their virtual hosts.

What is the design pattern, if there is some, in this case and similar ones (which seem to be quite common)?

Thanks in advance,
Regards

Yann

Aleksey Tsalolikhin

unread,
Oct 23, 2016, 3:32:59 PM10/23/16
to Yann Soubeyrand, help-cfengine

Yann, you can link promises together with classes ifrepaired.  Check out slides 31 and 32 in cf-primer. https://digitalelf.net/cf-primer/#(31)


--
You received this message because you are subscribed to the Google Groups "help-cfengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to help-cfengine+unsubscribe@googlegroups.com.
To post to this group, send email to help-c...@googlegroups.com.
Visit this group at https://groups.google.com/group/help-cfengine.
For more options, visit https://groups.google.com/d/optout.

Aleksey Tsalolikhin

unread,
Oct 23, 2016, 11:54:09 PM10/23/16
to Yann Soubeyrand, help-cfengine

You might also check out www.cfenginetutorial.org

I see you've found the IRC channel already. : )

Moore, Joe

unread,
Oct 24, 2016, 11:25:31 AM10/24/16
to help-cfengine

For your specific case, it's not as hard as you might think:

 

cfengine will "not_repaired" file promises for owners that do not exist.  If you promise "/etc/httpd/sites.available/mysite.conf" owner => "apache"; cfengine will make sure that happens once the apache user exists.  Similarly, if you have a separate user for the webapps, they can be enforced "eventually".  These implicit dependencies are better handled with--

 

The depends_on  attribute for the promise!… Description: A list of promise handles for promises that must have an outcome of KEPT or REPAIRED in order for the promise to be actuated.

 

#!/var/cfengine/bin/cf-agent -vbmain

bundle agent main {

  packages:

      "apache2"

        handle => "install_apache_pkg",

        policy => "present",

        package_module => apt_get,

        version => "latest";

       

  files:

      "/var/tomcat/webapps/mycoolwebapp1.jar"

        handle => "webapp1_jar_copy",

        copy_from => rcp("/deploy/mycoolwebapp1.jar", $(sys.policy_hub));

 

      "/etc/httpd/sites.availabe/webapp1.conf"

        owner => "webappdeveloper",  # This implicitly depends on the users: promise below.

        depends_on => { "install_apache_pkg", "webapp1_jar_copy" };

  users:

      "webappdeveloper"

        policy => "present",

        password => hashed_password("$6$the/string/youd/find/in/shadow");

}

body file control { inputs => {"$(sys.libdir)/stdlib.cf";}

 

 

This example will take at least 2 passes (of running cf-agent) and maybe up to 5, to converge to having everything installed right, but the system is at a stable (although misconfigured) state after each execution.

 

--Joe

--

You received this message because you are subscribed to the Google Groups "help-cfengine" group.

To unsubscribe from this group and stop receiving emails from it, send an email to help-cfengin...@googlegroups.com.

Yann Soubeyrand

unread,
Oct 24, 2016, 2:12:40 PM10/24/16
to help-c...@googlegroups.com
Hi,

Thanks for your answers! I think I wasn't clear enough in stating my
problem. I already know the various mechanisms to express dependencies
between promises. For example, in a first approach, I would write my
policy as is:

bundle agent apache
{
packages:

"apache2"
handle => "package_apache2",
package_module => apt_get,
policy => "present";

files:

"/etc/apache2/sites-enabled/webapp-1.conf"
handle => "file_etc_apache2_sites_enabled_webapp_1_conf",
create => "true",
edit_template => "$(this.promise_dirname)/webapp-1.conf",
depends_on => { "package_apache2" };

"/etc/apache2/sites-enabled/webapp-2.conf"
handle => "file_etc_apache2_sites_enabled_webapp_2_conf",
create => "true",
edit_template => "$(this.promise_dirname)/webapp-2.conf",
depends_on => { "package_apache2" };

"/srv/www/webapp-1/."
handle => "directory_srv_www_webapp_1",
create => "true",
copy_from => secure_cp("$(this.promise_dirname)/webapp-1/", "$(sys.policy_hub)"),
depth_search => recurse(inf),
perms => og("www-data", "www-data"),
depends_on => { "package_apache2" };

"/srv/www/webapp-2/."
handle => "directory_srv_www_webapp_2",
create => "true",
copy_from => secure_cp("$(this.promise_dirname)/webapp-2/", "$(sys.policy_hub)"),
depth_search => recurse(inf),
perms => og("www-data", "www-data"),
depends_on => { "package_apache2" };

services:

"apache2"
handle => "service_apache2",
service_policy => "start",
depends_on =>
{
"package_apache2",
"file_etc_apache2_sites_enabled_webapp_1_conf",
"file_etc_apache2_sites_enabled_webapp_2_conf",
"directory_srv_www_webapp_1",
"directory_srv_www_webapp_2"
};
}

But then, I'll need modularity in my policy because I'd like to reuse my
apache bundle on various hosts and I'll rewrite my policy as is:

bundle main
{
vars:

"webapps"
ilist => { "1", "2" };

methods:

"apache"
usebundle => apache("@(webapps)");
}


bundle agent apache(webapps)
{
packages:

"apache2"
handle => "package_apache2",
package_module => apt_get,
policy => "present";

methods:

"webapp"
handle => "webapp_$(webapps)",
usebundle => webapp("$(webapps)"),
depends_on => { "package_apache2" };

services:

"apache2"
handle => "service_apache2",
service_policy => "start",
depends_on =>
{
"package_apache2",
maplist("webapp_$(this)", "webapps")
};
}

bundle agent webapp(i)
{
files:

"/etc/apache2/sites-enabled/webapp-$(i).conf"
handle => "file_etc_apache2_sites_enabled_webapp_$(i)_conf",
create => "true",
edit_template => "$(this.promise_dirname)/webapp-$(i).conf";

"/srv/www/webapp-$(i)/."
handle => "directory_srv_www_webapp_$(i)",
create => "true",
copy_from => secure_cp("$(this.promise_dirname)/webapp-$(i)/", "$(sys.policy_hub)"),
depth_search => recurse(inf),
perms => og("www-data", "www-data");
}

But then my needs will evolve and I'll have to add PHP in the picture
and I'll need to install PHP before deploying my webapps (in order to do
some deployment steps using PHP interpreter) but I'll also need to start
PHP service after having enabled PHP FPM pools for my webapps and I'll
end up with something far too complicated to maintain.

My question is: is there a design pattern for this (having a modular
policy with reusable bundles [or sketches] while still being able to
manage the aforementioned kind of dependencies)?

Regards

Yann

Neil Watson

unread,
Oct 24, 2016, 4:13:32 PM10/24/16
to help-c...@googlegroups.com
If I understand your need correctly, order may not be as important as
you think. Order is a habit we gained from the Old Days of scripting.
It's not important what order Apache or PHP are installed and configured
in. Cf-agent will converge to the desired state in one run or two if
some arbitrary dependency constrains it. So long as the cf-agent run
frequency is high don't worry about order so much. Worrying less about
order is liberating. Try it and see.

--
Neil H Watson @neil_h_watson
CFEngine reporting: https://github.com/neilhwatson/delta_reporting
CFEngine policy: https://github.com/neilhwatson/evolve_cfengine_freelib
CFEngine and vim: https://github.com/neilhwatson/vim_cf3

Ted Zlatanov

unread,
Oct 24, 2016, 8:15:58 PM10/24/16
to help-c...@googlegroups.com
On Mon, 24 Oct 2016 20:13:58 +0200 Yann Soubeyrand <yann.so...@gmx.fr> wrote:

YS> My question is: is there a design pattern for this (having a modular
YS> policy with reusable bundles [or sketches] while still being able to
YS> manage the aforementioned kind of dependencies)?

If I was designing this, I'd think about it as an event subscription
mechanism.

The most natural way today in CFEngine to do it, I think, is with class
and bundle metadata.

The event generator would tag the classes with the right metadata to
indicate the event type and parameters.

All the event handlers would be discovered and called by the bundle
metadata. Each event handler would grab the classes for its type and
record which ones have been handled, to make it convergent. If the core
provided an actual event queue, however, that would be tremendously
helpful.

(I think it would be a very interesting direction if the event
subscriptions could be done across managed nodes, not just locally. This
kind of multi-node cooperative multiprocessing has been discussed
before. Tools like Docker Swarm are new attempts to solve this, and the
resulting toolkit (Docker Infrakit) is available for embedding.)

Ted

Ted Zlatanov

unread,
Oct 25, 2016, 10:27:53 AM10/25/16
to help-c...@googlegroups.com
On Mon, 24 Oct 2016 20:15:04 -0400 Ted Zlatanov <t...@lifelogs.com> wrote:

TZ> If I was designing this, I'd think about it as an event subscription
TZ> mechanism.

TZ> The most natural way today in CFEngine to do it, I think, is with class
TZ> and bundle metadata.

TZ> The event generator would tag the classes with the right metadata to
TZ> indicate the event type and parameters.

TZ> All the event handlers would be discovered and called by the bundle
TZ> metadata. Each event handler would grab the classes for its type and
TZ> record which ones have been handled, to make it convergent. If the core
TZ> provided an actual event queue, however, that would be tremendously
TZ> helpful.

A simple implementation of event handling the way I described (without
convergency) is at https://github.com/cfengine/masterfiles/pull/816

Ted

Yann Soubeyrand

unread,
Oct 25, 2016, 1:59:13 PM10/25/16
to help-c...@googlegroups.com
Le lundi 24 octobre 2016 à 14:29 -0400, Neil Watson a écrit :
> If I understand your need correctly, order may not be as important as
> you think. Order is a habit we gained from the Old Days of scripting.
> It's not important what order Apache or PHP are installed and configured
> in. Cf-agent will converge to the desired state in one run or two if
> some arbitrary dependency constrains it. So long as the cf-agent run
> frequency is high don't worry about order so much. Worrying less about
> order is liberating. Try it and see.

Hi,

I'm not sure to understand what you mean by not worrying about ordering
because it will eventually converge. Does it means restarting apache
each time cf-agent runs in order to take into account configuration
changes (like a new virtual host) that could have taken place the run
before? Or maybe using persistent classes to restart apache only when
needed?

Regards

Yann

Yann Soubeyrand

unread,
Oct 25, 2016, 2:18:25 PM10/25/16
to help-c...@googlegroups.com
Hi Ted,

Thanks for your answer and for the implementation of the event handling
lib ;-)

I think I understand how your lib works but I don't clearly see how to
use it in my case. Could you elaborate on where to place calls to
event_register and most importantly calls to event_handle?

Would you call event_register("apache", "install", "what do you put
here?", empty) after having installed apache in the apache bundle and
call event_handle("apache", "install") outside the apache bundle to call
all the webapps deployment bundles (which would have tagged themselve as
event handlers)? And would you then call event_register("apache",
"restart", "what do you put here?", metadata) in the webapps deployment
bundles each time you modify the apache configuration and then call
event_handle("apache", "restart") outside the bundles to call the apache
bundle which will then restart apache? Or am I totally missing the
point?

Regards

Yann


Aleksey Tsalolikhin

unread,
Oct 26, 2016, 12:29:32 AM10/26/16
to Yann Soubeyrand, help-cfengine

Dear Yann,

Small technical point - there is no need to restart Apache after updating configuration. You can reload configuration instead which is less disruptive.  See "/etc/init.d/httpd reload" and Apache graceful restart.

Best,
-at


--
You received this message because you are subscribed to the Google Groups "help-cfengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to help-cfengine+unsubscribe@googlegroups.com.

Ted Zlatanov

unread,
Oct 26, 2016, 6:43:13 AM10/26/16
to help-c...@googlegroups.com
On Tue, 25 Oct 2016 20:19:43 +0200 Yann Soubeyrand <yann.so...@gmx.fr> wrote:

YS> I think I understand how your lib works but I don't clearly see how to
YS> use it in my case. Could you elaborate on where to place calls to
YS> event_register and most importantly calls to event_handle?

The facility is not opinionated, it's just a voluntary contract to tag
classes with a type and a payload. I'm still not sure if the created
events should be persistent, and if they should be deleted (class
cancel) when they are collected. Those things could be optional or
mandated. I hope you and others have some opinions :)

So focusing on the current proposal for the events library... you can
register events anywhere. Then you can handle them whenever you want.
Usually the end of the regular CFEngine run is all right. It's a very
free-form system, since CFEngine itself doesn't enforce contracts.

YS> Would you call event_register("apache", "install", "what do you put
YS> here?", empty) after having installed apache in the apache bundle and
YS> call event_handle("apache", "install") outside the apache bundle to call
YS> all the webapps deployment bundles (which would have tagged themselve as
YS> event handlers)?

Yes, basically. The correct parameters are shown in the library docs and
in the usage example, and are not too important here, the point is just
to create and collect events according to the contract. You can pack
extra metadata in the last parameter, which is an slist of tags. Then
you can retrieve that metadata in the handler with
getclassmetatags("classname") or, in the upcoming 3.10, with
getclassmetatags("classname", "specific_tag_key").

YS> And would you then call event_register("apache",
YS> "restart", "what do you put here?", metadata) in the webapps deployment
YS> bundles each time you modify the apache configuration and then call
YS> event_handle("apache", "restart") outside the bundles to call the apache
YS> bundle which will then restart apache? Or am I totally missing the
YS> point?

The event could be `reload` as Aleksey mentioned, but yes that's one way
to do it.

The events are not persistent currently. So instead of delivering
installation events to trigger webapp deployments, I might use the
presence of the Apache packages instead. That way, if the CFEngine run
doesn't converge, or if someone installs Apache manually, the webapps
will still get deployed. I would still install the webapps and they
would issue `reload` events, but there wouldn't be `install` events.

Ted

Aleksey Tsalolikhin

unread,
Oct 26, 2016, 10:27:56 AM10/26/16
to Yann Soubeyrand, help-cfengine
On Tue, Oct 25, 2016 at 11:00 AM, Yann Soubeyrand <yann.so...@gmx.fr> wrote:
Le lundi 24 octobre 2016 à 14:29 -0400, Neil Watson a écrit :
> If I understand your need correctly, order may not be as important as
> you think. Order is a habit we gained from the Old Days of scripting.
> It's not important what order Apache or PHP are installed and configured
> in. Cf-agent will converge to the desired state in one run or two if
> some arbitrary dependency constrains it. So long as the cf-agent run
> frequency is high don't worry about order so much. Worrying less about
> order is liberating. Try it and see.


I'm not sure to understand what you mean by not worrying about ordering
because it will eventually converge.

This is unique to CFEngine.  Let's say you need to ensure Apache is running.

If you are doing it with a shell script or on the command line, you do things in sequence: 
1. Install Apache httpd package: yum install httpd
2. Run the service start script: service httpd start

But with CFEngine, you describe what you want declaratively:
- Apache httpd is installed (packages promise)
- Apache httpd service is running (services promise)

You *can* order the two promises, but you don't have to! 

In CFEngine Normal Ordering, packages promises are verified before services promises.

Even if they weren't, CFEngine agent does up to 3 passes over your policy during any single CFEngine agent run, so that if there is a dependency that was missing but it was fixed during the 1st pass, then the 2nd pass will fix the thing that depended on the first thing (e.g., the first pass would install apache httpd and the 2nd pass would start it).

Moreover, as Neil mentioned, CFEngine is lightweight and runs frequently, every 5 minutes out of the box -- so it may repair enough during the 1st run that it is able to complete the repair during the next run.

Mark Burgess, the author of CFEngine, used to illustrate it as a gravity well where the bottom is the desired state -- your system will just drop down the well to the ideal state.  Everything will just slot into place.  It's a different approach. :)

You might enjoy my presentation on it, 
Let me quote Mark Burgess:

Cfengine introduced the notion of ‘convergence’ into system administration. This was orginially only implicit in the early work, but was named explicitly in the Computer Immunology essay in (Burgess, 1998) and was immediately taken up by Couch et al (Couch and Gilfix, 1999) and formed the basis of the con- figuration management workshops. This concept was quickly understood to be important. 
...
Cfengine addresses convergence in two ways: by making each successful operation convergent in a single step, and by checking for contrary sequences. If a single step should fail or be undermined, for what ever reason (crash, interruption, changing conditions, loss of connectivity etc), it can be repeated later; this is sufficient to ensure that simple configurations converge.

The above is from section 8 in http://markburgess.org/papers/tiny_intro.pdf

Neil Watson

unread,
Oct 26, 2016, 11:10:25 AM10/26/16
to help-cfengine

Yann Soubeyrand

unread,
Oct 26, 2016, 2:06:06 PM10/26/16
to help-c...@googlegroups.com
Le mardi 25 octobre 2016 à 21:29 -0700, Aleksey Tsalolikhin a écrit :
> Dear Yann,
>
> Small technical point - there is no need to restart Apache after
> updating configuration. You can reload configuration instead which is
> less disruptive. See "/etc/init.d/httpd reload" and Apache graceful
> restart.
>
> Best,
> -at

Hi,

It depends on the kind of modification you do: if you enable a module
you'll then have to restart Apache (at least this is what a2enmod tells
me on Debian). But I agree that most of the time you'll just need to
reload Apache and that it is less disruptive. However, the problem
remains the same (being a restart or a reload) ;-)

Regards

Yann



Aleksey Tsalolikhin

unread,
Oct 26, 2016, 3:10:53 PM10/26/16
to Yann Soubeyrand, help-cfengine

Yep. :) Agreed. :)


Enrico Scholz

unread,
Oct 28, 2016, 7:18:12 PM10/28/16
to help-c...@googlegroups.com
You will have to create "early" and "late" variants of your bundles
(and perhaps "very-early" and "very-late" ones too) and call them in
the right order. The dependency concept in cfengine3 ("makes things
magically right") sounds intersting, but is practically undocumented
and unpredictable.

E.g. when having


---
bundle agent main
{
methods:
"" usebundle => some_bundle("foo");
"" usebundle => some_bundle("bar");
"" usebundle => other_bundle();
}

bundle agent some_bundle(file)
{
commands:
"/bin/echo '${file}' registered"
depends_on => { "global_registration" };
}

bundle agent other_bundle
{
commands:
"/bin/echo registering globally"
handle => "global_registration";
}
---

I would expect -- based on cfengine documentation -- an output

| registering globally
| 'foo' registered
| 'bar' registered

[where order of the 'foo' and 'bar' messages is not determined]


But in practice (at least with 3.9.1), you will see only the first line.


You have to think strictly procedurally and order your methods
accordingly.


Enrico

mike.w...@verticalsysadmin.com

unread,
Oct 30, 2016, 1:12:29 AM10/30/16
to help-cfengine
Enrico>> The dependency concept in cfengine3 ("makes things magically right") sounds intersting, but is practically undocumented and unpredictable. 

I have to disagree with you; I have found Normal Ordering to be quite well documented:


It *does* have some surprising ramifications for certain use cases.  For example, if you attempt to conditionally load files in "inputs" of "body file control" based on classes set in agent bundles, it won't work at all—you can only do this based on classes set in common bundles, since no further "inputs" are processed after pre-evaluation is complete, and pre-evaluation doesn't include classes promises of agent bundles.  This is a lot to wrap your head around, but it is in the documentation.  (This is also a highly finicky use case that most people would never think of doing at all.)

Also, you can only count on arbitrary promise sequence convergence within a single bundle, and only up to three iterations.  This is also documented at the link above.

What is reliable across bundles is specifically vars promises, and classes promises in common bundles, since these are handled during pre-evaluation.

I will agree with you on two points, though:

1. Your methods promises do indeed have to be ordered correctly, and
2. Putting promises in order can definitely make them easier to think about.

(Side note: methods promises are NOT function calls, and should never be thought of as such.  It leads to a false intuition that doesn't match the reality of a "bundle of promises.")

Hope that helps.  :)

Best,
--Mike Weilgart
Vertical Sysadmin, Inc.

Enrico Scholz

unread,
Oct 30, 2016, 7:42:47 AM10/30/16
to help-c...@googlegroups.com
mike.w...@verticalsysadmin.com writes:

>> The dependency concept in cfengine3 ("makes things magically right")
>> sounds intersting, but is practically undocumented and unpredictable.
>
> I have to disagree with you; I have found Normal Ordering to be quite well
> documented:
>
> https://docs.cfengine.com/lts/guide-language-concepts-normal-ordering.html#agent-evaluation-step
> [...]
> Also, you can only count on *arbitrary* promise sequence convergence
> *within* a single bundle [...]. This is also documented at the link
> above.

I do not read this in the link above.

The 'depends_on' documentation [1] does not state either, that it does
not work across bundles (but gives the opposite impression by mentioning
how to deal with other namespaces).

Nor is their any diagnostics which detects/warns about such broken uses.


> (Side note: methods promises are NOT function calls,

What are they else? Documentation [2] names them so too:

| ... In order to make the *function call* uniquely classified ...

It would be different when it would work like a macro/template instantiation
(inserting content of the bundle where it has been referenced). But the
called bundles are executed directly by 'method' promises.



Enrico

Footnotes:
[1] https://docs.cfengine.com/lts/reference-promise-types.html#depends_on

[2] https://docs.cfengine.com/lts/reference-promise-types-methods.html

nick.a...@cfengine.com

unread,
Oct 30, 2016, 9:59:02 AM10/30/16
to help-c...@googlegroups.com, Enrico Scholz
I agree, the documentation for methods type promises is in need of work. I'll put it on my backlog to work on.

Please read the policy evaluation docs here https://docs.cfengine.com/docs/master/reference-language-concepts-normal-ordering.html#policy-evaluation-overview.

If you find something confusing please ask here on the list for clarification or open a ticket so that we can improve it.
Sent from my android device.
--
You received this message because you are subscribed to the Google Groups "help-cfengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to help-cfengin...@googlegroups.com.

Yann Soubeyrand

unread,
Oct 31, 2016, 2:58:16 PM10/31/16
to help-c...@googlegroups.com
Hi,

Please excuse me for the late answer.

Aleksey, Neil, I already read all the materials you pointed me at ;-)

I think I should not have described my problem as I did: I don't want to
force CFEngine to respect some ordering by thinking procedurally. In
fact, I just want to find the best way to describe the desired state:
having all my webapps up and running. And this desired state cannot be
reached without restarting (or reloading) Apache after having deployed
the webapps (or I missed something).

The question was about how to describe my desired state in order for
CFEngine to be able to reach it, be it in a single run (which I
personally prefer when it's possible) or in several runs. And I would
like to be able to describe this desired state keeping separate bundles
for Apache and each webapp (for policy maintenance reasons).

I think Ted gave me the direction to go with the event framework ;-)

Regards

Yann

Yann Soubeyrand

unread,
Oct 31, 2016, 3:15:23 PM10/31/16
to help-c...@googlegroups.com
Le mercredi 26 octobre 2016 à 06:42 -0400, Ted Zlatanov a écrit :
> On Tue, 25 Oct 2016 20:19:43 +0200 Yann Soubeyrand <yann.so...@gmx.fr> wrote:
>
> YS> I think I understand how your lib works but I don't clearly see how to
> YS> use it in my case. Could you elaborate on where to place calls to
> YS> event_register and most importantly calls to event_handle?
>
> The facility is not opinionated, it's just a voluntary contract to tag
> classes with a type and a payload.

The facility may not be opinionated but your opinion on how you would
use it matters to me ;-)

> I'm still not sure if the created
> events should be persistent, and if they should be deleted (class
> cancel) when they are collected. Those things could be optional or
> mandated. I hope you and others have some opinions :)
>
> So focusing on the current proposal for the events library... you can
> register events anywhere. Then you can handle them whenever you want.
> Usually the end of the regular CFEngine run is all right. It's a very
> free-form system, since CFEngine itself doesn't enforce contracts.

I also think that the end of the CFEngine run is a good place to handle
events and that it can solve my problem in an elegant fashion ;-)
Unfortunately I won't have time to test it soon because I've some other
important points I need to work on, but as soon as I can, I'll try to
provide you with feedback.
You rise an important point here: with non persistent classes, an event
won't be handled if the CFEngine run crashes for whatever reason and the
configuration may not converge in some situations.

>
> Ted
>

Thanks for your help!

Regards

Yann


Yann Soubeyrand

unread,
Oct 31, 2016, 3:31:48 PM10/31/16
to help-c...@googlegroups.com
Le samedi 29 octobre 2016 à 01:18 +0200, Enrico Scholz a écrit :
> Yann Soubeyrand <yann.so...@gmx.fr> writes:
>
> > I need to write a policy to install Apache and some webapps using virtual
> > hosts. I'd like to organise my policy having a bundle for Apache and a
> > bundle per webapps. The problem is that I need the apache package to be
> > installed before I deploy the webapps in order to give to the apache user
> > ownership on some files of the webapps, but I also need the apache service
> > being started after having deployed all the webapps in order to take into
> > account their virtual hosts.
> >
> > What is the design pattern, if there is some, in this case and similar ones
> > (which seem to be quite common)?
>
> You will have to create "early" and "late" variants of your bundles
> (and perhaps "very-early" and "very-late" ones too) and call them in
> the right order.

That's what I have for the moment but I'm not satisfied with it and I'll
try the event framework Ted created.
I agree this behavior is really disappointing at first but it finally
seems logical to me if you consider that a method promise is... A
promise! During the first pass, the command promise in some_bundle is
not evaluated as it dependency is not satisfied but it doesn't fail. So
the method promise is considered kept and won't be evaluated again
during the second pass, hence the surprising behavior ;-) Maybe what I
said isn't correct technically speaking but at least it helps me
explaining this behavior :-D

> You have to think strictly procedurally and order your methods
> accordingly.

Sometime you can also put the dependency on the method promises
themselves but I agree that putting methods promises in order is simpler
and easier to understand (that's also true for the other kinds of
promises).

>
> Enrico
>

Regards

Yann

Ted Zlatanov

unread,
Oct 31, 2016, 11:11:06 PM10/31/16
to help-c...@googlegroups.com
On Mon, 31 Oct 2016 20:16:42 +0100 Yann Soubeyrand <yann.so...@gmx.fr> wrote:

YS> And would you then call event_register("apache",
YS> "restart", "what do you put here?", metadata) in the webapps deployment
YS> bundles each time you modify the apache configuration and then call
YS> event_handle("apache", "restart") outside the bundles to call the apache
YS> bundle which will then restart apache? Or am I totally missing the
YS> point?

Yes, you've got a 2-level dependency there. Some people prefer to issue
a "restart" and an "install" event together, and others use one class
like "apache_repaired" for both. You have to consider the user: who will
be reading and maintaining this? If it's experts, then 2-level is
probably OK. But for beginners, it may be too complex.

YS> You rise an important point here: with non persistent classes, an event
YS> won't be handled if the CFEngine run crashes for whatever reason and the
YS> configuration may not converge in some situations.

OK, I can make these events persistent and cancel them when they are
collected. Metadata is saved when classes are persistent. I'll update
the PR when I get this done.

Ted

Ted Zlatanov

unread,
Nov 1, 2016, 9:06:32 AM11/1/16
to help-c...@googlegroups.com
On Mon, 31 Oct 2016 23:10:42 -0400 Ted Zlatanov <t...@lifelogs.com> wrote:

TZ> OK, I can make these events persistent and cancel them when they are
TZ> collected. Metadata is saved when classes are persistent. I'll update
TZ> the PR when I get this done.

My testing looked good, so I pushed the update to
https://github.com/cfengine/masterfiles/pull/816

Ted

Nick Anderson

unread,
Apr 12, 2017, 1:43:36 PM4/12/17
to help-cfengine
Merged for 3.11
Reply all
Reply to author
Forward
0 new messages