First off, very new to Capistrano, so excuse my newbness.
I am deploying a CodeIgniter application of which I have a data folder that lives outside the current web directory that I am trying to symlink to. This is what I have used to create the symlink
set :shared_dir, %w(/var/www/website/)
set :linked_dirs, %w{43b621acdfc9523443f27b7767e}
This is the result of the deployed application
43b621acdfc9523443f27b7767e -> /var/www/website/shared/43b621acdfc9523443f27b7767e
My goal is to override the shared_dir variable to generate a symlink of
/var/www/website/43b621acdfc9523443f27b7767e
I am using Capistrano 3. Any insight greatly appreciated.
Thanks
You can create an specific task to take care of creating and updating the symlink from anywhere in your application to anywhere in your system on each deploy. For example:
namespace :terminal do
task :link_external_dir, :except => { :no_release => true } do
capifony_pretty_print '--> Generating soft link with external_example_dir'
run "sharedWebDir=#{shared_path}/web; cd $sharedWebDir; if [ -d $sharedWebDir/internal_example_dir -o -f $sharedWebDir/internal_example_dir ]; then rm -rf $sharedWebDir/internal_example_dir; fi; if [ ! -L $sharedWebDir/internal_example_dir ]; then ln -s /srv/example/vhost/external_example_dir $sharedWebDir/internal_example_dir; fi;"
capifony_puts_ok
end
task :rm_shared_example_dir, :except => { :no_release => true } do
capifony_pretty_print '--> Removing sharedDir/internal_example_dir symlink'
run "sharedWebDir=#{shared_path}/internal_example_dir; if [ -L $sharedWebDir/internal_example_dir ]; then rm $sharedWebDir/internal_example_dir; fi;"
capifony_puts_ok
end
end
Now call each function on each deploy:
before "deploy", "terminal:rm_shared_example_dir"
after "deploy", "deploy:cleanup"
after "deploy", "terminal:link_external_dir"
What we are trying to accomplish is:
1.Before Deploy, remove the file from your main sharedDir that links to your external dir.
REMOVE
/var/www/website/shared/externalDir -> /srv/example/vhost/external_example_dir
2.Deploy your app.
3.Generate the custom symlink again.
ln -s /srv/example/vhost/external_example_dir $sharedWebDir/internal_example_dir
Related
I have a bash command that will return either 1 or 0. I want to run said command from puppet:
exec { 'Check if Thinkpad':
command => 'sudo dmidecode | grep -q ThinkPad && echo 1 || echo 0',
path => '/usr/bin/:/bin/bash/',
environment => "HOME=/root"
}
Is there a way I can include a file using puppet only if my command returned 1?
file { '/etc/i3/config':
source => 'puppet:///modules/i3/thinkpad',
owner => 'root',
group => 'root',
mode => '0644',
}
You can use an external fact to use the bash script as is. Inside the module's facts.d directory, you could place the script.
#!/bin/bash
if [ dmidecode | grep -q ThinkPad ]
echo 'is_thinkpad=true'
else
echo 'is_thinkpad=false'
fi
You can also use a custom fact inside the lib/facter directory of your module.
Facter.add(:is_thinkpad) do
confine kernel: linux
setcode do
`dmidecode | grep -q ThinkPad && echo true || echo false`
end
end
In both cases, the fact name of is_thinkpad follows the convention for the nomenclature of boolean facts for types of systems. You can then update the code in your manifest for this boolean.
if $facts['is_thinkpad'] == true {
file { '/etc/i3/config':
source => 'puppet:///modules/i3/thinkpad',
owner => 'root',
group => 'root',
mode => '0644',
}
}
This will provide you with the functionality you desire.
https://docs.puppet.com/facter/3.6/custom_facts.html#adding-custom-facts-to-facter
https://docs.puppet.com/facter/3.6/custom_facts.html#external-facts
You will probably need to turn your bash script into a "custom fact" -- which is something I've only done once and don't fully understand enough to teach you how.
I want to say that the easiest way to set up a custom fact is to put your script into /etc/facter/facts.d/ on the agent machine, and make sure it ends with a line that says
echo "thinkpadcheck=1"
or
echo "thinkpadcheck=0"
You can test it with (note: you must be root)
sudo facter -p | grep think
and it should return
thinkpadcheck => 1
But once you have done that, then your puppet script can say
if $thinkpadcheck == 1
{
file { '/etc/i3/config':
source => 'puppet:///modules/i3/thinkpad',
owner => 'root',
group => 'root',
mode => '0644',
}
}
else
{
notify { "thinkpadcheck failed for $hostname" : }
}
I'd like to share another method I found in the Puppet Cookbook 3rd edition (page 118):
message.rb
#!/usr/bin/env ruby
puts "This runs on the master if you are centralized"
Make your script executable with:
sudo chmod +x /usr/local/bin/message.rb
message.pp
$message = generate('/usr/local/bin/message.rb')
notify { $message: }
Then run:
puppet apply message.pp
This example uses a ruby script but any type of script including a basic shell script, as was needed in my case, can be used to set a variable in puppet.
Say you copy folder f_1 from your local machine to target machine m_1 into the /tmp directory as mf_1.
console:
[root#m_1 tmp] ls -a | grep mf_1 # => doesn't exist
irb:
options = {recursive: true}
Net::SCP.upload!(host, user, '~/f_1', '/tmp/mf_1', options)
console:
[root#m_1 tmp] ls -a | grep mf_1 # => folder exists, everything is fine
# but then, if you try to overwrite the existing folder...
irb:
Net::SCP.upload!(host, user, '~/f_1', '/tmp/mf_1', options)
console:
[root#m_1 tmp] ls -a | grep mf_1 # => folder exists
[root#m_1 tmp] cd mf_1
[root#m_1 m_f1] ls # => f_1 => /tmp/mf_1/f_1
So, instead of mf_1 being overwritten folder was copied inside of /tmp/mf_1, resulting in /tmp/mf_1/f_1.
The question is pretty simple, how to preserve the behavior so it's consistent and calling
Net::SCP.upload!(host, user, '~/f_1', '/tmp/mf_1', options)
twice in a row would act the same way both when folder exists and doesn't?
I ended up adding a dot, if source is a dir.
This is not ideal, here's an example:
options = {recursive: true}
# target /tmp/mf_1 doesn't exist
Net::SCP.upload!(host, user, '~/f_1/.', '/tmp/mf_1', options)
# target /tmp/mf_1 has been created
# second time
Net::SCP.upload!(host, user, '~/f_1/.', '/tmp/mf_1', options)
# target /tmp/mf_1 has been overwritten
# not dir, but files in it, which is what we usually want
How to exec a command if directory does not exists in puppet file?
exec { "my_exec_task":
command => "tar zxf /home/user/tmp/test.tar.gz",
unless => "test -d /home/user/tmp/new_directory",
path => "/usr/local/bin/:/bin/",
}
I get error: "Could not evaluate: Could not find command 'test'". Also is this the best practice to check if directory does not exists?
test work for me at /usr/bin, so adding it to path could solve error.
unless => 'bash -c "test -d /home/user/tmp/new_directory"',
Should work too. But I think the correct way is to use creates:
exec { "my_exec_task":
command => "tar zxf /home/user/tmp/test.tar.gz",
creates => "/home/user/tmp/new_directory",
path => "/usr/local/bin/:/bin/",
}
Actual problem is in path:
path => [ '/usr/local/bin', '/sbin', '/bin', '/usr/sbin', '/usr/bin' ]
I'm trying to configure paperclip to use it with openshift but I can't do it right, any suggestion?
has_attached_file :photo,
:styles => {
:thumb=> "100x100#",
:small => "400x400>"
},
:url => "/assets/users_folder/:id/:style/:id.:extension",
:path => ENV['OPENSHIFT_DATA_DIR']+"public/assets/users_folder/:id/:style/:id.:extension"
We ended doing this:
:url => "/assets/:id.:extension",<br>
:path => ":rails_root/public/assets/:id.:extension"
and on the deploy file of openshif ( /.openshift/action_hooks/deploy ):
STORED_ASSETS="${OPENSHIFT_DATA_DIR}/assets"
LIVE_ASSETS="${OPENSHIFT_REPO_DIR}/public/assets"
\# Ensure our stored assets directory exists
if [ ! -d "${STORED_ASSETS}" ]; then
echo " Creating permanent assets directory"
mkdir "${STORED_ASSETS}"
fi
\# Create symlink to stored assets unless we're uploading our own assets
if [ -d "${LIVE_ASSETS}" ]; then
echo " WARNING: Assets included in git repository, not using stored assets"
else
echo " Restoring stored assets"
ln -sf "${STORED_ASSETS}" "${LIVE_ASSETS}"
fi
that way we created a link to our data folder (OPENSHIFT_DATA_DIR) that will never be removed by git pushes.
Based on the answer by alfredo in your models in order to save different styles for different models to - similar to Paperclip's default:
has_attached_file :image,
:url => "/uploads/:class/:attachment/:id/:style_:filename",
:path => ":rails_root/public/uploads/:class/:attachment/:id/:style_:filename"
Quick explanations:
:rails_root will be your rails root
:class will be the name of your model of the image (pluralized)
:attachment will be the name of the field (pluralized)
:id will be the current id of the model
:style_ will be the styles you have defined for your images (eg thumb, original, etc)
:filename will be the final filename in the folder
(rails_root is your rails root, class is usually the name of your model, attachment is the name of the field, id is the id of the model, style is the style you have defined - thumb etc - and filename is the filename for the image)
Notice the change of the /assets/ to /uploads/ folder. Based on your git configuration the assets folder might be deleted.
Finally, at the end of the /.openshift/action_hooks/deploy file:
STORED_ASSETS="${OPENSHIFT_DATA_DIR}/uploads" LIVE_ASSETS="${OPENSHIFT_REPO_DIR}/public/uploads"
# Ensure our stored assets directory exists
if [ ! -d "${STORED_ASSETS}" ]; then
echo " Creating permanent assets directory"
mkdir "${STORED_ASSETS}"
fi
# Create symlink to stored assets unless we're uploading our own assets
if [ -d "${LIVE_ASSETS}" ]; then
echo " WARNING: Assets included in git repository, not using stored assets"
else
echo " Restoring stored assets"
ln -sf "${STORED_ASSETS}" "${LIVE_ASSETS}"
fi
I would like to create a package that contains a file but renames it inside the package.
For example:
Rake::PackageTask.new("rake", "1.2.3") do |p|
p.package_files.include("aa.rb")
end
I would like aa.rb to be named bb.rb inside the package.
How can I do this elegantly?
Looking at the PackageTask source, it seems you could define a new task (say rename_files) that depends on on the p.package_dir_path task defined by Rake::PackageTask. In rename_files task you can rename the file link(s) which package_dir_path task made in package_dir. Then you add your new rename_files task as a dependency for each of the "#{package_dir}/#{[tar|zip|etc]_file}" task targets you care about.
With these dependencies, the order of operations should become:
set up package_dir with links to source files from package_files
rename links with your injected dependency
execute archive creation command on package_dir
If this isn't clear enough to get you there, I'll try and post some actual code later.
[LATER] Ok, some code. I made a sample project which looks like this:
$ find .
.
./lib
./lib/aa.rb
./lib/foo.rb
./Rakefile
And in the Rakefile, I define a package task as:
require 'rake/packagetask'
Rake::PackageTask.new('test', '1.2.3') do |p|
p.need_tar = true
p.package_files.include('lib/**/*')
task :rename_files => [ p.package_dir_path ] do
fn = File.join( p.package_dir_path, 'lib', 'aa.rb' )
fn_new = File.join( p.package_dir_path, 'lib', 'bb.rb' )
File.rename( fn, fn_new )
end
[
[p.need_tar, p.tgz_file, "z"],
[p.need_tar_gz, p.tar_gz_file, "z"],
[p.need_tar_bz2, p.tar_bz2_file, "j"],
[p.need_zip, p.zip_file, ""]
].each do |(need, file, flag)|
task "#{p.package_dir}/#{file}" => [ :rename_files ]
end
end
The logic here is what I explained above. Running it, you can see that the hard link made in the package dir is renamed from "aa.rb" to "bb.rb", then we tar the directory and viola!
$ rake package
(in /Users/dbenhur/p)
mkdir -p pkg
mkdir -p pkg/test-1.2.3/lib
rm -f pkg/test-1.2.3/lib/aa.rb
ln lib/aa.rb pkg/test-1.2.3/lib/aa.rb
rm -f pkg/test-1.2.3/lib/foo.rb
ln lib/foo.rb pkg/test-1.2.3/lib/foo.rb
cd pkg
tar zcvf test-1.2.3.tgz test-1.2.3
a test-1.2.3
a test-1.2.3/lib
a test-1.2.3/lib/bb.rb
a test-1.2.3/lib/foo.rb
cd -
Here's the tar manifest with "bb.rb" instead of "aa.rb":
$ tar tf pkg/test-1.2.3.tgz
test-1.2.3/
test-1.2.3/lib/
test-1.2.3/lib/bb.rb
test-1.2.3/lib/foo.rb