Search code examples
ruby-on-railscapistrano

Checking directory existence in Capistrano task fails


I've added new HDD to the server and need to use it to save all users info, so I need to move public directory to new HDD.

I don't know what is the best approach in my case, but I decided to change the public directory to be symbolic link pointing to new HDD path.

Based on that I created the below capistrano task to run after deploy:

  # I'm using capistrano 3.1
  namespace :public_to_symbolic do
    desc 'Change public directory to symbolic link pointing to other Hdd'
    task :change do
      on roles(:app) do
        is_directory = File.directory?("#{release_path}/public")
        is_symbolic_link = File.symlink?("#{release_path}/public")
        is_new_directory_exist = File.directory?('/mnt/newhdd/public')
        can_change = is_directory && !is_symbolic_link && is_new_directory_exist
        puts "is_directory : #{is_directory}" # prints false
        puts "is_symbolic_link : #{is_symbolic_link}" # prints false
        puts "is_new_directory_exist : #{is_new_directory_exist}" # prints false
        puts "can_change: #{can_change}" # prints false
        puts "release_path: #{release_path}" # prints /var/www/myapp/releases/20180305112922
        if can_change
          puts 'Changing public directory to symbolic link'
          execute "mv #{release_path}/public #{release_path}/public_linked"
          execute "ln -s /mnt/newhdd/public #{release_path}/public"
          execute "rm -rf #{release_path}/public_linked"
        end
      end
    end
  end

  after 'deploy', 'public_to_symbolic:change'

So, as commented, is_directory, is_symbolic_link and is_new_directory_exist are all returns false, but when I'm doing the same check (i.e File.directory?("#{Rails.root}/public") or File.directory?("/var/www/myapp/current/public")) using Rails console on deployment server, I'm getting true and I'm able to see the public directory!

To avoid this issue I tried also to use current_path instead of release_path but still same results.

I have two questions:

  1. Why is_directory and is_new_directory_exist are always false while task is running?
  2. If there is any better approach to use public directory on different Hdd, please advice.

All suggestions are welcome


Solution

  • All Ruby methods that you use in your Capistrano tasks run on your local machine.

    For example:

    • File.directory?
    • File.symlink?

    These are always evaluated on your local filesystem. Capistrano never runs Ruby code on the remote server. These methods always return false for you because they are trying to find e.g. "#{release_path}/public" on your local computer, which of course does not exist.

    To run code on the server, the tools available to you are Capistrano's test and execute methods. These take in a command string that is executed remotely via SSH.

    If you want to test if a remote path is a directory, you cannot use Ruby; you have to use something that can be run in a remote shell. Here is one way to test if a path is a directory, for example:

    is_directory = test("[ -d #{release_path}/public ]")
    

    Likewise, to test if a path is a symlink:

    is_symbolic_link = test("[ -h #{release_path}/public ]")