Puppet: how to add a line to an existing file - puppet

I am trying to add a line to an existing file /etc/fuse.conf. I tried this
added a folder two folders under modules directory
sudo mkdir /etc/puppet/modules/test
sudo mkdir /etc/puppet/modules/test/manifests
Then created a test.pp file and added following lines
sudo vim /etc/puppet/modules/test/manifests/test.pp
file { '/etc/fuse.conf':
ensure => present,
}->
file_line { 'Append a line to /etc/fuse.conf':
path => '/etc/fuse.conf',
line => 'Want to add this line as a test',
}
After that I ran this command
puppet apply /etc/puppet/modules/test/manifests/test.pp
Then I opened this file /etc/fuse.conf and there was no change in the file. The line was not added to the file. I don't understand what I am missing here. How can I do this?

Interesting. I ran the same test you did without an issue, and as long as you have stdlib installed in your environment you should be fine.
https://forge.puppet.com/puppetlabs/stdlib
The results of running the same steps you outlined were successful for me:
[root#foreman-staging tmp]# puppet apply /etc/puppet/modules/test/manifests/test.pp
Notice: Compiled catalog for foreman-staging.kapsch.local in environment production in 0.18 seconds
Notice: /Stage[main]/Main/File[/etc/fuse.conf]/ensure: created
Notice: /Stage[main]/Main/File_line[Append a line to /etc/fuse.conf]/ensure: created
Notice: Finished catalog run in 0.24 seconds
What did your puppet run output?

You should use templates (ERB) to handle file configuration. Its easier and cleaner.
Check the puppet docs for it in :
https://docs.puppetlabs.com/puppet/latest/reference/lang_template.html
There are other options though. e.g. Augeas which is an API for file configuration and integrate very well with Puppet. http://augeas.net/index.html
[]'s

There are a few ways to handle this. If it's ini file you can use ini_setting. If it's supported by augeas you can use that. Otherwise try specifying the after parameter to file_line

Related

Puppet creates a broken symlink

For example I have a symlink /etc/foo/folder11/some/link.txt which points to etc/foo/folder12/some/file.txt.
And in puppet I have the following
ensure_resource('file', "/etc/bar/link.txt", {
owner => $someUser,
mode => '0444',
source => `/etc/foo/folder11/some/link.txt`,
})
After puppet run it creates a broken symlink /etc/bar/link.txt which points to ../../folder12/some/file.txt.
Why does it create so strange symlink? And how can I force puppet to create /etc/foo/link.txt symlink which should point to the same file to which /etc/foo/folder11/some/link.txt points to ?
Note that I don't use ensure => link because sometimes /etc/foo/folder11/some/link.txt may be a regular file and in this case /etc/bar/link.txt should be a copy of this file.
As it turned out the problem was in /etc/foo/folder11/some/link.txt which was a relative symlink. I changed it to be absolute and now it works fine.

Inserting a string into a file with Puppet with iteration

I'm running a .each iteration with Puppet:
$extensions_list = ["RT::Extension::ActivityReports",
"RT::Extension::JSGantt",
]
$extensions_list.each |$extls| {
cpan { $extls:
ensure => present,
require => Class['::cpan'],
}
}
As you can see I'm just installing two Perl modules with a cpan module from Puppet Forge. This part works just as expected.
What I would like to happen is each time a new Perl module is installed in this way it will be added to added to the config line of RT (Request Tracker). That file lives here:
/opt/rt4/etc/RT_SiteConfig.pm
and the format of the line is:
Plugins('RT::MODULE::ONE RT::MODULE::TWO');
So, in the end I would like it to look like this:
Plugins('RT::Extension::ActivityReports RT::Extension::JSGantt');
Having Puppet add each new module in turn to that line as they are installed. As in if I decided to install RT::Authen::ExternalAuth a month from now I can just add it to my above iteration and after Puppet runs this:
Plugins('RT::Extension::ActivityReports RT::Extension::JSGantt');
would become this:
Plugins('RT::Extension::ActivityReports RT::Extension::JSGantt RT::Authen::ExternalAuth');
With no other intervention on my part then to add it to the iteration statement.
Assuming that you don't have any other Puppet code managing /opt/rt4/etc/RT_SiteConfig.pm, then you have a few options for making sure that you have the correct Plugins line in that file.
If you only want to manage just that one line then I would recommend using join and a file_line resource from stdlib.
For example:
include stdlib
$ext_string = join($extensions_list, ' ')
file_line { 'rt extensions':
ensure => present,
path => '/opt/rt4/etc/RT_SiteConfig.pm',
line => "Plugins('${ext_string}');",
match => '^\s*Plugins\(',
}
This will add a line containing the list of plugins and will replace any existing plugin line.
If there are several settings that you want to manage then it might make sense to just templatize the entire file. In that case you could simply have the line
Plugins('<%= #extensions_list.join(' ') %>');
in your template.

How to create a JSCS config file on windows

When I try to create a JSCS config file:
C:\Blog\BlogWeb>jscs --auto-configure "C:\Blog\BlogWeb\temp.jscs"
I get the following error:
safeContextKeyword option requires string or array value
What parameter am I supposed to pass? What is a safecontextkeyword?
New to NPM and JSCS, please excuse ignorance.
JSCS was complaining that I didn't have a config file, so I was trying to figure out how to create one.
JSCS looks for a config file in these places, unless you manually specify it with the --config option:
jscs it will consequentially search for jscsConfig option in package.json file then for .jscsrc (which is a just JSON with comments) and .jscs.json files in the current working directory then in nearest ancestor until it hits the system root.
I fixed this by:
Create a new file named .jscsrc. Windows Explorer may not let you do this, so may need to use the command line.
Copy the following into it. It doesn't matter if this is the preset you want to use or not. The command will overwrite it.
{
"preset": "jquery",
"requireCurlyBraces": null // or false
}
Verify that it works by running a command such as:
run the command
jscs --auto-configure .jscsrc

How can I refer to the current puppet module's files directory?

This is most likely an anti-pattern, but I'd like to know nonetheless:
I need to extract a tgz which is in puppet and then move the contents somewhere else. Is it possible, in a puppet exec { }, to refer to the file where it is stored on disk?
For example, puppet is available at /usr/local/puppet, and the tgz file I need it in /usr/local/puppet/modules/components/files/file.tgz. In the exec { } can I do something like command => "/bin/cp $modules/components/files/file.tgz /somewhere_else" ? Or do I have to declare a file { source => "..." } block first?
Both approaches are correct if you run puppet with puppet apply.
In master-agent architecture using exec to copy file probably will not work at all.
In my opinion using file resource is more "puppet-like" but is has one significant drawback.
You can use:
file { '/some_path/somewhere_else':
source => '/usr/local/puppet/modules/components/files/file.tgz',
}
This will create file /some_path/somewhere_else with the same content as /usr/local/puppet/modules/components/files/file.tgz (it will make a copy of the original file).
But if /some_path doesn't not exist in the file system, the command will fail.
If you are working with tgz files you can also consider using some of the archive puppet modules e.g gini.
UPDATE:
I can propose two approaches:
Use puppet file server to serve files (or define module path for old puppet versions). Next just use it e.g:
file { '/some_path/somewhere_else':
source => "puppet:///modules/components/file.tgz',
}
Define custom facter fact 1, 2 that points path in your filesystem containing required files. E.g:
file { '/some_path/somewhere_else':
source => "${::my_custom_fact}/some_path/file.tgz',
}
I do not think that any of the core facts might be useful for you.

Sourcing Puppet files from outside of modules

I'm installing a package from a module (Nginx in this specific case) and would like to include a configuration file from outside of the module, i.e. from a top level files directory parallel to the top level manifests directory. I don't see any way to source the file though without including it in a module or in my current Vagrant environment referring to the absolute local path.
Does Puppet allow for sourcing files from outside of modules as described in the documentation?
if I understand your question correctly, you can.
In your module a simple code like this
file { '/path/to/file':
ensure => present,
source => [
"puppet:///files/${fqdn}/path/to/file",
"puppet:///files/${hostgroup}/path/to/file",
"puppet:///files/${domain}/path/to/file",
"puppet:///files/global/path/to/file",
],
}
will do the job. The /path/to/file will be sourced using a file located in the "files" Puppet share.
(in the example above, it search in 4 different locations).
update maybe you're talking about a directory to store files which is not shared by Puppet fileserver (look at http://docs.puppetlabs.com/guides/file_serving.html), and in this case you can't i think, Vagrant or not, but you can add it to your Puppet fileserver to do it. I thinks it's the best (and maybe only) way to do it.
If you have a number of Vagrant VMs you can simply store files within your Vagrant project directory (containing your VagrantFile).
This directory is usually available to all VMs as /vagrant within the VM on creation.
If you want other directories on your computer to be available to your VMs just add the following to your VagrantFile
# see http://docs.vagrantup.com/v1/docs/config/vm/share_folder.html
config.vm.share_folder "v-packages", "/vagrant_packages", "../../dpkg"
Then to use the files within puppet you can simply treat them as local files to the VM
# bad example, bub basically use 'source => 'file:///vagrant/foo/bar'
file { '/opt/cassandra':
ensure => directory,
replace => true,
purge => true,
recurse => true,
source => 'file:///vagrant/conf/dist/apache-cassandra-1.2.0',
}
This is probably only wise to do if you only using local puppet manifests/modules.
Probably too late to help bennylope, but for others who happen across this question, as I did before figuring it out for myself ...
Include stuff like this in your Vagrantfile ...
GUEST_PROVISIONER_CONFDIR = "/example/destination/path"
HOST_PROVISIONER_CONFDIR = "/example/source/path"
config.vm.synced_folder HOST_PROVISIONER_CONFIDIR, GUEST_PROVISIONER_CONFDIR
puppet.options = "--fileserverconfig='#{GUEST_PROVISIONER_CONFDIR}/fileserver.conf'"
Then make sure /example/source/path contains the referenced fileserver.conf file. It should look something like ...
[foo]
path /example/destination/path
allow *
Now, assuming example-file.txt exists in /example/source/path, the following will work in your manifests:
source => "puppet:///foo/example-file.txt",
See:
Puppet configuration reference entry for fileserverconfig
Serving Files From Custom Mount Points

Resources