How to make service start depend on a file existing

1,104 views
Skip to first unread message

Mark Kirkwood

unread,
Jul 7, 2015, 9:21:48 PM7/7/15
to puppet...@googlegroups.com
I would like to prevent a service starting until a certain file exists.
The wrinkle is that the file is not (directly) created by puppet.

I'm thinking that I want to somehow 'declare' the file to puppet without
*it* trying to create it, and the use something like:

File["the-file"] -> Service["the-service"]

to make sure the service get started after the file is created. However
I'm stumped at the first bit (the file 'declare' idea). Any thoughts?

Regards

Mark

jcbollinger

unread,
Jul 8, 2015, 9:25:37 AM7/8/15
to puppet...@googlegroups.com
Puppet doesn't work that way.  You cannot use a reference to an unmanaged resource (i.e. File["the-file"]).  It does not anyway make sense to establish a relationship to such a resource; at best it would be meaningless.  A resource relationship describes an order-of-application dependency.  What's Puppet supposed to do with that if one of the resources involved is not scheduled to be applied at all?

There may be hope, however.  You emphasize that the file is not directly created by Puppet, but that implies that it is indirectly created by Puppet, as a side effect of managing some other resource.  If you can rely on that other resource to fail in the event that it does not create or appropriately modify the file in question, then make that the other end of the relationship, maybe

package { 'the-service-package': }
->
service
{ 'the-service': }

Otherwise, interpose an Exec between the two that tests for the existence (or any other property) of the file:

package { 'the-service-package': ensure => 'latest' }
->
exec { 'ensure the-file is present': command => 'test -e the-file' }
->
service
{ 'the-service': ensure => 'running' }


John

Gerard Kok

unread,
Jul 8, 2015, 10:26:11 AM7/8/15
to puppet...@googlegroups.com, mark.k...@catalyst.net.nz
You could create a custom fact that returns the desired state of the service, based on the existence of the file, and then use the value of that fact in the service declaration. For example, like so:

The custom fact:

Facter.add(:state_of_the_service) do
 setcode
do
 
File.exists?(the-file) ? "running" : "stopped"
 
end
end

and the service declaration:

service { 'the-service':
 
ensure => $::state_of_the_service
}


The downside of this solution is that you'll require two puppet runs to get the service running if the file is (indirectly) created by puppet. The first run the file will be created, but the fact is computed at the start of the run, so it will still be 'stopped', and only switch to 'running' at the start of the second run.

Mark Kirkwood

unread,
Jul 9, 2015, 8:49:22 PM7/9/15
to puppet...@googlegroups.com
On 09/07/15 01:25, jcbollinger wrote:
>
>
> On Tuesday, July 7, 2015 at 8:21:48 PM UTC-5, Mark Kirkwood wrote:
>
> I would like to prevent a service starting until a certain file exists.
> The wrinkle is that the file is not (directly) created by puppet.
>
> I'm thinking that I want to somehow 'declare' the file to puppet
> without
> *it* trying to create it, and the use something like:
>
> File["the-file"] -> Service["the-service"]
>
> to make sure the service get started after the file is created. However
> I'm stumped at the first bit (the file 'declare' idea). Any thoughts?
>
>
>
> Puppet doesn't work that way. You cannot use a reference to an
> unmanaged resource (i.e. File["the-file"]). It does not anyway make
> sense to establish a relationship to such a resource; at best it would
> be meaningless. A resource relationship describes an
> order-of-application dependency. What's Puppet supposed to do with that
> if one of the resources involved is not scheduled to be applied at all?
>
> There may be hope, however. You emphasize that the file is not
> /directly/ created by Puppet, but that implies that it is indirectly
> created by Puppet, as a side effect of managing some other resource. If
> you can rely on that other resource to fail in the event that it does
> not create or appropriately modify the file in question, then make that
> the other end of the relationship, maybe
>
> |
> package{'the-service-package':}
> ->
> service {'the-service':}
> |
>
> Otherwise, interpose an Exec between the two that tests for the
> existence (or any other property) of the file:
>
> |
> package{'the-service-package':ensure=>'latest'}
> ->
> exec{'ensure the-file is present':command =>'test -e the-file'}
> ->
> service {'the-service':ensure=>'running'}
> |
>
>

Thanks John,

That worked perfectly! However - and, sorry - I failed to mention that
one of the reasons for doing this was to get rid to errors from puppet
runs, so that scripted builds for testing etc behave well. This solution
seems to still elicit errors when the exec fails to find the file... so
progress but not quite there!

Cheers

Mark

Mark Kirkwood

unread,
Jul 9, 2015, 8:54:46 PM7/9/15
to puppet...@googlegroups.com
On 09/07/15 02:26, Gerard Kok wrote:
> You could create a custom fact that returns the desired state of the
> service, based on the existence of the file, and then use the value of
> that fact in the service declaration. For example, like so:
>
> The custom fact:
>
> |
> Facter.add(:state_of_the_service)do
> setcode do
> File.exists?(the-file)?"running":"stopped"
> end
> end
> |
>
> and the service declaration:
>
> |
> service {'the-service':
> ensure=>$::state_of_the_service
> }
> |
>
>
> The downside of this solution is that you'll require two puppet runs to
> get the service running if the file is (indirectly) created by puppet.
> The first run the file will be created, but the fact is computed at the
> start of the run, so it will still be 'stopped', and only switch to
> 'running' at the start of the second run.
>

Actually that is not a problem (the setup concerned - puppet-swift -
already requires a number of runs).

I've used this approach, and it seems to work fine - awesome!

The only consideration is that this logic is actually in an external
module (puppet-swift) todo with classes that are called by the module
internally...so I'm patching the module :-( I've started a discussion
about this on the openstack-dev list to see if they like this approach
or not.

Thanks for your help

Mark

jcbollinger

unread,
Jul 10, 2015, 9:10:40 AM7/10/15
to puppet...@googlegroups.com


On Thursday, July 9, 2015 at 7:49:22 PM UTC-5, Mark Kirkwood wrote:
[...]


That worked perfectly! However - and, sorry - I failed to mention that
one of the reasons for doing this was to get rid to errors from puppet
runs, so that scripted builds for testing etc behave well. This solution
seems to still elicit errors when the exec fails to find the file... so
progress but not quite there!


If the Exec does not find the file, then whatever resource you were relying on to create it (and that you therefore marked the Exec to depend upon) must in fact not have created the file.  What is Puppet then supposed to do?  You have specified that the Service should be managed, but Puppet cannot manage it because the file does not exist.  As far as I can tell, this is a bona fide error that should be reported.

If neither of the setups I suggested adequately meets your needs then I think you need to take a higher-level view for a moment.  Ignore the details, and consider what the actual moving parts are, and what their functional requirements and relationships are.  What are you trying to achieve here?  Perhaps focusing on the file in question is is not the best way to approach your objective, or perhaps that file really should be Puppet-managed.  Perhaps you have misstated your requirement: you cast it as a question of timing -- when the service is started -- but if it is also a question of what Puppet is supposed to manage -- i.e. whether the service is started at all -- then that's a rather different thing.


John

Reply all
Reply to author
Forward
0 new messages