Why are Moonshine/Capistrano having SFTP trouble during deploy:setup? - ruby-on-rails

I'm having trouble setting up a new server using Moonshine and Capistrano. It seems to get started pretty well, installs a bunch of Ubuntu packages, compiles REE, installs some gems, but then it fails to upload a file via SFTP with this output:
* executing `moonshine:setup_directories'
* executing "mkdir /tmp/moonshine"
servers: ["myserver.tld"]
[myserver.tld] executing command
command finished
servers: ["myserver.tld"]
** sftp upload /Users/arussell/Sites/mysite/config/moonshine/production.yml -> /tmp/moonshine/production.yml
/Users/arussell/.rvm/gems/ree-1.8.7-2011.03/gems/capistrano-2.5.19/lib/capistrano/transfer.rb:196:in `normalize': undefined method `pos' for #<Pathname:0x10f3a6988> (NoMethodError)
from /Users/arussell/.rvm/gems/ree-1.8.7-2011.03/gems/capistrano-2.5.19/lib/capistrano/transfer.rb:104:in `prepare_transfers'
Googling that error isn't really turning much up, all I can figure out is that capistrano/transfer.rb is expecting something other than a PathName object on line 196, but I'm not sure what it's expecting, nor am I sure why it's being fed a PathName object.
Edit: Here is my deploy.rb:
set :stages, %w(staging production dev)
set :default_stage, "staging"
require 'capistrano/ext/multistage' rescue "YOU NEED TO INSTALL THE capistrano-ext GEM"
require 'fileutils'
if ENV['branch']
set :branch, ENV['branch']
end
set :deploy_via, :remote_cache
before "deploy:restart", "deploy:delete_cache"
namespace(:deploy) do
desc "delete cache"
task :delete_cache do
run "rm -rf /usr/local/shared/cache/"
end
task :null, :roles => :app do
run "date"
end
end
require './config/boot'
... and my deploy/production.rb:
server "myserver.tld", :app, :web, :db, :primary => true
set :rails_env, 'production'
Edit 2: I tried using SCP instead of SFTP, but that didn't go any better. I added this to my deploy/production.rb:
upload "local", "remote", :via => :scp
download "remote", "local", :via => :scp
and got this error instead while trying to deploy:
upload via scp failed on myserver.tld: SCP did not finish successfully () (SCP did not finish successfully ())

I can't figure that error out either. It appears the version of Capistrano your using is fairly outdated by a year plus. I would update the version your using to a more recent release, and try again.
If that still doesn't resolve your problem it would help if you provided sanitized copy of your deploy.rb configuration.

Turns out that this was due to Moonshine not being able to handle the presence of deploy-stage-specific files (eg config/moonshine/production.yml) during cap production deploy:setup.
Here's how I got around it:
Remove config/moonshine/production.yml (replace production with whatever your deploy stage is called)
Run cap production deploy:setup
Put config/moonshine/production.yml back
Then run cap production deploy

Related

Capistrano 3 pulling command line arguments

I'm in the process of upgrading from Capistrano 2 to Capistrano 3. In Cap 2 I was using the following to take a command line argument as the branch name (otherwise default to master)
set :branch, fetch(:branch, "master")
If I called cap deploy it would deploy the master branch. But it also let me do something like this:
cap deploy -S branch=foo
Which would deploy the foo branch.
Now, in Capistrano 3, if I try to run the above I get an error: invalid option: -S.
What's the proper way to pass an argument via the command line now?
What I ended up doing was setting an ENV variable.
So now I can call
cap production deploy branch=mybranch
And it will deploy mybranch. If I run a simple cap production deploy it will deploy the default branch (master if you don't set one, but I've changed mine below to default to demonstrate)
This is the code I put in my deploy.rb file:
set :branch, "default"
if ENV['branch']
set :branch, ENV['branch']
end
Rake tasks (which cap is using) are supporting arguments.
namespace :test do
desc "Test task"
task :test, :arg1 do |t, args|
arg1 = args[:arg1]
puts arg1
end
end
cap -T outputs:
cap yiic:test[arg1] # Test task
Example of invocation:
cap production yiic:test[test1]
Also, here is a helpful post
P.S.: you should use env vars for "global" settings. Like common values for multiple tasks.
To give an updated and working solution for Capistrano 3 (as it took me a while to find and too many tests to make it works).
My files are like:
config/
deploy/
staging.rb
production.rb
deploy.rb
...
Capfile
In staging.rb I have:
server 'staging', roles: %w(db)
set :branch, ENV.fetch('REVISION', 'master')
set :use_sudo, false
set :user, 'toto'
set :deploy_to, '/var/www'
(In server 'staging', staging is a SSH connexion, defined in my .ssh/config)
Then, to deploy a specific revision, I just need to call:
cap staging deploy REVISION=3b2d9ab
Where 3b2d9ab is the Git commit hash (short or long version).

Rails Capistrano Deployment

for the first time I'm trying to deploy a rails app not to Heroku but to DigitalOcean, mainly because of the price. I'm completely new to Capistrano as well as VPS deployment and I'm totally lost. I've created the 1-click-Rails-droplet and followed this tutorial:
http://guides.beanstalkapp.com/deployments/deploy-with-capistrano.html
This are the settings in my deploy.rb file:
require 'capistrano/ext/multistage'
set :stages, ["staging", "production"]
set :default_stage, "staging"
set :application, "myAppName"
set :scm, :git
set :repository, "myGitRepository"
set :use_sudo, :false
set :deploy_via, :remote_cache
set :scm_passphrase, "myPassword"
set :user, "root"
role :web, "xx.xxx.x.xxx"
role :app, "xx.xxx.x.xxx"
The staging.rb file:
server "xx.xxx.x.xxx", :app, :web, :db, :primary => true
set :deploy_to, "/var/www/xx.xxx.x.xxx_staging"
And the production.rb file
server "xx.xxx.x.xxx", :app, :web, :db, :primary => true
set :deploy_to, "/var/www/xx.xxx.x.xxx"
Now, when I run
cap deploy:check
in the terminal I get the following:
[xx.xxx.x.xxx] executing command
xx.xxx.x.xxx: env:
xx.xxx.x.xxx: sh
xx.xxx.x.xxx: : No such file or directory
xx.xxx.x.xxx:
command finished in 88ms
* executing "test -w /var/www/xx.xxx.x.xxx_staging"
servers: ["xx.xxx.x.xxx"]
[xx.xxx.x.xxx] executing command
xx.xxx.x.xxx: env:
xx.xxx.x.xxx: sh
xx.xxx.x.xxx: : No such file or directory
xx.xxx.x.xxx:
command finished in 79ms
* executing "test -w /var/www/xx.xxx.x.xxx_staging/releases"
servers: ["xx.xxx.x.xxx"]
[xx.xxx.x.xxx] executing command
xx.xxx.x.xxx: env:
xx.xxx.x.xxx: sh
xx.xxx.x.xxx: : No such file or directory
xx.xxx.x.xxx:
command finished in 72ms
* executing "which git"
servers: ["xx.xxx.x.xxx"]
[xx.xxx.x.xxx] executing command
xx.xxx.x.xxx: env:
xx.xxx.x.xxx: sh
xx.xxx.x.xxx: : No such file or directory
xx.xxx.x.xxx:
command finished in 85ms
* executing "test -w /var/www/xx.xxx.x.xxx_staging/shared"
servers: ["xx.xxx.x.xxx"]
[xx.xxx.x.xxx] executing command
xx.xxx.x.xxx: env:
xx.xxx.x.xxx: sh
xx.xxx.x.xxx: : No such file or directory
xx.xxx.x.xxx:
command finished in 81ms
The following dependencies failed. Please check them and try again:
--> `/var/www/xx.xxx.x.xxx_staging/releases' does not exist. Please run `cap staging deploy:setup'. (xx.xxx.x.xxx)
--> You do not have permissions to write to `/var/www/xx.xxx.x.xxx_staging'. (xx.xxx.x.xxx)
--> You do not have permissions to write to `/var/www/3xx.xxx.x.xxx_staging/releases'. (xx.xxx.x.xxx)
--> `git' could not be found in the path (xx.xxx.x.xxx)
--> `/var/www/xx.xxx.x.xxx_staging/shared' is not writable (xx.xxx.x.xxx)
I've googled for a long time now but can't fix this. As I'm totally new to this and feel like there is a huge gap between learning to create a rails app and knowing all the things about deploying them (btw: what happened to ftp upload from earlier days?), I really hope someone knows how to fix this and could guide me into a direction to a not so steep learning curve for deployment. By the way: are there "easier" ways to do what I'm trying to do? Thank you very much!
Edit: One more question: Do I really need to deploy the app at github on the way to the server?
require "bundler/capistrano"
server "XXX.XX.XXX.XXX", :web, :app, :db, primary: true
This is just informing Capistrano which server you want to be accessing. For now since you have only one server it will be acting as a web, app and db server. The web server is your nginx + unicorn. App server is your rails application and db is your database server. The primary true indicates that this is your primary database server once you expand to more database servers. These are called roles you can define more but these are the main ones that are required. You can specify some tasks to work on some roles and not others, but that's all when you have more than 1 server.
set :application, "applicationName"
set :user, "deployer"
set :deploy_to, "/home/#{user}/apps/#{application}"
set :deploy_via, :remote_cache
set :use_sudo, false
set :scm, :git
set :repository, "GIT REPO URL"
set :branch, "master"
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
These just set up some variables for Capistrano to use. Your application name, the user that you will be deploying as (don't use root create another user), where you want to deploy, whether to use sudo when running commands (Ryan says sometimes he encounters permission errors if sudo is used). Then the source code management system as git / subversion, and a link to your repository and the branch with which you want to deploy to.
The next 2 options If I recall were to handle some things with the ssh keys.
So when it comes to thinking of how Capistrano works think of exactly how a Rakefile and Rake tasks work.
after "deploy", "deploy:cleanup"
if you see this kind of statement after "XXX", "YYY", it's just saying after task XXX is done do YYY. So in this case once task deploy is done, do deploy:cleanup.
namespace :deploy do
%w[start,stop,restart].each do |command|
desc "#{command} unicorn server"
task command, roles: :app, except: {no_release: true} do
run "/etc/init.d/unicorn_#{application} #{command}"
end
end
This task is just creating tasks to be able to stop start and restart the unicorn server. Therefore this task can be used in conjunction later as soon as the site is deployed to restart the unicorn server.
task :setup_config, roles: :app do
sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}"
sudo "ln -nfs #{current_path}/config/unicorn_init.sh /etc/init.d/unicorn_#{application}"
run "mkdir -p #{shared_path}/config"
put File.read("config/database.example.yml"), "#{shared_path}/config/database.yml"
puts "Now edit the config files in #{shared_path}."
end
after "deploy:setup", "deploy:setup_config"
task :symlink_config, roles: :app do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
after "deploy:finalize_update", "deploy:symlink_config"
So this is a very complex looking task, but it's actually not doing much. Since in the railscasts Ryan was not putting his database.yml file in git (with production values), he just created a template database.example.yml file which is being put in folder apps/APPNAME/shared/ you have to manually go and edit it. These shared configurations are being symlinked to the current folder.
In the other files nginx.conf unicorn.rb and unicorn_init.sh you'd want to edit the paths to point to correct path.
Additional Resources
Also take a look at the Railscasts Capistrano Recipes where he expands on the details of his recipes and makes them more DRY. The Capistrano Wiki also has a great resource called from the beginning. In addition Nginx & Unicorn covers more on those 2 things. I'd also suggest reading Github's blog post on Unicorn and this Nginx primer they were help me clear up some other doubts I had.
But most of all you don't worry if you get errors just try breaking it down 1 error at a time and good luck.

How to deploy licensed fonts that can't go into version-control with Capistrano?

I am using Capistrano to deploy my Rails application to a VPS (as shown in episode 335 on railscasts.com). I have some custom fonts I'm using for the application and don't want to check them into source-control for licensing reasons (See clarification at bottom).
What's the best way to go about this? Should I edit the deploy.rb file to sftp the assets/webfonts directory from my local computer? Maybe I just need to copy them manually to the my_app/shared/assets directory on the VPS, but I'd rather it be automated as part of the deploy task.
Here's my current deploy.rb file:
require "rvm/capistrano"
require "bundler/capistrano"
server "ip_address", :web, :app, :db, primary: true
set :application, "armory"
set :user, "username"
set :deploy_to, "/home/#{user}/apps/#{application}"
set :deploy_via, :remote_cache
set :use_sudo, false
set :scm, "git"
set :github_user, "gorrillamcd"
set :repository, "git#github.com:#{github_user}/Armory.git"
set :branch, "master"
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
after "deploy", "deploy:cleanup" # keep only the last 5 releases
namespace :deploy do
%w[start stop restart].each do |command|
desc "#{command} unicorn server"
task command, roles: :app, except: {no_release: true} do
run "/etc/init.d/unicorn_#{application} #{command}"
end
end
task :setup_config, roles: :app do
sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}"
sudo "ln -nfs #{current_path}/config/unicorn_init.sh /etc/init.d/unicorn_#{application}"
run "mkdir -p #{shared_path}/config"
put File.read("config/database.base.yml"), "#{shared_path}/config/database.yml"
puts "Now edit the config files in #{shared_path}."
end
after "deploy:setup", "deploy:setup_config"
task :symlink_config, roles: :app do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
run "ln -nfs #{shared_path}/config/initializers/stripe.rb #{release_path}/config/initializers/stripe.rb"
end
after "deploy:finalize_update", "deploy:symlink_config"
desc "Make sure local git is in sync with remote."
task :check_revision, roles: :web do
unless `git rev-parse HEAD` == `git rev-parse origin/master`
puts "WARNING: HEAD is not the same as origin/master"
puts "Run `git push` to sync changes."
exit
end
end
before "deploy", "deploy:check_revision"
end
Edit: Sorry for being so vague beforehand. I'm using Museo Slab from myfonts.com and a public repo on github (check my user profile if you want to see it). I read through the license and found this:
3. The Licensed Webfont(s) may be used on any Website owned or controlled by the Licensee
4. Agencies responsible for multiple clients’ Websites, for example web design agencies or hosting providers, may not share a single Webfont license across multiple clients’ Websites.
Those two lines of the license make me believe that checking the font into a public repository would be against the license, since it could be used on sites that are not mine without obtaining a new license for the font (even though they were free to begin with). I imagine that other people have had this problem before. So my question is, What's the normal/best way to handle deploy, with Capistrano, fonts (or any file for that matter) that can't be checked into source control?
I would pack the web fonts in an archive and put that archive somewhere separate from the repository. (Amazon S3 is a prime candidate.) Then, I'd have the release process retrieve and unpack this archive at deploy time.
This lets you put your entire app in your public repository -- the Capistrano scripts, the Rake tasks, etc. -- but leaves the actual font binaries out, with their location specified as a matter of configuration. This is consistent with 12-factor app principles, treating these webfonts as an external resource needed by but not contained within your application.
You could, for example, specify a WEBFONTS_URL environment variable, and add a fetch_webfonts Rake task. This task would automatically pull these resources into your application, and would do nothing in the case that WEBFONTS_URL is unspecified -- e.g. if someone else did a checkout of your repo without having these fonts. (You could even make the task do appropriate things with stylesheets, ensuring that the fresh-checkout users get a working app without 404ing on font files.) Rake allows you to add dependencies to existing tasks, so you can ensure this happens automatically as part of assets:precompile, which Capistrano very likely already invokes.
Additionally, this approach works equally well on development and production: you can take a fresh checkout of your own repo, specify the appropriate WEBFONTS_URL, and end up with a working set of fonts on your local machine. (The dotenv gem makes it easy to get development configuration into environment variables, keeping all your environments consistent.) Just be sure that you .gitignore the results so you don't accidentally make them public after all.
You could upload/synchronize the fonts directory using rsync. For example:
Add your IP/domain to a separate variable:
set :host, "ip_address"
server host, :web, :app, :db, primary: true
And add a task to run
`rsync -vz app/assets/webfonts #{user}##{host}:#{shared_path}/assets/webfonts`
Then symlink it into the current version of your application like is done already in the deploy script with database.yml and stripe.rb

newbie capistrano rails deployment problem (can't find git in the path)

I'm using: Rails 3, ruby 1.9.2 and trying to deploy using capistrano. When I run cap deploy:check, capistrano tells me that it can't find git on my deployment server (see below).
Any thoughts on what I'm doing wrong??
Here's my setup.
I have a git repo # github
I have a
laptop with an updated local copy of
the github repo
I have a local
"production" server (192.168.0.103) where the
production app should be deployed
I'm running all commands from the local repo on my laptop (not the production server)
If I run cap deploy:setup, my deploy.rb file successfully adds the "releases" and "shared" directories on my production server (aka 192.168.0.103).
If I run the cap deploy:check command, it fails with the error message of
`git' could not be found in the path (192.168.0.103).
What is strange (to me at least) is that git is definitely installed on 192.168.0.103 and the command that's used to see if git is there (which git) works when I ssh into 192.168.0.103.
So, obviously I'm doing something wrong (maybe in the deploy.rb file?)
Here's a sanitized version of the deploy.rb file
default_run_options[:pty] = true
set :application, "myapp"
set :repository, "git#github.com:xxxxxxx/myapp.git"
set :user, "abcde" #username that's used to ssh into 192.168.0.103
set :scm, :git
set :scm_passphrase, "xxxxxxxx"
set :branch, "master"
set :deploy_via, :remote_cache
set :deploy_to, "/Users/abcde/www"
role :web, "192.168.0.103"
role :app, "192.168.0.103"
Here's the output of cap deploy:check
* executing `deploy:check'
* executing "test -d /Users/abcde/www/releases"
servers: ["192.168.0.103"]
Password:
[192.168.0.103] executing command
command finished
* executing "test -w /Users/abcde/www"
servers: ["192.168.0.103"]
[192.168.0.103] executing command
command finished
* executing "test -w /Users/abcde/www/releases"
servers: ["192.168.0.103"]
[192.168.0.103] executing command
command finished
* executing "which git"
servers: ["192.168.0.103"]
[192.168.0.103] executing command
command finished
The following dependencies failed. Please check them and try again:
--> `git' could not be found in the path (192.168.0.103)
Okay, I think I figured it out.
I was basically having the same problem as described here: http://groups.google.com/group/capistrano/browse_thread/thread/50af1daed0b7a393
Here's a choice excerpt:
I try to deploy an application on a
shared environment on which I
installed git. I have added the path
to bashrc, but this would work only
in an interactive bash. When cap is
logging in, it will not be running
bash. If I run deploy:check it fails
by
--> `git' could not be found in the path (example.com) If i set
:scm_command, "/home/user/opt/bin/git"
the problem is solved with the
deploy:check command, but when I run
deploy:cold, it fails because it
tries to run /home/user/opt/bin/git
locally and I can't even put git in
there, because I use windows on my pc.
adding :scm_command, "path/to/my/git" fixed the issue, although I'm not 100% that this is the correct approach to take.
I would recommend using:
default_run_options[:env] = {'PATH' => '/home/user/opt/bin/git:$PATH'}
This will allow adjusting the PATH system environment variable (and of them more if needed) so that not only the "Capistrano can't find the SCM" problem get solved bu any other similar problems with Capistrano not running in interactive bash (not executing the .bashrc etc.).

Capistrano and Git, Ruining my life. "Unable to resolve revision for [HEAD] on repository ..."

I searched all of the relevant Capistrano issues, but couldn't find something that even elucidated anything here for me.
git version 1.6.4.2
Capistrano v2.5.10
Basically, when I run my cap deploy.rb script, it connects to the server, starts executing the deploy:update task, then in the deploy:update_code task:
*** [deploy:update_code] rolling back
* executing "rm -rf /home/user_name/public_html/project_name/releases/20091223094358; true"
servers: ["project_name.com"]
It fails with the following error:
/Library/Ruby/Gems/1.8/gems/capistrano-2.5.10/lib/capistrano/recipes/deploy/scm/git.rb:231:in `query_revision': Unable to resolve revision for 'master' on repository 'ssh://git#slice_ip:path_to_git_repository'. (RuntimeError)
Here's my deploy script, I've tried including and omitting:
set :branch 'master'
I also just thought my path to the repository was off, but i've tried just about every permutation (absolute, not absolute, .git suffix, no suffix). There's definitely a bare git repository at the path i'm pointing to.
**I do have multiple projects being hosted on one slice. The other projects is also a rails project, but is running SVN. Capistrano deployments work fine.
Any pointers in the right direction or any ideas would help reduce the amount of drinking I am planning on doing if I can't figure this out. (Paths / IPs obfuscated, dont hack me bro!)
set :application, "project1"
set :user, "username"
set :repository, "ssh://git#67.24.9.133/home/git/project1.git"
set :branch, "master"
set :port, 696969
set :deploy_to, "/home/username/public_html/#{application}"
set :scm, :git
role :app, application
role :web, application
role :db, application, :primary => true
# deployment via remote client (workstation)
set :deploy_via, :copy
set :runner, user
# mod_rails
namespace :deploy do
desc "Restarting mod_rails with restart.txt"
task :restart, :roles => :app, :except => { :no_release => true } do
run "touch #{current_path}/tmp/restart.txt"
end
[:start, :stop].each do |t|
desc "#{t} task is a no-op with mod_rails"
task t, :roles => :app do ; end
end
end
This was the most relevant post (extremely relevant even), but I couldn't really figure out what they were saying the fix is. I'm pretty new with git / capistrano configs.
https://capistrano.lighthouseapp.com/projects/8716/tickets/56-query_revision-unable-to-resolve-revision-for-head-on-repository
Ok I seemed to have fixed it.
Basically, since I have 2 separate repositories on the remote server, I think the "git" user was failing because I hadn't registered an ssh keypair for the git user. That explains why one of my deploy.rb scripts was working properly, while this one wasn't.
In the link I posted in the question, one of the commenters pointed out the issue:
https://capistrano.lighthouseapp.com/projects/8716/tickets/56-query%5Frevision-unable-to-resolve-revision-for-head-on-repository
Note this error is also displayed if
you are using multiple github keys per
http://capistrano.lighthouseapp....
and you do not have these keys and a
corresponding entry in your
.ssh/config on the workstation you're
running the deploy from. so the
ls-remote is run locally. is there a
way to reference the repository at
github.com for this request while the
remote deploy uses
git#github-project1:user/project1.git
Also, see the following link for more details, since the whole ssh issue would apply even if you're not using github.
http://github.com/guides/multiple-github-accounts
Both your workstation and your server must be able to reach the repository at the address specified, if not then you may have to set :local_repository to how you access it from your workstaion, and :repository to be how your servers should access it.
For me Capistrano deployments with Git only seem to work when setting set :copy_cache, true
I've only used capistrano with git once, but never used or seen the use of ssh:// in the repository definition.
Try using set :repository, "git#67.24.9.133/home/git/project1.git" instead
Make sure the branch you are deploying from exists.
set :branch, "upgrade-to-2013.4.3"
is not equal to
set :branch, "upgrade-to-2013.3.4"

Resources