Sign in through GitHub

Please read for an updated status on RailsCasts:

Learn more or hide this

adam-pl's Profile

GitHub User: adam-pl

Comments by

Avatar

SSH Timeouts - avoid ssh disconnection with Capistrano:

1) Add file config/recipes/ssh.rb

ruby
load "config/recipes/base"

namespace :ssh do
  desc "Setup long timeouts for ssh connection"
  task :install, roles: :app do
    sshd = <<-BASHRC
  ClientAliveInterval 60
  ClientAliveCountMax 1200
    BASHRC
    cmd = %Q{grep -R "ClientAliveInterval" /etc/ssh/sshd_config}
    content = capture( %Q{bash -c '#{cmd}' || echo "false"}).strip
    if content == 'false'
      put sshd, '/tmp/sshd'
      run 'cat /etc/ssh/sshd_config /tmp/sshd > /tmp/sshd.tmp'
      run 'rm /tmp/sshd'
      run "#{sudo} mv /tmp/sshd.tmp /etc/ssh/sshd_config"
    else
      run 'echo "FILE /etc/ssh/sshd_config" IS ALREADY UPDATED!'
    end
  end
  after "deploy:install", "ssh:install"
end

2) Edit config/deploy.rb file and add:

ruby
load "config/recipes/ssh"

It works when you call:

terminal
cap deploy:install

or

terminal
cap ssh:install

NOTE 1 - you can call cap ssh:install many times with no worries that file /etc/ssh/sshd_config includes string ClientAliveInterval 60 many times.
It's safe because following code:

ruby
    cmd = %Q{grep -R "ClientAliveInterval" /etc/ssh/sshd_config}
    content = capture( %Q{bash -c '#{cmd}' || echo "false"}).strip
    if content == 'false'
      # Here we know that we must do setup
    else
      # Here we know that setup is already done
    end

NOTE 2 - Additionally I've made the same kind of protection in file config/recipes/rbenv.erb. So now I can call cap deploy:install many times (well, it's not recommended but sometimes it's usefull if you tests deploying process many times).

Avatar

Today I had a big problem with deploying on remote machine. Many hours spent on problem with hanging Capitrano.
When I did cap deploy:install all required packages were installed properly except one - ruby 1.9.3-p327.

Capistrano hangs forever on executing rbenv install 1.9.3-p327 with message Installing ruby-1.9.3-p327....

I've used second ssh connection with top running for checking numer of users logged in. I've detected that message Installing ruby-1.9.3-p327... still exists after number of logged in users decrease from 2 into 1.

What is the reason? SSH timeout session breaks connection.

How to solve the problem? My solution is:
1) Just edit file /etc/ssh/sshd_config and add following lines:

config
  ClientAliveInterval 18
  ClientAliveCountMax 100

Parameter ClientAliveInterval should have very small number to make pinging very often.
18*100 = 1800 seconds means 30 minutes of session timeout (enough I think).
2) Then restart ssh service:

terminal
sudo service ssh restart

3) Try to deploy:

terminal
cap deploy:install

It works now for me :-)

If you not, additionally try to edit file /etc/ssh/ssh_config:

settings
  ServerAliveInterval 18
  ServerAliveCountMax 100

Then restart ssh service.
I hope it will be helpfull for somebody.

Avatar

This code repeats 3 times. I've made press_enter method:

ruby
def press_enter( ch, stream, data)
  if data =~ /Press.\[ENTER\].to.continue/
    # prompt, and then send the response to the remote process
    ch.send_data( "\n")
  else
    # use the default handler for all other text
    Capistrano::Configuration.default_io_proc.call( ch, stream, data)
  end
end

I don't like to press Enter every time, so I've used ch.send_data( "\n") code.

Then you can use it like that:

ruby
run "#{sudo} add-apt-repository ppa:pitti/postgresql", pty: true do |ch, stream, data|
  press_enter( ch, stream, data)
end
Avatar

Hi Mark,

Thank your for your info!

I'm not sure if I understand correctly.
Can you give me an example how it works and how it should work?

In the meantime I'll give you an idea how to make www. subdomain by default. Let's suppose:
1. First you open page that has url - for example <a href="http://mark.lvh.me:3000/">Show Mark</a>). You click it and new page opens.
2. Then you click link http://www.lvh.me:3000/adam (page has full url path - <a href="http://www.lvh.me:3000/adam">Show Adam</a>)
3. New page opens and it has only paths for example <a href="/adam">Show Adam</a>. It doen't have html code like <a href="http://lvh.me:3000/adam">Show Adam</a> - I guess you gets full url in this point.

How I did it?
1. added line before_filter :check_url_for_www
2. defined method check_url_for_www
It looks like that:

ruby
  def check_url_for_www
    redirect_to request.protocol + "www." + request.host_with_port + request.fullpath 
      if !/^www/i.match(request.host) 
      and !DomainFormatValidator::check_numeric_domain(request.host)
      and allowed_subdomains?
      and !Rails.env.test?
end

There is used DomainFormatValidator::check_numeric_domain method in the :check_url_for_www:

ruby
def self.check_numeric_domain( host)
  /^(\d{1,3}\.){3}(\d{1,3})$/.match( host)
end

and allowed_subdomains? ApplicationHelper's method:

ruby
def allowed_subdomains?
  !request.domain.blank?
end

The reason is you can use numeric addresing like 127.0.0.1:3000 for opening your page. In this case we cannot add www. subdomain.
Besides we chec if domain is blank. If true the we do nothing.

It works fine on my local, development environment. I've never tested it in the poduction environment, but I'm going to do that very soon :)

I hope it is clear. If not let me know :)

Avatar

I've also had the same problem.

The reason is unicorn_init.sh file doesn't have execute flag on server site.
To do that let's add following line into deploy.rb at :symlink_config task section:

ruby
sudo "chmod +x #{release_path}/config/unicorn_init.sh"

Finally :symlink_config task's code is:

ruby
  task :symlink_config, roles: :app do
    run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
    run "chmod +x #{release_path}/config/unicorn_init.sh"
  end

You do not have replace any run into sudo.

For me it works fine.

Avatar

Hi all!

Nice screencast but I don't like:
1. Using lambda in the routes.rb file
2. Problem with adding subdomain: false in every routing that I want to clean urls from subdomain
3. Problem with changing every link_to with _path to _url also for cleaning urls (many hours of work in large project).

My solutions:
ad. 1. Instead of using the lambda I can use smart regular expression:

ruby
match '/' => 'blogs#show', constraints: { subdomain: /^(?!www$)(.+)$/i }

Regular expression /^(?!www$)(.+)$/i doesn't allow to handle main domain with www. Really nice, isn't?

ad. 2. I prefer to add following line in development.rb and production.rb files:

ruby
config.action_controller.default_url_options = { subdomain: false }

Now using subdomain is disabled by default. I don't need to add subdomain: false in many lines in routes.rb file... ufff.

ad. 3. I prefer to create file url_helper.rb with a few lines of code:

ruby
module UrlHelper
  def url_for(options = nil)
    if request.subdomain.present? 
    and request.subdomain.downcase != 'www'
    and !options.nil? and options.is_a?(Hash)
    and options.has_key? :only_path
    and options[:only_path]
      options[:only_path] = false
      puts "Changed options[:only_path] to true. options=#{options.inspect}" unless options.nil?
    end
    super
  end
end

Now I do not have to change thousands of links :-) ufff :-))

It works for me. Do you like it?

P.S. I'm using Rails 3.2