Chef understanding only_if in execute resource - ruby

I have here an execute block that looks like this
execute 'uninstall_datadog' do
command 'sudo apt-get --purge remove datadog-agent -y'
only_if 'command -v datadog-agent'
end
So my understanding is if exit status of only_if is not 0 then this block will not execute. Is this true?

Yes.
However I see some problems with your example:
the built-in package resource is able to remove a package if it is installed.
package 'datadog-agent' do
action :purge
options '--yes' # not sure about this
end
If the package is not installed (anymore), chef will just skip it.
See https://docs.chef.io/resource_package.html for more details.
usually chef runs as root so the sudo command is not needed in execute commands.
only_if by default runs in the environment of the chef-client/chef-solo/chef-apply process. See https://docs.chef.io/resource_common.html#arguments you'll have to adjust environment variables like PATH when impersonating as another user

command is a bash builtin, looks like might not be executing as bash.
bash -c "command -v datadog-agent" would work, but could also use which datadog-agent instead.

Related

Bash script behaving different than when manually executing commands into remote server

I have a remote server and I can ssh into it and when I execute npm install it works just fine. I can see that it's installed by calling which npm and i see:
/home/ubuntu/.nvm/versions/node/v15.11.0/bin/npm
Great.
However, when I do this via a bash script, it says
bash: line 1: npm: command not found
My script:
#!/bin/bash
ssh he-int 'npm install'
Why the discrepancy between the two ? It's the same commands...
Sounds like maybe npm is added to your PATH in one of the login scripts (.bashrc, .profile, etc). I especially think this is true because the npm path indicates you are using nvm to manage your npm environment. There may be a call to nvm to add npm to the path in one of those login scripts.
When you run an ssh command like your second command, it doesn't run as a login shell, so it doesn't run the login scripts. You can either:
Try and force it to run as a login shell (ssh -t maybe? not sure).
Try to initialize your npm environment inside your script, probably by calling nvm.
npm may not be in the PATH of the user you're sshing in as using the bash script.
Use this to see what's in your PATH variable:
ssh he-int 'echo $PATH'
You can also just try to use the path directly and see if it works.
#!/bin/bash
ssh he-int '/home/ubuntu/.nvm/versions/node/v15.11.0/bin/npm install'

Installing cpanm in a bash script

I'm writing a script that installs and configures Nagios to my requirements. It requires cpanm and some perl modules.
It's using the step/try/next function from here: https://stackoverflow.com/a/5196220
step "Downloading cpanm installer"
try `wget -q http://cpanmin.us -O $swrepo/cpanm.install`
next
step "Installing cpanm"
try echo '{ exec </dev/tty; cat $swrepo/cpanm.install | perl - App::cpanminus; }' | bash
# try bash -c "$(cat $swrepo/cpanm.install | perl - App::cpanminus)"
# try cat $swrepo/cpanm.install | perl - App::cpanminus
next
step "Installing Perl module Nagios Config"
try `cpanm Nagios::Config`
next
My problems here are:
whichever way I attempt to run the install for cpanminus, it fails the script, and won't install properly. I can't seem to make it function outside of the step/try/next functions (not that I want it to.)
The cpanm command fails too. If I isolate and run only this part of the script, it still fails, with "cpanm command not found." I can run it manually at the command line.
Any pointers for the slightly frustrated?
Update
I pulled the cpanm setup out to a separate file:
step "Installing cpanm"
try sh conf_cpanm.sh
next
Which works, and I'll probably try and pull it back in at a later date, but so far that functions. So it can stay.
However, doing the same for
try cpanm Nagios::Config
won't work. The file looks like this:
#!/bin/bash
cpanm Nagios::Config
...and if I run that by calling sh conf_nagcpanm.sh it works fine.
I think using backticks
try `cpanm Nagios::Config`
is a mistake. bash will take an expression in backticks, execute it, and substitute the output of the command for the expression. The output of cpanm is not going to be shell commands, so this will not work. It should simply be
try cpanm Nagios::Config

How can I default to a login shell for Jenkins shell execution

I want to use rvm (or rbenv/chruby for that matter) to select different ruby versions from within my Jenkins jobs.
By default, Jenkins will use /bin/sh, which on Ubuntu, is dash.
For this to change, I can add
#!/bin/bash -l
To the top of every single shell execute function everywhere. Seeing as that's a lot of annoying work, I'd like to be able to set that somewhere central.
Using the "Shell executable" configuration setting, I can get it to run bash, adding parameters like '-l' however will fail with
"/bin/bash -l" -xe /tmp/hudson5660076222778817826.sh FATAL:
command execution failed java.io.IOException: Cannot run program
"/bin/bash -l" (in directory
"/home/jenkins/jobs/workspace/rvm-test"): error=2, No such file or
directory
I tried using the rvm plugin for jenkins, but that doesn't even install on the current release version.
Any ideas? :)
You could work around by creating a wrapper around bash:
#!/bin/sh
# for ex.: /usr/local/bin/login-bash
exec /bin/bash -l "$#"
If you want to use the default ruby just use the rvm-shell, which comes with rvm.
Login as the jenkins user and type:
$ which rvm-shell
/home/jenkins/.rvm/bin/rvm-shell
to get the path of the rvm-shell.
Use this path for the "Shell executable" option.

Variable assignment fails if called with sudo

I have to do an assignment like m=7 from the C++ command line application. When I run this application using sudo MyApp, the command present in the program fails to execute.
sudo m=7
fails with the following error
Command Not Found.
Is there any way so that I can assign value to a variable with the sudo keyword present in the command?
Basically I want a way to do sudo {Assignment} i.e. sudo m=3. Thanks.
The sudo command allows one to run an external command as a given user (default: root). m=7 is not an external command and hence cannot be run by sudo. It is a variable assignment statement that is directly interpreted and executed by the current shell.
The Command not found message indicates that sudo failed to find an executable command named m=7.
In fact, it is hard to imagine what the intended goal of running sudo m=7 might be. If you want to assign 7 to the shell variable m you do not need any special privileges or sudo for that, just run m=7. If you want to open root shell and execute some commands there starting with m=7 just start with sudo bash and then issue the m=7 statement.

Setting path for whenever in cron so it can find ruby

My ruby is in /usr/local/bin. whenever can't find it, and setting PATH at the top of my cron file doesn't work either, I think because whenever is running the command inside of a new bash instance.
# this does not work
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin
# Begin Whenever generated tasks for: foo
0 * * * * /bin/bash -l -c 'cd /srv/foo/releases/20110429110637 && script/rails runner -e production '\''ActiveRecord::SessionStore::Session.destroy_recent(15)'\'''
# End Whenever generated tasks for: foo
How can I tell whenever where my ruby binary is? Making a symbolic link from /usr/bin seems messy to me, but I guess that might be the only option.
This question offers env :PATH, "..." in schedule.rb as a solution, but (a) I can't find any documentation of that feature anywhere in the docs (b) it doesn't seem to have solved the asker's problem (unfortunately it takes non-trivial turnaround time for me to just try it).
update actually it is in the bottom of this page, i'll try it now.
more info
I can't modify the cron command because it's generated by whenever
i verified that if I make a new bash shell with bash -l, /usr/bin/env finds ruby just fine
I just tried the exact command in cron, starting with /bin/bash, from the command line of that user, and it worked.
so, this is very mysterious...
The solution is to put this in schedule.rb:
env :PATH, ENV['PATH']
Here's a little guide I put together on the topic.
rewrite your crontab as
0 * * * * { PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin ; export PATH ;/bin/bash -l -c 'cd /srv/foo/releases/20110429110637 && script/rails runner -e production '\''ActiveRecord::SessionStore::Session.destroy_recent(15)'\''' ; }
Or you should try to figure out why your BASH shell is not picking the PATH=... that is almost certainly in your .profile or .bash_profile.
I hope this helps.
As John Bachir pointed out, you can do it via env. But let me add more input. I am deploying on AWS Opsworks. Unfortunately they do not have a ruby manager (RVM, Rbenv, etc) installed by default.
The first thing I needed to do was SSH into the instance and figure out which ruby I was using. This was easy enough by executing the which ruby command in a terminal.
$ which ruby
/usr/local/bin/ruby
Cron was using ruby located at /usr/bin/ruby. This needed to be changed.
In schedule.rb, I have:
set :env_path, ''
env :PATH, #env_path if #env_path.present?
In local, env_path doesn't need to be set. For most users, the only thing to do is execute whenever as such:
bundle exec whenever --set 'environment=development' --update-crontab
On a staging / production environment, ruby may be installed elsewhere. So running this may be more appropriate:
bundle exec whenever --set 'environment=staging&env_path=/usr/bin/local' --update-crontab
You will need to replace /usr/bin/local with the output of echo $PATH.
In Opsworks, however, I needed to create a custom Chef recipe that looked like:
node[:deploy].each do |application, deploy|
execute 'whenever' do
user 'deploy'
group 'nginx'
cwd "#{deploy[:deploy_to]}/current"
command "bundle exec whenever --set 'environment=#{deploy[:environment_variables][:RAILS_ENV]}&env_path=#{ENV['PATH']}' --update-crontab"
end
end
I hope the information here is clear enough.

Resources