Setting environment variables with puppet - ruby

I'm trying to work out the best way to set some environment variables with puppet.
I could use exec and just do export VAR=blah. However, that would only last for the current session. I also thought about just adding it onto the end of a file such as bashrc. However then I don't think there is a reliable method to check if it is all ready there; so it would end up getting added with every run of puppet.

I would take a look at this related question.
*.sh scripts in /etc/profile.d are read at user-login time (as the post says, at the same time /etc/profile is sourced)
Variables export-ed in any script placed in /etc/profile.d will therefore be available to your users.
You can then use a file resource to ensure this action is idempotent. For example:
file { "/etc/profile.d/my_test.sh":
content => 'export MYVAR="123"'
}

Or an alternate means to an indempotent result:
Example
if [[ ! grep PINTO_HOME /root/.bashrc | wc -l > 0 ]] ; then
echo "export PINTO_HOME=/opt/local/pinto" >> /root/.bashrc ;
fi
This option permits this environmental variable to be set when the presence of the
pinto application makes it warrented rather than having to compose a user's
.bash_profile regardless of what applications may wind up on the box.

If you add it to your bashrc you can check that it's in the ENV hash by doing
ENV[VAR]
Which will return => "blah"

If you take a look at Github's Boxen they source a script (/opt/boxen/env.sh) from ~/.profile. This script runs a bunch of stuff including:
for f in $BOXEN_HOME/env.d/*.sh ; do
if [ -f $f ] ; then
source $f
fi
done
These scripts, in turn, set environment variables for their respective modules.

If you want the variables to affect all users /etc/profile.d is the way to go.
However, if you want them for a specific user, something like .bashrc makes more sense.
In response to "I don't think there is a reliable method to check if it is all ready there; so it would end up getting added with every run of puppet," there is now a file_line resource available from the puppetlabs stdlib module:
"Ensures that a given line is contained within a file. The implementation matches the full line, including whitespace at the beginning and end. If the line is not contained in the given file, Puppet appends the line to the end of the file to ensure the desired state. Multiple resources can be declared to manage multiple lines in the same file."
Example:
file_line { 'sudo_rule':
path => '/etc/sudoers',
line => '%sudo ALL=(ALL) ALL',
}
file_line { 'sudo_rule_nopw':
path => '/etc/sudoers',
line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
}

Related

Chef - use env variable with package resource what created with bash resource

I would get the changed project from git commit and install the package based on this.
Here is my code
bash 'get_project' do
code <<-EOH
filelist=$(git diff-tree --no-commit-id --name-only -r $1)
for file in ${filelist[#]}; do
project=$(echo $file | cut -d "/" -f1)
projectList+=($project)
done
for changedProject in $(echo "${projectList[#]}" | sort | uniq); do
INSTALLABLE_RPM=application-$changedProject
done
EOH
environment 'INSTALLABLE_RPM' => '$INSTALLABLE_RPM'
end
zypper_package ENV['INSTALLABLE_RPM']
My idea is to generate the INSTALLABLE_RPM variable with bash and install the package with zypper. Unfortunately it doesn't work. The zypper_package resource cant recognize.
I ran out of ideas :-(
The environment property of the bash resource is to supply existing environment variables to execute the bash command(s).
(These variables must exist for a command to be run successfully.)
Specifying environment variables here will not set them in the shell. Also from within the code block you will not be able to access the Ruby's ENV hash.
There may not be a straight-forward way to do this. One of the options is to write this package (list?) to a file. Then we can read the file contents into variable, and use it with zypper_package resource.
Example:
Since you have used for loop in Shell, I believe you get a list of packages, so I am considering pkg_list as Array. I've set compile_time to true as the variable assignment below bash resource will only run during compile time.
bash 'get_project' do
code <<-EOH
# your code as-it-is
for changedProject in $(echo "${projectList[#]}" | sort | uniq); do
echo "application-$changedProject" >> /tmp/rpm_packages
done
EOH
compile_time true
end
pkg_list = File.read('/tmp/rpm_packages').split
zypper_package pkg_list
# remove the file for good measure :)
file '/tmp/rpm_packages' do
action :delete
end

bash: wrong behavior in for... loop together with a test statement

I am trying to test if certain files, called up in a list of textfiles, are in a certain directory. Every once in a while (and I am quite certain I use the same statements every time) I get an error, complaining that the echo command cannot be found.
The textfiles I have in my directory /audio/playlists/ are named according to their date on which they are supposed to be used: 20130715.txt for example for today:
me#computer:/some/dir# ls /audio/playlists/
20130715.txt 20130802.txt 20130820.txt 20130907.txt 20130925.txt
20130716.txt 20130803.txt 20130821.txt 20130908.txt 20130926.txt
(...)
me#computer:/some/dir# cat /audio/playlists/20130715.txt
#A Comment line goes here
00:00:00 141-751.mp3
00:03:35 141-704.mp3
00:06:42 140-417.mp3
00:10:46 139-808.mp3
00:15:13 136-126.mp3
00:20:26 071-007.mp3
(...)
23:42:22 136-088.mp3
23:46:15 128-466.mp3
23:50:15 129-592.mp3
23:54:29 129-397.mp3
So much for the facts. The following statement, which lets me test if all files called upon in all of the textfiles in the given directory are actually a file in the directory /audio/mp3/, produces an error:
me#computer:/some/dir# for i in $(cat /audio/playlists/*.txt|cut -c 10-16|sort|uniq); do [ -f "/audio/mp3s/$i.mp3" ] || echo $i; done
 echo: command not found
me#computer:/some/dir#
I would guess bash wants to complain about the "A Comment"-line (actually " line ") not being a file, but why would that cause echo not to be found? Again, mostly this works, but every so often I get this error. Any help is greatly appreciated.
That space before echo isn't U+0020, it's U+00A0. And indeed, the command " echo" doesn't exist.

startup script in freebsd is not running

I have been trying to run a shell script at boot time of freebsd. I have read all simmilar questions in stackoverflow and tried. But nothing is worked. This is the sample code that i tried is dummy.
#!/bin/sh
. /etc/rc.subr
name="dummy"
start_cmd="${name}_start"
stop_cmd=":"
dummy_start()
{
echo "Nothing started."
}
load_rc_config $name
run_rc_command "$1"
Saved with name of dummy.
Permissions are -r-xr-xr-x.
in rc.conf file made dummy_enable="YES".
The problem is, when i rebooted my system to test, dummy file is not there. So script is not executing. what else need to do run my dummy script.
SRC:http://www.freebsd.org/doc/en/articles/rc-scripting/article.html#rc-flags
You need to add rcvar="dummy_enable" to your script. At least for FreeBSD 9.1.
Call your script with parameter rcvar to get the enabled status:
# /etc/rc.d/dummy rcvar
# dummy
#
dummy_enable="YES"
# (default: "")
And finally start it with parameter start - this won't start the service/script unless dummy_enable is set in /etc/rc.conf (or /etc/rc.conf.local, or /etc/defaults/rc.conf)
# /etc/rc.d/dummy start
Nothing started.
One possible explanation is that rcorder(8) says:
Within each file, a block containing a series of "REQUIRE", "PROVIDE",
"BEFORE" and "KEYWORD" lines must appear.
Though elsewhere I recall that if a file doesn't have "REQUIRE", "PROVIDE" or "BEFORE", then it will be arbitrarily placed in the dependency ordering. And, it could be that the arbitrary placement differs between the first run up to $early_late_divider and in the second run of those after $early_late_divider.
OTOH, is this a stock FreeBSD, or some variant? I recall reading that FreeNAS saves its configuration somewhere else and recreates its system files on every boot. And, quite possibly that /etc is actually on a ramdisk.
Also, /usr/local/etc/rc.d doesn't come into existence until the first port installing an rc file is installed.

Running Shells as cronjobs

I am trying to work out how to setup a Shell to run as a cron, I have created a TaskEmailerShell.php file at /app/Console/Command/TaskEmailerShell.php with the following code:
App::uses('CakeEmail', 'Network/Email');
class TaskEmailerShell extends AppShell {
public $uses = array('Task');
public function main()
{
// GENERATE AND SEND THE EMAIL
// ------------------------------------------------------------>
$email = new CakeEmail();
etc etc
I have followed the instructions here and when the cron runs I get this error:
/home/village/public_html/app/Console/cakeshell: line 14: cake: command not found
My cron command is:
/home/village/public_html/app/Console/cakeshell TaskEmailer -cli /usr/bin -console /Cake/Console -app /home/village/public_html/app >> /home/village/public_html/emailer_log.log
Any suggestions where I am going wrong?
The cakeshell script you're referring to there requires the cake console binary to be somewhere in PATH, or (at least from looking at the usage example), for you to have specified the full path to the Console with the -console argument. It looks like you've got a relative path there.
Personally I recommend just calling the cake console directly from your cron job. As other needs arise you may end up writing a script like cakeshell to wrap the console. You could try something like :
# m h dom mon dow command
*/5 * * * * /home/village/public_html/lib/Cake/Console/cake -app '/home/village/public_html/app/' TaskEmailer >> /home/village/public_html/emailer_log.log
Command not found usually means your PATH is the problem. Programs run from cron might not even have PATH set. Any script started by cron must set PATH near the beginning or it won't find any of the programs it is supposed to run.
The error occurs at line 14 in the file cakeshell: $cmd. cmd is set at line 4.
#!/bin/bash
TERM=dumb
export TERM
cmd="/opt/lampp/htdocs/MyApp/app/Console/cake"
while [ $# -ne 0 ]; do
if [ "$1" = "-cli" ] || [ "$1" = "-console" ]; then
PATH=$PATH:$2
shift
else
cmd="${cmd} $1"
fi
shift
done
$cmd
Originally line 4 is
cmd="cake"
Change it to absolute path like:
cmd="/opt/lampp/htdocs/MyApp/app/Console/cake"
where MyApp is the application directory. I have faced this problem even after PATH settings. Then mentioning the absolute path solved it.

updating file using 'file' chef-solo resource

i am trying to install java using chef-solo. The problem is to set the JAVA_HOME and PATH variables in /etc/profile file. I tried using 'file' resource provided by chef. here is some of my code:
java_home = "export JAVA_HOME=/usr/lib/java/jdk1.7.0_05"
path = "export PATH=$PATH:/usr/lib/java/jdk1.7.0_05/bin"
execute "make_dir" do
cwd "/usr/lib/"
user "root"
command "mkdir java"
end
execute "copy" do
cwd "/usr/lib/java"
user "root"
command "cp -r /home/user/Downloads/jdk1* /usr/lib/java"
end
file "/etc/profile" do
owner "root"
group "root"
action :touch
content JAVA_HOME
content PATH
end
but the problem is content command overrides all the content of file, is there any way to UPDATE the file while using chef-solo resources. Thanks!
UPDATE: i have found some code from chef-recipe, but i am not sure what it does exactly, the code is..
ruby_block "set-env-java-home" do
block do
ENV["JAVA_HOME"] = java_home
end
end
Does it set JAVA_HOME variable for only that instance or permanently? Can anybody help?
Use Chef::Util::FileEdit. Below is an example how I modify .bashrc. The idea here is that I just add:
# Include user specific settings
if [ -f ~/.bashrc_user ]; then . ~/.bashrc_user; fi
to the end of default .bashrcand all other modifications take place in .bashrc_user that is part of my cookbook.
cookbook_file "#{ENV['HOME']}/.bashrc_user" do
user "user"
group "user"
mode 00644
end
ruby_block "include-bashrc-user" do
block do
file = Chef::Util::FileEdit.new("#{ENV['HOME']}/.bashrc")
file.insert_line_if_no_match(
"# Include user specific settings",
"\n# Include user specific settings\nif [ -f ~/.bashrc_user ]; then . ~/.bashrc_user; fi"
)
file.write_file
end
end
As #user272735 's suggestion, a clean way to modify .bashrc is:
write all your modification in a .bashrc_local file,
include your specific settings to .bashrc.
For step 1, we can use template resource.
For step 2, I prefer use line cookbook.
Sample codes as below,
templates/bashrc_local.erb
export JAVA_HOME=/usr/lib/java/jdk1.7.0_05
export PATH=$PATH:/usr/lib/java/jdk1.7.0_05/bin
recipes/default.rb
# add bashrc_local
template "#{ENV['HOME']}/.bashrc_local" do
source 'bashrc_local.erb'
mode 00644
end
# update bashrc
append_if_no_line "add bashrc_local" do
path "#{ENV['HOME']}/.bashrc"
line "if [ -f ~/.bashrc_local ]; then . ~/.bashrc_local; fi"
end
You can fix this by either using a template resource instead of a file resource, or if you are just appending those two variables, try doing this:
content "#{java_home}\n#{path}"
The second content line is overriding the first, as you have already discovered. You also don't need the action :touch.

Resources