I am trying to perform a database backup as part of a Capistrano (v3) deployment script (for a NON-Rails app).
The script works fine -- if I hard-code database config into it.
Now I want to load in the database config from a .env file. On my local machine, my .env file (in the repo root next to the Capfile) reads as follows:
DB_NAME='local_name'
DB_USER='local_user'
DB_PASSWORD='local_pw'
DB_HOST='127.0.0.1'
On the server, the .env file (which Capistrano has placed in the shared folder & symlined to from the current folder) reads as follows:
DB_NAME='dev_name'
DB_USER='dev_user'
DB_PASSWORD='dev_pw'
DB_HOST='127.0.0.1'
However, when running cap deploy, I get the following:
INFO [292e2535] Running /usr/bin/env mysqldump -u local_user --password='local_pw' --databases local_name -h 127.0.0.1 | bzip2 -9 > /var/www/vhosts/xxxxx/backups/database_local_name_2014-05-29_22:52:07.sql.bz2 on <server>
I.e. it's using my local .env file, when actually I'd like it to load the .env file that is present on the server. I do not want all of my team to have to manage a separate .env.production file if at all possible!
The relevant portion of my script is as follows (using the Dotenv gem):
require 'dotenv'
Dotenv.load '.env'
username, password, database, host = ENV['DB_USER'], ENV['DB_PASSWORD'], ENV['DB_NAME'], ENV['DB_HOST']
Any help would be greatly appreciated!
You can use the Dotenv::Parser.call(string). I am using with Capistrano 2.14 (this is older version!)
desc <<-desc
ENV test
desc
task :test do
text = capture "cat #{shared_path}/.env"
ENV2 = Dotenv::Parser.call(text)
puts ENV2['DB_NAME']
end
Under Capistrano 3 I need fixed KrisztiƔn Ferenczi's answer
task :load_remote_environment do
on roles(:app) do
set :default_environment, Dotenv::Parser.call(capture("cat #{shared_path}/.env"))
end
end
after 'deploy:set_current_revision', 'load_remote_environment'
In the Capfile
require 'dotenv'
Related
I got some issue with the gem 'mina'. If I do set :user, 'username', he tries to connect to the server via Username#xxx.... wich is not working if the user is not existing. My PC is name Username. So mina setup and mina deploy are not working.
Does someone know a solution?.
Thanks
Best regards
Matze
EDIT:
Gemfile:
gem 'mina'
After that I run bundle install and mina init
deploy.rb:
require 'mina/rails'
require 'mina/git'
# require 'mina/rbenv' # for rbenv support. (https://rbenv.org)
require 'mina/rvm' # for rvm support. (https://rvm.io)
# Basic settings:
# domain - The hostname to SSH to.
# deploy_to - Path to deploy into.
# repository - Git repo to clone from. (needed by mina/git)
# branch - Branch name to deploy. (needed by mina/git)
set :user, "user"
set :application_name, 'appname'
set :domain, 'xx.xxx.xxx.xxx'
set :deploy_to, '/var/www/user/appname'
set :repository, 'user#xx.xxx.xxx.xxx:/home/user/git/appname.git'
set :branch, 'master'
# Optional settings:
# set :user, 'user' # Username in the server to SSH to.
# set :port, '30000' # SSH port number.
# set :forward_agent, true # SSH forward_agent.
# Shared dirs and files will be symlinked into the app-folder by the 'deploy:link_shared_paths' step.
# Some plugins already add folders to shared_dirs like `mina/rails` add `public/assets`, `vendor/bundle` and many more
# run `mina -d` to see all folders and files already included in `shared_dirs` and `shared_files`
# set :shared_dirs, fetch(:shared_dirs, []).push('public/assets')
set :shared_files, fetch(:shared_files, []).push('config/database.yml', 'config/secrets.yml')
# This task is the environment that is loaded for all remote run commands, such as
# `mina deploy` or `mina rake`.
task :remote_environment do
# If you're using rbenv, use this to load the rbenv environment.
# Be sure to commit your .ruby-version or .rbenv-version to your repository.
# invoke :'rbenv:load'
# For those using RVM, use this to load an RVM version#gemset.
# invoke :'rvm:use', 'ruby-1.9.3-p125#default'
end
# Put any custom commands you need to run at setup
# All paths in `shared_dirs` and `shared_paths` will be created on their own.
task :setup do
# command %{rbenv install 2.3.0 --skip-existing}
end
desc "Deploys the current version to the server."
task :deploy do
# uncomment this line to make sure you pushed your local branch to the remote origin
# invoke :'git:ensure_pushed'
deploy do
# Put things that will set up an empty directory into a fully set-up
# instance of your project.
invoke :'git:clone'
invoke :'deploy:link_shared_paths'
invoke :'bundle:install'
invoke :'rails:db_migrate'
invoke :'rails:assets_precompile'
invoke :'deploy:cleanup'
on :launch do
in_path(fetch(:current_path)) do
command %{mkdir -p tmp/}
command %{touch tmp/restart.txt}
end
end
end
# you can use `run :local` to run tasks on local machine before of after the deploy scripts
# run(:local){ say 'done' }
end
# For help in making your deploy script, see the Mina documentation:
#
# - https://github.com/mina-deploy/mina/tree/master/docs
set :execution_mode, :exec if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
When I run now mina setup he print that:
$ mina setup
User#xx.xxx.xxx.xxx's password:
SSH Auth key working fine and git working fine he just puts User instead of user before the ip, what is not working because the user just exists with small letter. But my working machine is named User.
Okay,
I'm sorry if the title is not descriptive enough, but allow me to explain what I want to achieve:
I have a Rails 3 application
During my deploy, it needs to call pg_dump with the correct parameters to restore a backup
The task needs to be ran after the deploy is done but before the migrations.
The problem I have however, is that for this task, I would like to access Rails specific code, which is not working as Capistrano keeps throwing a lot of errors at me like gems not available or module not defined.
This is my Rake task:
namespace :deploy do
namespace :rm do
desc 'Backup the database'
task :backup do
# Generates the command to invoke the Rails runner
# Used by the cfg method to execute the ActiveRecord configuration in the rails config.
def runner
dir = "#{fetch(:deploy_to)}/current"
bundler = "#{SSHKit.config.command_map.prefix[:bundle].first} bundle exec"
env = fetch(:rails_env)
"cd #{dir}; #{bundler} rails r -e #{env}"
end
def cfg(name)
env = fetch(:rails_env)
command = "\"puts ActiveRecord::Base.configurations['#{env}']['#{name}']\""
"#{runner} #{command}"
end
on roles(:db) do
timestamp = Time.now.strftime('%Y%m%d%H%M%S')
backups = File.expand_path(File.join(fetch(:deploy_to), '..', 'backups'))
execute :mkdir, '-p', backups
dump = "PGPASSWORD=`#{cfg('password')}` pg_dump -h `#{cfg'host')}` -U `#{cfg('username')}` `#{cfg('database')}`"
fn = "#{timestamp}_#{fetch(:stage)}.sql.gz"
path = File.join(backups, fn)
execute "#{dump} | gzip > #{path}"
end
end
end
end
In it's current form, it simply generates a string with the runner method and dumps that inside the cfg method.
I tried rewriting the runner method, but for some reason I keep getting the runner --help output from the remote server, but the command being generated in the output is correct, and works locally just fine.
We are using Ruby 2.2.2 and RVM on the remote server.
Is it even possible to do what we are trying to construct together?
I'd suggest writing a rake task inside your Rails app and invoking that from your Capistrano task. This is how the Capistrano rails tasks work.
within release_path do
with rails_env: fetch(:rails_env) do
execute :rake, "db:migrate"
end
end
To set config vars for a Heroku app, you do this:
$ heroku config:set GITHUB_USERNAME=joesmith
How would I set a config var with the contents of a file?
Take a look at the heroku-config plugin, which adds a heroku config:push command to push key-value pairs in a file named .env to the app.
It also has a heroku config:pull command to do the opposite and works very well with foreman for running the app locally with the config in .env.
https://github.com/xavdid/heroku-config
Example
heroku config:push --file=.env.production
I know this is too late but still it will be helpful for future users who land here.
I also wanted a quick solution to add variable to heroku app but copy-paste is so boring.. So wrote a script to read values from the .env file and set it at the requested app - all things passed as an option:
https://gist.github.com/md-farhan-memon/e90e30cc0d67d0a0cd7779d6adfe62d1
Usage
./bulk_add_heroku_config_variables.sh -f='/path/to/your/.environment/file' -s='bsc-server-name' -k='YOUR_CONFIG_KEY1 YOUR_CONFIG_KEY2'
A simple pure-python solution using honcho and invoke:
from honcho.environ import parse
from invoke import run
def push_env(file='.env'):
"""Push .env key/value pairs to heroku"""
with open(file, 'r') as f:
env = parse(f.read())
cmd = 'heroku config:set ' + ' '.join(
f'{key}={value}' for key, value in env.items())
run(cmd)
The idea here is that you will get the same configuration as if you ran the project locally using honcho. Then I use invoke to run this task easily from the command line (using #task and c.run) but I've adapted it here to stand alone.
I just started a new app and I was able to push it to Heroku, But I it seems, that I can't access the console.
The command, that I am running is:
heroku run console --app myappname
What I get, is:
Running `console` attached to terminal... up, run.3951 Usage: rails
new APP_PATH [options]
Options: -r, [--ruby=PATH] # Path to the Ruby binary of
your choice
# Default: /app/vendor/ruby-1.9.3/bin/ruby -b, [--builder=BUILDER] #
Path to a application builder (can be a filesystem path or URL) -m,
[--template=TEMPLATE] # Path to an application template (can be a
filesystem path or URL)
[--skip-gemfile] # Don't create a Gemfile
[--skip-bundle] # Don't run bundle install -G, [--skip-git] # Skip Git ignores and keeps -O,
[--skip-active-record] # Skip Active Record files -S,
[--skip-sprockets] # Skip Sprockets files -d,
[--database=DATABASE] # Preconfigure for selected database
(options:
mysql/oracle/postgresql/sqlite3/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)
# Default: sqlite3 -j, [--javascript=JAVASCRIPT] # Preconfigure for selected JavaScript
library
# Default: jquery -J, [--skip-javascript] # Skip JavaScript files
[--dev] # Setup the application with Gemfile pointing to your Rails checkout
[--edge] # Setup the application with Gemfile pointing to Rails repository -T, [--skip-test-unit] # Skip
Test::Unit files
[--old-style-hash] # Force using old style hash (:foo = 'bar') on Ruby >= 1.9
Runtime options: -f, [--force] # Overwrite files that already
exist -p, [--pretend] # Run but do not make any changes -q,
[--quiet] # Suppress status output -s, [--skip] # Skip files
that already exist
Rails options: -h, [--help] # Show this help message and quit
-v, [--version] # Show Rails version number and quit
Description:
The 'rails new' command creates a new Rails application with a default
directory structure and configuration at the path you specify.
You can specify extra command-line arguments to be used every time
'rails new' runs in the .railsrc configuration file in your home directory.
Note that the arguments specified in the .railsrc file don't affect the
defaults values shown above in this help message.
Example:
rails new ~/Code/Ruby/weblog
This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
See the README in the newly created application to get going.
I know, that the application name is correct, as I just pushed it and it is loaded.
When I look at the logs on Heroku for the moment, when I tried to hit the console, I see following:
2013-07-01T16:21:58.780979+00:00 heroku[api]: Starting process with command `bundle exec rails console` by mzaragoza#myemail.com
2013-07-01T16:22:09.000482+00:00 heroku[run.2993]: Awaiting client
2013-07-01T16:22:09.055474+00:00 heroku[run.2993]: Starting process with command `bundle exec rails console`
2013-07-01T16:22:10.342966+00:00 heroku[run.2993]: State changed from starting to up
2013-07-01T16:22:13.870963+00:00 heroku[run.2993]: Process exited with status 0
2013-07-01T16:22:13.889703+00:00 heroku[run.2993]: State changed from up to complete
What about heroku run rails c? Does it make any difference if you add rails?
PS: I'm unsure if you want to access Rails' console or just a normal shell, from the comments.
The correct form is => heroku run "any rails command here"
I had this problem when I upgraded to Rails > 4.0.0. The solution is to run locally the following command rake rails:update:bin. This will generate a bin directory in the root of your application. Make sure that it is not in your .gitignore file. Commit and then push the changes to Heroku.
For 3.2.x apps:
This also just happened to me when I removed script/rails from my repo and pushed to Heroku. Reverting the commit and pushing that change made things work again.
I have rake tasks for getting the production database from the remote server, etc. It's always the same tasks but the server info changes per project. I have the code here: https://gist.github.com/868423 In the last task, I'm getting a #local_db_dir_path = nil error.
I don't think want to use shell environment variables because I don't want to set them up each time I use rake or open a new shell.
Stick the settings in a YAML file, and read it like this:
require 'yaml'
config = YAML.load("config.yaml") # or wherever
$remote_host = config['remote_host']
$ssh_username = config['ssh_username']
# and so on
Or you can just read one big config hash:
$config = YAML.load("config.yaml")
Note that I'm using globals here, not instance variables, so there's no chance of being surprised by variable scope.
config.yaml would then look like this:
---
remote_host: some.host.name
ssh_username: myusername
other_setting: foo
whatever: bar
I tend to keep a config.yaml.sample checked in with the main body of the code which has example but non-working settings for everything which I can copy across to the non-versioned config.yaml. Some people like to keep their config.yaml checked in to a live branch on the server itself, so that it's versioned, but I've never bothered with that.
you should be using capistrano for this, you could use mulitsage or just separate host setting to a task, example capistrano would look like this:
task :development do
server "development.host"
end
task :backup do
run "cd #{current_path}; rake db:dump"
download "remote_path", "local_path"
end
and call it like this:
cap development backup