How to install and run a script in Puppet - puppet

I am new to Puppet..I am trying to install a shell script and exceute it using Puppet. The shell script after running creates another conf file and places in a specific location /usr/local/conf/app.conf. How can I write a puppet code to execute this script and then take the output file and scp it to another server (in my case its the webserver). Can someone please help.

Let's assume you have developed a module named webconfig and your puppet config dir is /etc/puppet.
You would need to store your shell script as /etc/puppet/modules/webconfig/files/script.sh
Your puppet code would partially look like this:
file { '/path/to/script.sh':
ensure => present,
source => 'puppet:///modules/webconfig/script.sh',
mode => '0644',
owner => 'root',
group => 'root',
}
->
exec { 'Generate the config':
command => '/path/to/script.sh',
cwd => '/path/to',
user => 'root',
}
->
exec { 'SCP the config':
command => 'scp /usr/local/conf/app.conf user#remote-server:',
cwd => '/path/to',
user => 'root',
}

Related

Puppet: how many times an exec block with creates run?

I have the below two exec resources and would like the exec resource run the script to run whenever the file /var/lib/my-file is not present. I'm wondering what would happen if the file never gets created. Would the exec resource check if file exists run forever in a loop until it gets created?
exec { 'run the script':
command => "python my-script.py",
path => '/bin:/usr/bin:/usr/local/bin',
timeout => 900,
subscribe => File["my-settings.yaml"],
refreshonly => true,
}
exec { 'check if file exists':
command => 'true',
path => '/bin:/usr/bin:/usr/local/bin',
creates => '/var/lib/my-file',
notify => Exec['run the script']
}
A resource is only applied once per catalog application, which occurs once per catalog compilation per node. You can verify this for yourself by trying it out.
If the Python script fails to create the file, the resource would simply be applied again during the next catalog application. Otherwise, idempotence prevails and the resource is not applied because the file already exists.
Additionally, you should simplify your resources into:
exec { 'run the script':
command => 'python my-script.py',
path => '/bin:/usr/bin:/usr/local/bin',
timeout => 900,
creates => '/var/lib/my-file',
subscribe => File["my-settings.yaml"],
refreshonly => true,
}
This is functionally the same as what you have in your question and is more efficient and easier to read.

Puppet execute command only if file does not exist

I am trying to use the following code which should perform some action only if a certain file does not exist. If the file exists, it should skip that task. I cannot get it to work.
exec {"is_file_there":
command => "true",
path => ["/usr/bin","/usr/sbin","/bin"],
unless => "test -e /tmp/some_file",
}
somecommand {
..
..
require => Exec['is_file_there'],
}
As an example, I tried using file but even that did not work. This is just an example for purpose of demonstrating the issue.
exec {"is_file_there":
command => "true",
path => ["/usr/bin","/usr/sbin","/bin"],
unless => "test -e /tmp/some_file",
}
file {'/tmp/success'
ensure => present,
require => Exec['is_file_there'],
}
EDIT : I am trying to create a dependency between another resource and exec. The other resource does not allow onlyif. The example about file is just that an example
According to https://puppet.com/docs/puppet/7/types/exec.html#exec-attribute-creates the "creates" option in "exec" will only run "command" if the file doesn't exist:
exec {"is_file_there":
command => "some_action_command",
path => ["/usr/bin","/usr/sbin","/bin"],
creates => "/tmp/some_file",
}
You could try something like this:
exec {"Some title":
command => "Your command",
path => ["/usr/bin","/usr/sbin","/bin"],
unless => "test -e /tmp/some_file",
}
So, your command is going to execute unless the result of test -e /tmp/some_file is success (exit code 0), that is, the file exists.

File paths must be fully qualified error in puppet

I was trying to create a new file in my module, but every time I am getting an error for my file resource, saying:
File paths must be fully qualified, not '/the/path/that/I/have/given'.
What are the possible reasons for that error?
class fresh_start {
file { 'source_file.rb':
ensure => 'file',
source => 'puppet:///modules/fresh_start/source_file.rb',
path => '/etc/puppetlabs/code/environments/production/modules/fresh_start/destination_file.rb',
owner => 'root',
group => 'root',
mode => '0755', # Use 0700 if it is sensitive
notify => Exec['run_my_ruby']
}
exec { 'run_my_ruby':
command => 'ruby etc/puppetlabs/code/environments/production/modules/fresh_start/source_file.rb > /etc/puppetlabs/code/environments/production/modules/fresh_start/output.txt',
refreshonly => true,
}
}
I have also tried to put the file path in a variable and use that variable as the path attribute's value, but I got the same error.
This happens when you attempt to run code with Unix paths on Windows. Check out the Puppet source code here and here.
Using a debugger, we can see that Unix-style paths are rejected on a Windows platform:
[1] pry(main)> slash = '[\\\\/]'
=> "[\\\\/]"
[2] pry(main)> label = '[^\\\\/]+'
=> "[^\\\\/]+"
[3] pry(main)> AbsolutePathWindows = %r!^(?:(?:[A-Z]:#{slash})|(?:#{slash}#{slash}#{label}#{slash}#{label})|(?:#{slash}#{slash}\?#{slash}#{label}))!io
=> /^(?:(?:[A-Z]:[\\\/])|(?:[\\\/][\\\/][^\\\/]+[\\\/][^\\\/]+)|(?:[\\\/][\\\/]\?[\\\/][^\\\/]+))/i
[4] pry(main)> path = '/foo/bar'
=> "/foo/bar"
[5] pry(main)> path =~ AbsolutePathWindows
=> nil

Run custom services on startup with puppet

I'm migrating our old process of doing our linux configurations to be managed by puppet but I'm having issues trying to figure out how to do this. We add some custom scripts to the init.d folder on our systems to manage some processes, and then these need this command executed on them to launch on startup:
update-rc.d $file defaults
So what I'm doing with puppet is that I have all these scripts residing a directory, and I copy them over to init.d. I then want to call 'exec' on each of these files with the former command and use the file name as an argument. This is what I have so far:
#copy init files
file { '/etc/init.d/':
ensure => 'directory',
recurse => 'remote',
source => ["puppet:///files/init_files/"],
mode => 755,
notify => Exec[echo],
}
exec { "echo":
command => "update-rc.d $file defaults",
cwd => "/tmp", #directory to execute from
path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:",
refreshonly => true
}
This will copy all the files and it calls exec when something is added/updated, but what I can't figure out is how to pass the name of the file as an argument into the exec command. It seems I'm really close but I just can't find anything to help with what I need to do. Is this the right way to try and achieve this?
Thanks.
Your probably not going to accomplish that if your using ensure => 'directory'. You will want to declare the file resource for each individual init script. And the exec isn't the way to go to enable a service. Use the service resource.
file { '/etc/init.d':
ensure => 'directory',
mode => '0755'
}
file { '/etc/init.d/init_script_1':
ensure => 'present',
owner => 'root',
group => 'root',
mode => '0755',
notify => Service['init_script_1']
}
file { '/etc/init.d/init_script_2':
ensure => 'present',
owner => 'root',
group => 'root',
mode => '0755',
notify => Service['init_script_2']
}
service { 'init_script_1':
ensure => running,
enable => true
}
service { 'init_script_2':
ensure => running,
enable => true
}
Hope this helps.

Puppet: Found 1 dependency cycle

I am getting this error when applying my Puppet manifest:
Error: Could not apply complete catalog: Found 1 dependency cycle:
(Exec[pip install requirements] => File[change venv permissions] => File[enforce MinGW compiler] => Exec[pip install requirements])
Try the '--graph' option and opening the resulting '.dot' file in OmniGraffle or GraphViz
Here is my Puppet manifest (the relevant part) and I don't see any dependency cycle there. Any ideas?
exec {'create virtualenv':
command => "$install_dir/Scripts/virtualenv.exe venv",
cwd => $project_dir,
require => Exec['install virtualenv'],
}
file { "fix Mingw32CCompiler":
path => "C:/Python27/Lib/distutils/cygwinccompiler.py",
content => template($cygwinc_template),
ensure => present,
require => Exec['create virtualenv'],
}
file { "enforce MinGW compiler":
path => "$project_dir/venv/Lib/distutils/distutils.cfg",
owner => $user,
content => $mingw,
ensure => present,
require => File['fix Mingw32CCompiler'],
}
exec {'pip install requirements':
timeout => 1200,
command => "$project_dir/venv/Scripts/pip.exe install -r $project_dir/requirements.txt",
require => File['enforce MinGW compiler'],
}
file {'change venv permissions':
path => "$project_dir/venv",
recurse => true,
owner => $user,
mode => 0770,
require => Exec['pip install requirements'],
}
In puppet files have an implicit require for any parent directories that are declared.
Effectively:
File['change venv permissions'] -> File['enforce MinGW compiler']
So the parent requires the exec, the exec requires the child, and the child requires the parent, creating a loop.
What was your last change (that's probably the moment you added the cycle).
Try the suggestion to generate the graph. Post the generated dot file as gist so that we can investigate further.
Take a look at Debugging cycle or missing dependency.

Resources