Why is 'notify' acting as a 'before' and not a 'require' ?

1,232 views
Skip to first unread message

Alexandre Fouché

unread,
Jan 24, 2012, 4:09:59 AM1/24/12
to puppet...@googlegroups.com
Why is 'notify' acting as a 'before' and not a 'require' ?

Can someone explain why this way is unlogical to Puppet parser, why the 'notify' would create a dependency cycle ? Why would the 'notify' need to create an order ? Isn't it supposed to carry a message, and not a constraint ?

Typically i would need something like this
   
    # First i have an Apache class
    class apache {
        #(...)
        exec { 'apache-reload':
            command     => '/sbin/service httpd reload',
            refreshonly => true,
            require     => Service['apache'],
        }   
    }
   
    # Then another class which adds an Apache conf file
    class backup::backuppc::web {
        #(...)
       
        require 'apache'
       
        file { '/etc/httpd/conf.d/BackupPC.conf':
            #(...)
            require => [ Class['apache'] ],
            notify  => Exec['apache-reload'],
        }
    }

I find it logical that my 'BackupPC.conf' apache file is put after the apache package is installed, or more broadly after the apache class is complete. Afterwards, i put the 'BackupPC.conf' conf, and then afterwards, i want to notify Exec['apache-reload'], that it needs to reload. To me, the notify is a good way to ensure the apache class does not have to know anything about the backup class, and stay generic, while at the same time ensuring that the backup class can notify the apache service if it thinks it needs to.

Unfortunately, the 'notify' is acting as a 'before' and creates a dependency cycle. It breaks the scheme of being able to keep the apache class generic yet able to respond to notifications

Felix Frank

unread,
Jan 24, 2012, 4:20:11 AM1/24/12
to puppet...@googlegroups.com
Hi,

On 01/24/2012 10:09 AM, Alexandre Fouch� wrote:
> I find it logical that my 'BackupPC.conf' apache file is put after the
> apache package is installed, or more broadly after the apache class is
> complete. Afterwards, i put the 'BackupPC.conf' conf, and then
> afterwards, i want to notify Exec['apache-reload'], that it needs to
> reload. To me, the notify is a good way to ensure the apache class does
> not have to know anything about the backup class, and stay generic,
> while at the same time ensuring that the backup class can notify the
> apache service if it thinks it needs to.

Your outset looks a bit contradictory to me. Yes, requiring
Class["apache"] is sound design. But notifying a resource decalred
*within* that class is the complete opposite of that.

A better solution will take care of your problem as well.

> Unfortunately, the 'notify' is acting as a 'before' and creates a
> dependency cycle. It breaks the scheme of being able to keep the apache
> class generic yet able to respond to notifications

Think about it. You want puppet to send a notification to a resource.
Puppet must decide whether this notification gets sent. So it must
process the notifying resource. After that, *if* a notification was in
fact generated, it can process the notified resource. The opposite order
cannot be achieved. Therefore, notifies and subscriptions imply
before/requires relationships.

I suggest you add a class
apache::service {
...
}
with whatever implementation you choose for your reload (in most cases
you want to notify a service resource instead of an exec, but it's not
more than a rule of thumb).

The you can go ahead and require Class[apache] but notify
Class[apache::service]. For good measure, class apache will likely
include apache::service.

Hope this makes sense to you.

Cheers,
Felix

Alexandre

unread,
Jan 24, 2012, 4:51:52 AM1/24/12
to Puppet Users
> Think about it. You want puppet to send a notification to a resource.
> Puppet must decide whether this notification gets sent. So it must
> process the notifying resource. After that, *if* a notification was in
> fact generated, it can process the notified resource.

I see. I was making a difference between parsing the notified
ressource and applying this resource. That is why i -though- the
notify would require the parsing, but Puppet would then apply/refresh
the notified resource afterwards. But it seems that for Puppet,
parsing and applying the notified ressource is one operation, which
means, if i understand correctly, that it is not possible to require
and notify the same resource as i was expecting erroneously.

>
> with whatever implementation you choose for your reload (in most cases
> you want to notify a service resource instead of an exec, but it's not
> more than a rule of thumb).

Yes, my class apache includes a Service, and the Exec requires it. But
since notifying the service will trigger an restart and not a reload,
i do not notify the Service directly ( I see there are open issues
#3323 and #1014 )

Felix Frank

unread,
Jan 24, 2012, 5:05:22 AM1/24/12
to puppet...@googlegroups.com
On 01/24/2012 10:51 AM, Alexandre wrote:
> But it seems that for Puppet,
> parsing and applying the notified ressource is one operation, which
> means, if i understand correctly, that it is not possible to require
> and notify the same resource as i was expecting erroneously.

It's not. Both notify and require operate *only* on the order in which
the *agent* will apply resources.

Parsing happens on the master. There is no reason you would change its
order.

I sense we're still talking in circles so to make it yet more clear:
The decision wether an applied resource needs changing (I believe you
refer to this decision as "parsing") is indeed made at the time of
resource application and there is no way to separate these steps.

HTH,
Felix

jcbollinger

unread,
Jan 26, 2012, 9:48:19 AM1/26/12
to Puppet Users


On Jan 24, 3:51 am, Alexandre <alexandre.fou...@gmail.com> wrote:
> > Think about it. You want puppet to send a notification to a resource.
> > Puppet must decide whether this notification gets sent. So it must
> > process the notifying resource. After that, *if* a notification was in
> > fact generated, it can process the notified resource.
>
> I see. I was making a difference between parsing the notified
> ressource and applying this resource. That is why i -though- the
> notify would require the parsing, but Puppet would then apply/refresh
> the notified resource afterwards. But it seems that for Puppet,
> parsing and applying the notified ressource is one operation, which
> means, if i understand correctly, that it is not possible to require
> and notify the same resource as i was expecting erroneously.


No, that is incorrect. Parsing and applying are always distinct
operations to Puppet. In general, they don't even happen on the same
machine.

Testing for dependency cycles is part of parsing manifests and
compiling them into a catalog. This does not conflict with Felix's
explanation of why 'subscribe' and 'notify' [must] establish resource
relationships.

Perhaps you meant you thought the 'require' was needed for correct
parsing? That is incorrect, precisely *because* Puppet separates
parsing / compiling from applying, but we need to be careful because
you use two semantically different 'require's in your manifest:

1) The 'require' function --
require 'apache'

2) The 'require' metaparameter --
require => [ Class['apache'] ]

You must first understand that the latter is redundant with the
former, because the former causes the entire class in which it appears
to have a requirement on the named class. This is an order-of-
application consideration, not a parsing consideration, and it seems
to be the key problem in your manifest.

The 'require' function (but not the metaparameter) ADDITIONALLY has
the same effect as the 'include' function, and part of *that* effect
is indeed necessary to ensure that your manifest always parses
cleanly. Perhaps this is the source of your confusion.

It looks like what you want might be


modules/apache/manifests/init.pp:
====
class apache {
#(...)
exec { 'apache-reload':
command => '/sbin/service httpd reload',
refreshonly => true,
require => Service['apache'],
}
}


modules/backup/manifests/backuppc/web.pp:
====
class backup::backuppc::web {
#(...)

include 'apache' # NOTE

file { '/etc/httpd/conf.d/BackupPC.conf':
#(...)
# NO REQUIRE
notify => Exec['apache-reload'],
}
}


John
Reply all
Reply to author
Forward
0 new messages