With capistrano, I am deploying a Rails application from Mac OS X 10.5 to CentOS 5.2
Note that deploy.rb and the server environment have not changed in over a year.
There is a task within our deploy.rb file called upload:
put(File.read( file ),"#{shared_path}/#{filename}", :via => :scp)
This fails each and every time with the following exception:
No such file or directory - /srv/ourapp/releases/20100104194410/config/database.yml
My local copy of config/database.yml is failing to upload properly. I've verified it's not our internet connection, as this happens on three different connections and two different systems.
I've also tried to swap out put() for upload() but get the same result; also, dropping :via => :scp, and/or trying to force :sftp instead similarly fails.
Relevant info:
$ cap -V
Capistrano v2.5.10
$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin9.6.0]
If I understand your question correctly, it sounds like Capistrano is successfully uploading the files, but Rails is failing to start because it can't find the deploy.yml file. This might be happening during the Capistrano deploy as part of the deploy:restart task, making it look like a Capistrano error.
Based on the information you've given Capistrano is uploading the file to /svr/ourapp/shared/ and Rails is almost definitely looking for it in /svr/ourapp/releases/20100104194410/config/.
If that's the case, what you'll need to do is create a task which symlinks the shared database file to the expected location then add a hook so that task will be run after finalize_update. For instance:
task :symlink_database do
run "ln -s #{shared_path}/database.yml #{latest_release}/config/database.yml"
end
after 'deploy:finalize_update', :symlink_database
namespace :deploy do
task :upload_settings, :roles => :app do
run "mkdir -p #{shared_path}/config/"
top.upload "config/database.yml", "#{shared_path}/config/database.yml", :via => :scp
end
task :symlink_yml, :roles => :app do
run "ln -sf #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
end
after 'deploy:setup', 'deploy:upload_settings'
after 'deploy:update_code', 'deploy:symlink_yml'
This is purely from a server-side view, but have you checked to make sure that the user you're using to upload has proper permissions for the directory?
Doing a recursive change for the user (or group) depending on your server environment should fix this.
chown -R user_name_here /srv/ourapp/releases/
chgrp -R group_name_here /srv/ourapp/releases/
You might also want to clean up any code repositories e.g. git gc or svn cleanup. As well as updating any symbolic links.
The "No such file or directory" error occurs when you are trying to copy a file to a destination path that does not exist. As far as I know, the put and upload methods of Capistrano merely attempt to transfer the file, but do not make the required path. Is it possible that the config/ directory, or even the shared_path itself, has not been created when you are trying to upload this file?
Related
Everytime I deploy my redmine repository with capistrano my files are gone. I can see that capistrano symlinks the public directory, but not the {ROOT}/files directory.
I've read some articles on the internet but can't seem to get it work.
So I want is to keep my files in the {APPROOT/files} directory after a deploy
Many thanks for reading this.
You have two solutions:
1: Put your files directory in public/shared, which persists over the deployments.
2: Add a task in your capistrano recipe to create the symlink after each deploy:
task :create_files_symlink, :roles => :app do
run "ln -nfs #{shared_path}/files #{release_path}/files"
end
after 'deploy:update_code', 'create_files_symlink'
I don't check my database.yml file into source control and I was wondering what others do/best practice for copying this file over to the server when deploying.
I use Capistrano for deployment.
Currently, I keep a shared folder called shared that lives outside of my deply_to dirs. I keep my database.yml and other config files there and have a hook in cap to cp those over during deployment. Here is my simple cap task for doing the copy:
after "deploy:update_code","deploy:config_symlink"
namespace :deploy do
task :config_symlink do
run "cp #{shared_path}/../../shared/database.yml #{release_path}/config/database.yml"
end
end
My deployment script was breaking using the after "deploy:update_code" hook because that step seemed to be trying to access the DB already. So I do:
before "deploy:assets:precompile", 'deploy:symlink_shared'
namespace :deploy do
task :symlink_shared do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
end
I've been beating my head on this one for quite some time, and have figured out an easier solution for Capistrano 3. Hope this helps those out there.
I couldn't for the life of me get the "run" or "execute" commands to work in my deploy.rb file. As it turns out, in Capistrano 3, you should put your database.yml underneath the deployment_directory/shared folder. Then, in your deployment.rb file, include the file in the linked_files variable and it automatically gets symlinked to the same path during deployment.
Here's an example:
For starters, I don't have database.yml checked into source control. My database.yml is located here on the production server:
var/www/myapp/shared/config/database.yml
In my deployment.rb, I've added this line
set :linked_files, %w{config/database.yml}
During the deployment, capistrano automatically symlinks the file to:
var/www/myapp/current/config/database.yml
Hope this helps others out there. I've really been beating my head on the wall on this today.
I'm sort of stuck with adding symlinks to my app on the server. I currently have the following in .gitignore:
/non-public/system/uploads/*
I basically don't want Git to store the contents of the upload directory. So far so good.
On my server, inside my deploy.rb, I have the following:
namespace :customs do
task :symlink, :roles => :app do
run <<-CMD
ln -nfs #{shared_path}/system/uploads #{release_path}/non-public/system/uploads
CMD
end
end
after "deploy:symlink","customs:symlink"
after "deploy", "deploy:cleanup"
I want to create a symlink after each deployment for the uploads directory, but I keep getting a failed error message because the non-public/system/uploads directory doesn't exist in the git repository in the first place.
I've verified this by taking a look at the repository, and the structure /non-public/system/uploads doesn't exist because I have that set in .gitignore to ignore it.
I've looked at the Git wiki and it doesn't track directories, so I must be missing something. How do other developers symlink the uploads directory with their server?
What I'll usually do on my cap deploys is to create the directories, by doing a basic
set :deploy_to, "/this/dir"
run "mkdir -p #{deploy_to}/then/more/dirs"
after "deploy:symlink"
namespace :deploy....
....
....
then provide the run code to do some symlinks either on an after or whatever. This probably not optimal for all situations, but for the simple stuff it usually gets the job done.
I've an issue at the moment where we are running a CMS within a site
(browsercms) that lets the user upload files. However, every time I
do a deploy Capistrano runs a hard reset thus nuking any uploaded
files.
Does anyone have any suggestions as to how to prevent the hard reset,
and just do a pull, or a way of moving the uploaded files elsewhere,
without having to change the application code?
This might not be the right approach.
You should include your 'images' folder in your .gitignore and symlink the $current_release/images folder to $shared/images.
This may be done automatically on every deployment if you put in your deploy.rb:
task :link_imgs do
run "ln -s #{shared_path}/photos #{release_path}/photos"
end
after "deploy:update_code", :link_imgs
I've done the same with my CMS and it works like a charm
This doesn't quite meet your criteria of "without having to change the application code".
However after running into a similar issue I shifted my uploaded image from /public/images to /public/system/images the /public/system directory is not 'versioned' by each capistrano deployment so the images survive.
Could it be the capistrano 'versioning' causing the problem (instead of a git reset)?
cap deploy calls deploy:update and deploy:restart
deploy:update makes the versioning, copying stuff
deploy:restart does the true restart, overload it at your convenince, usually in your config/deploy.rb file
namespace :deploy do
desc "Softly restart the server"
task :restart, :roles => :app, :except => { :no_release => true } do
my_own.restart_recipe
end
end
I want to protect my database.yml file by keeping it out of version control. Thus, I have two tasks in my Capistrano deploy recipe:
task :copy_db_config do
# copy local config file if it exists and is more
# recent than the remote one
end
task :symlink_db_config do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
Can you help fill in the first task?
I don't have functioning code for you here and now but..
you can the the local timestamp by using ruby. File class has a function ctime which let's You know when it was changed.
Run the same command on the servers database.yml
If the local one is newest, capistrano has a method for secure upload
upload("products.txt", "/home/medined", :via => :scp)
I had the same problem, but I approached it differently. Maybe it will be helpful.
The setup task copies database.yml.example to database.yml. The deploy task does not touch database.yml. I have separate tasks for changing the database names, usernames, and passwords. Here's an example:
desc "Change the database name"
task :change_db_database, :roles => :app do
database = prompt('Enter new database name: ')
run <<-CMD
cd #{shared_path}/config &&
perl -i -pe '$env = $1 if /^(\\w+)/; s/database:.*/database: #{database}/ if $env eq "#{ENV['CONNECTION'] || ENV['TARGET']}"' database.yml
CMD
end
I run these after setup but before the first deploy on new boxes. Then any time after that when I need to change database parameters, I use these tasks instead of copying in a new file.