chef logging of wget - bash

I have a chef recipe that looks something like:
Chef::Log.info('step1')
# do stuff
Chef::Log.info('step2')
bash "do_wget" do
code <<-EOF
wget somefile
EOF
end
Chef::Log.info('step3')
# do stuff
The wget takes a while but the logging ends up looking like
step1
step2
step3
bash script runs #indicates that the bash script from step 2 is running
Is there a way to prevent the logging from step3 until the bash script is done executing?

You should get acquainted with Anatomy of Chef Run. It has 2 stages: compiling and executing.
No action is taken on the resources in the recipes at compiling stage - each evaluated resource is just taken and put into the Resource Collection. Plain Ruby code outside of resources is evaluated, however.
In execution stage it actually evaluates Resource Collection. But by this moment all your logging messages are already printed out.
If you need to run ruby code (including Chef logging) on execution stage, there is a special resource for that Ruby Block
ruby_block "Add logging step3" do
block do
Chef::Log.info('step3')
end
action :create
end
Another way may be, is to actually execute resource in compiling stage:
bash "do_wget" do
code "wget somefile"
action :nothing
end.run_action :run
Action :nothing is set to avoid running this resource twice (once in every stage).

You can use the log resource instead, which I understand runs at the execution stage as you require
log "step2" do
:info
end
or simply
log "step 3"
http://docs.opscode.com/resource_log.html

Related

Strange behavior with ruby_block resource in Chef

I have two ruby blocks at the end of a recipe:
ruby_block 'set permissions for app dir' do
block do
require 'fileutils'
FileUtils.chown_R 'user01', 'user01', '/mnt/app/'
end
action :run
end
ruby_block 'configure node app session' do
block do
cmd = "sudo su - user01 -c \"/mnt/app/http-app-/bin/app create /mnt/app/http-app/#{node['hostname']}\" && sudo su -c 'systemctl enable app' && sudo su -c 'systemctl start app'"
exec(cmd)
end
action :run
not_if "stat -c %U /mnt/app/#{node['hostname']} |grep app"
end
A couple strange things are happening. One, I cannot add any code after the last block... it will not run if added. Two, when the cookbook runs the recipe never ends with if the run failed or was successful. Bootstrapping the system a second time will prove to finish successful... but ssh'ing to the box and running chef-client comes back with an empty run list.
Can anyone explain this behavior? How can i fix it?
exec() is not what you think. That's a Ruby core method which calls the actual exec() syscall, which replaces the current process with something new. What you want is our shell_out!() helper which runs a subcommand and returns and object with the results.

Can I use guards to chef if a windows service is running?

I'm writing a chef recipe and on this I need to perform an operation (run a batch) only if a service is not working.
I use this snippet:
batch 'run commnad' do
cwd target_path + '/bin/win64'
code 'command to be executed'
not_if '::Win32::Service.exists?("Service name")'
end
But it does not seems to work. After seeing this question I changed the process using an if clause instead of the guard and it works fine:
if !::Win32::Service.exists?("Service name") then
batch 'Install zabbix agent' do
cwd target_path + '/bin/win64'
code 'command to be executed'
end
end
But this should not be, for what I understood, the right way to manage this, so I'm wondering: why is the guard not working properly?
Thanks,
Michele.
The way you wrote your not_if statement runs the command as a shell script.
The shell doesn't know Ruby code, so the whole command will fail.
Need to first:
require win32/service
In order to use not_if with Ruby code you should put it inside a block instead:
not_if { ::Win32::Service.exists?("Service name") }
See some more examples here (search for not_if on the page):
https://docs.chef.io/resource_common.html
Here is the working example (Chef 13)
require 'win32/service'
windows_service "jenkins" do
action [:stop, :disable]
only_if { ::Win32::Service.exists?("jenkins")}
end

Chef run sh script

I have a problem trying to run shell script via Chef (with docker-provisioning).
This is how I try to execute my script:
bash 'shell_try' do
user "root"
run = "#{some_path_to_script}/my_script.sh some_params"
code " #{run} > stdout.txt 2> stderr.txt"
end
(note that this script should run another scripts, processes and write logs)
Here's no errors in the output, but when I log into machine and run ps aux process isn't running.
I guess something wrong with permissions (or env variables), because when I try the same command manually - it works.
A bash resource just runs the provided script text directly, if you wanted to run a long-running process generally you would set up an Upstart or systemd service and use the service resource to start it.
Finally find a solution (thanks to #coderanger) -
Install supervisor:
Download supervisor cookbook
Add:
include_recipe 'supervisor::default'
Add my service to supervisor:
supervisor_service "name" do
action :enable
#action :start
command '/path/script.sh start'
end
Run supervisor service
All done!
Please see the Chef documentation for your resource: https://docs.chef.io/resource_bash.html. The bash resource does not support a run attribute. Text of the code attribute is run as a bash script. The default action is to run the script unless told otherwise by the resource.
bash 'shell_try' do
user "root"
code " #{run} > stdout.txt 2> stderr.txt"
action :run
end
The code attribute is written to a temporary file where it is then run using the attributes specified in the resource.
The line run = "#{some_path_to_script}/my_script.sh some_params" at this point does nothing.

Chef Bash Resource Not Running

I've currently created a custom lwrp that essentially runs a bash script that curls for the localhost after tomcat restarts to make the sure the service is running.
My provider file looks like this:
use_inline_resources
action :run do
bash "checkhealth" do
user "root"
code <<-EOF
echo Started counting
curl http://localhost/version.html
...
EOF
end
end
On one of my nodes, I have the following block:
service "node" do
supports :start => true, :stop => true, :restart => true, :status => true
action :nothing
notifies :run, "healthcheck[check-status]", :delayed
end
And when i run chef-client, I can see the echos from the bash code running.
However, on a different node, I have a block like this:
service "tomcat" do
action :restart
notifies :run, "healthcheck[check-status]", :delayed
end
But I can't see any output from the echo and it doesn't look like the bash code is running. I know the bash resource is being executed because the log output says the bash resource was successfully run. However, there is a very long delay after the log says:
action run[2014-07-23T09:10:23-07:00] INFO: Processing bash[checkhealth] action run
and when it says it was successful, which makes me think something weird is going on with the bash code, but I'm not sure what. This is where I'm stuck and hoping you guys could help me figure out this weird bug :). I'm guessing it may have something to do with the fact that in the first block, the action is :nothing, but the second block has :restart.
Let me know what you guys think.
Thanks!
Why not emulate what the old Jenkins cookbook (v1.2.2) used to do?
See:
Ruby block that checks for running service
Helper functions contained in a chef library

How to code elasticsearch status checks in ruby with Chef?

I want to accomplish two things:
1) clean out any pointless pid files (if elasticsearch is not running) and then start it, and
2) check that ES has started up before proceeding
Now between what Chef offers out-of-box and what Ruby allows, I can only figure out a pseudo-code like syntax for making it happen but its not going to run so I need some help/advice writing the real thing.
Pseudo-Code For (1):
bash "start it up" do
user "root"
only_if { # pretty sure this syntax is all incorrect, any ideas to make it happen?
(sudo service elasticsearch status).match(/^elasticsearch not running/)
}
code <<-EOS
sudo rm -rf /usr/local/var/run/elasticsearch/*.pid
sudo service elasticsearch restart
EOS
end
Pseudo-Code For (2):
bash "wait for it to start up" do
user "root"
only_if { # pretty sure this syntax is all incorrect, any ideas to make it happen?
(sudo service elasticsearch status).match(/^elasticsearch running with PID/)
}
retries 20
retry_delay 5
code <<-EOS
echo "I can now go on with my life..."
EOS
end
If you wish to ensure a certain particular status before continuing, insert this in a recipe (this is an example and not tested):
service "elasticsearch" do
action [ :enable, :start ]
status_command "/usr/sbin/service elasticsearch status | grep 'running with PID'"
end
It's the job of the init script's start command to wait for the service to be actually started.
Chef docs says:
There is no reason to use the execute resource to control a service because the service resource exposes the start_command attribute directly, which gives a recipe full control over the command issued in a much cleaner, more direct manner.

Resources