Reputation: 9
I'm writing a Puppet module to enforce a configuration and restart the service if needed. I'd like to do something like that:
class app_cfg {
$app_files = ['file1', 'file2', 'file3']
$app_files.each |String $file| {
exec {"sed -i 's/bar/foo/g' $file":
path => ['/bin'],
onlyif => 'grep "bar" $file 2>/dev/null',
cwd => '/opt/app/config/',
}
} ~>
service { 'app':
ensure => running,
enable => true,
}
}
I could add "notify" inside the exec but I don't want to restart my service for each file, and it looks like the notify chaining arrow doesn't work after an each loop. Do you guys have any idea how to make it work?
Thanks a lot :)
I found a workaround by inserting a for loop inside the exec resource instead of using each:
class app_cfg {
service { 'app':
ensure => running,
enable => true,
}
exec {"for file in file1 file2 file3; do sed -i 's/bar/foo/g' \$file; done":
path => ['/bin'],
onlyif => 'grep "bar" $file 2>/dev/null',
cwd => '/opt/app/config/',
provider => shell,
notify => Service['app']
}
}
I'm still pretty curious about the first solution! Did you ever manage to do something like that?
Thanks!
Upvotes: 0
Views: 1227
Reputation: 180201
I could add "notify" inside the exec but I don't want to restart my service for each file, and it looks like the notify chaining arrow doesn't work after an each loop.
It is important to understand that the code in a Puppet manifest describes only how to build a catalog that in turn describes the desired configuration of your server. The catalog lists the classes and resources declared, their parameters and properties, and the relationships among them. The logic within a manifest does not map to actions performed when applying the resulting catalog; it is reflected only in which classes and resources are catalogued, and what their parameters, properties, and relationships are.
Thus, when you use one of the chaining arrows in a manifest, you are instructing the catalog builder to record a relationship between the two resources in the catalog, not an explicit instruction to apply or refresh a resource. No declared resource will be applied at more than once or refreshed more times than it is applied. It will be perfectly fine, therefore, to put an appropriate chain expression inside your loop, but what you cannot do is put the Service
declaration itself inside the loop, because that would produce multiple declarations of it. So you might do any of these:
Declare the service (once), and use a resource reference to it in your chain expression inside the loop:
class app_cfg {
service { 'app':
ensure => running,
enable => true,
}
['file1', 'file2', 'file3'].each |String $file| {
exec {"sed -i 's/bar/foo/g' $file":
path => ['/bin'],
onlyif => 'grep "bar" $file 2>/dev/null',
cwd => '/opt/app/config/',
} ~> Service['App']
}
}
As above, but use the appropriate resource metaparameter instead of a chain expression:
class app_cfg {
service { 'app':
ensure => running,
enable => true,
}
['file1', 'file2', 'file3'].each |String $file| {
exec {"sed -i 's/bar/foo/g' $file":
path => ['/bin'],
onlyif => 'grep "bar" $file 2>/dev/null',
cwd => '/opt/app/config/',
notify => Service['app'],
}
}
}
Or declare the relationships with the help of a collector:
class app_cfg {
['file1', 'file2', 'file3'].each |String $file| {
exec {"sed -i 's/bar/foo/g' $file":
path => ['/bin'],
onlyif => 'grep "bar" $file 2>/dev/null',
cwd => '/opt/app/config/',
tag => 'app_notifier',
}
}
Exec<|tag == 'app_notifier|>
~> service { 'app':
ensure => running,
enable => true,
}
}
Upvotes: 2