deployinator 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/deployinator.rb CHANGED
@@ -5,3 +5,4 @@ load 'deployinator/deploy.rb'
5
5
  load 'deployinator/check.rb'
6
6
  load 'deployinator/config.rb'
7
7
  load 'deployinator/helpers.rb'
8
+ load 'deployinator/built-in.rb'
@@ -0,0 +1,186 @@
1
+ set :deploy_log_level, "debug"
2
+ set :webserver_socket_path, -> { shared_path.join('run') }
3
+ set :deploy_templates_path, "templates/deploy"
4
+
5
+ # Default deploy_to directory is /var/www/my_app
6
+ # set :deploy_to, '/var/www/my_app'
7
+
8
+ # Default value for :log_level is :debug
9
+ # set :log_level, :debug
10
+
11
+ # Default value for :linked_files is []
12
+ # set :linked_files, %w{config/database.yml}
13
+
14
+ # Default value for linked_dirs is []
15
+ # set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
16
+
17
+ # Default value for default_env is {}
18
+ # set :default_env, { path: "/opt/ruby/bin:$PATH" }
19
+
20
+ # Default value for keep_releases is 5
21
+ # set :keep_releases, 5
22
+
23
+ #set :bundle_roles, :all # this is default
24
+ #set :bundle_servers, -> { release_roles(fetch(:bundle_roles)) } # this is default
25
+ #set :bundle_binstubs, -> { shared_path.join('bin') } # this is default
26
+ #set :bundle_binstubs, -> { shared_path.join('bundle', 'bin') } # this will be overwritten by deployinator
27
+ #set :bundle_gemfile, -> { release_path.join('Gemfile') } # this will be overwritten by deployinator
28
+ #set :bundle_path, -> { shared_path.join('bundle') } # this is default
29
+ #set :bundle_without, %w{development test}.join(' ') # this is default
30
+ #set :bundle_flags, '--deployment --quiet' # this is default
31
+ #set :bundle_flags, '--deployment'
32
+ #set :bundle_env_variables, {} # this is default
33
+ set :migration_role, :db # Defaults to 'db'
34
+ #set :conditionally_migrate, true # Defaults to false. If true, it's skip migration if files in db/migrate not modified
35
+ set :assets_roles, [:app] # Defaults to [:web]
36
+ #set :assets_prefix, 'prepackaged-assets' # Defaults to 'assets' this should match config.assets.prefix in your rails config/application.rb
37
+
38
+ # TODO: fix from_local, right now you have to copy-paste the set_scm method to your deploy.rb
39
+ # Use `cap <stage> deploy from_local=true` to deploy your locally changed code
40
+ # instead of the code in the git repo. You can also add --trace.
41
+ # You can set include_dir and exclude_dir settings (from capistrano-scm-copy gem).
42
+ # These will only apply when using the from_local=true option
43
+ # set :include_dir, '../.*'
44
+ # set :exclude_dir, ["../.$", "../..", '.././infrastructure']
45
+ def set_scm
46
+ if ENV['from_local']
47
+ if "#{fetch(:stage)}" == "production"
48
+ run_locally do
49
+ fatal("You are trying to deploy to production using from_local, " +
50
+ "this should pretty much never be done.")
51
+ end
52
+ ask :yes_no, "Are you positive you want to continue?"
53
+ case fetch(:yes_no).chomp.downcase
54
+ when "yes"
55
+ when "no"
56
+ exit
57
+ else
58
+ warn "Please enter 'yes' or 'no'"
59
+ set_scm
60
+ end
61
+ end
62
+ set :scm, :copy
63
+ else
64
+ set :scm, :git
65
+ end
66
+ end
67
+ set_scm
68
+
69
+ def deploy_run_bluepill(host)
70
+ execute(
71
+ "docker", "run", "--tty", "--detach",
72
+ "--name", fetch(:ruby_container_name),
73
+ "-e", "GEM_HOME=#{shared_path.join('bundle')}",
74
+ "-e", "GEM_PATH=#{shared_path.join('bundle')}",
75
+ "-e", "BUNDLE_GEMFILE=#{current_path.join('Gemfile')}",
76
+ "-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
77
+ "--restart", "always", "--memory", "#{fetch(:ruby_container_max_mem_mb)}m",
78
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
79
+ "--entrypoint", shared_path.join('bundle', 'bin', 'bluepill'),
80
+ fetch(:ruby_image_name), "load",
81
+ current_path.join('config', 'bluepill.rb')
82
+ )
83
+ end
84
+ def deploy_run_cadvisor(host)
85
+ execute(
86
+ "docker", "run", "--detach",
87
+ "--name", "cadvisor",
88
+ "--volume", "/:/rootfs:ro",
89
+ "--volume", "/var/run:/var/run:rw",
90
+ "--volume", "/sys:/sys:ro",
91
+ "--volume", "/var/lib/docker/:/var/lib/docker:ro",
92
+ "--publish", "127.0.0.1:8080:8080",
93
+ "--restart", "always",
94
+ "google/cadvisor:latest"
95
+ )
96
+ end
97
+ def deploy_rails_console(host)
98
+ [
99
+ "ssh", "-t", "#{host}", "\"docker", "exec", "--interactive", "--tty",
100
+ fetch(:ruby_container_name),
101
+ "bash", "-c", "'cd", current_path, "&&",
102
+ shared_path.join('bundle', 'bin', 'rails'),
103
+ "console", "#{fetch(:rails_env)}'\""
104
+ ].join(' ')
105
+ end
106
+ def deploy_rails_console_print(host)
107
+ [
108
+ "docker", "exec", "--interactive", "--tty",
109
+ fetch(:ruby_container_name),
110
+ "bash", "-c", "\"cd", current_path, "&&",
111
+ shared_path.join('bundle', 'bin', 'rails'),
112
+ "console", "#{fetch(:rails_env)}\""
113
+ ].join(' ')
114
+ end
115
+ def sshkit_bundle_command_map
116
+ [
117
+ "/usr/bin/env docker run --rm --tty",
118
+ "--user", fetch(:deployment_username),
119
+ "-e", "GEM_HOME=#{shared_path.join('bundle')}",
120
+ "-e", "GEM_PATH=#{shared_path.join('bundle')}",
121
+ "-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
122
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
123
+ "--volume", "$SSH_AUTH_SOCK:/ssh-agent --env SSH_AUTH_SOCK=/ssh-agent",
124
+ "--volume", "/home:/home:rw",
125
+ "--volume", "/etc/passwd:/etc/passwd:ro",
126
+ "--volume", "/etc/group:/etc/group:ro",
127
+ "--entrypoint", "#{shared_path.join('bundle', 'bin', 'bundle')}",
128
+ fetch(:ruby_image_name)
129
+ ].join(' ')
130
+ end
131
+ def deploy_assets_precompile(host)
132
+ execute("docker", "run", "--rm", "--tty", "--user", fetch(:webserver_username),
133
+ "-w", release_path,
134
+ "--volume", "/home:/home:rw",
135
+ "--volume", "/etc/passwd:/etc/passwd:ro",
136
+ "--volume", "/etc/group:/etc/group:ro",
137
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
138
+ "--entrypoint", "/bin/bash",
139
+ fetch(:ruby_image_name), "-c",
140
+ "\"umask", "0007", "&&", "#{shared_path.join('bundle', 'bin', 'rake')}",
141
+ "assets:precompile\"")
142
+ end
143
+ def deploy_assets_cleanup(host)
144
+ execute("docker", "run", "--rm", "--tty",
145
+ "-e", "RAILS_ENV=#{fetch(:rails_env)}",
146
+ "-w", release_path,
147
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
148
+ "--entrypoint", shared_path.join('bundle', 'bin', 'bundle'),
149
+ fetch(:ruby_image_name), "exec", "rake", "assets:clean")
150
+ end
151
+ def deploy_rake_db_migrate(host)
152
+ execute("docker", "run", "--rm", "--tty",
153
+ "-w", release_path,
154
+ "-e", "RAILS_ENV=#{fetch(:rails_env)}",
155
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
156
+ "--entrypoint", shared_path.join('bundle', 'bin', 'rake'),
157
+ fetch(:ruby_image_name), "db:migrate")
158
+ end
159
+ def deploy_install_bundler(host)
160
+ execute("docker", "run", "--rm", "--tty", "--user", fetch(:deployment_username),
161
+ "-e", "GEM_HOME=#{shared_path.join('bundle')}",
162
+ "-e", "GEM_PATH=#{shared_path.join('bundle')}",
163
+ "-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
164
+ "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
165
+ "--volume", "/home:/home:rw",
166
+ "--volume", "/etc/passwd:/etc/passwd:ro",
167
+ "--volume", "/etc/group:/etc/group:ro",
168
+ "--entrypoint", "/bin/bash",
169
+ fetch(:ruby_image_name), "-c",
170
+ "\"umask", "0007", "&&" "/usr/local/bin/gem", "install",
171
+ "--install-dir", "#{shared_path.join('bundle')}",
172
+ "--bindir", shared_path.join('bundle', 'bin'),
173
+ "--no-ri", "--no-rdoc", "--quiet", "bundler", "-v'#{fetch(:bundler_version)}'\"")
174
+ end
175
+ def deploy_bluepill_restart(host)
176
+ execute("docker", "exec", "--tty",
177
+ fetch(:ruby_container_name),
178
+ shared_path.join('bundle', 'bin', 'bluepill'),
179
+ fetch(:application), "restart")
180
+ end
181
+ def deploy_bluepill_stop(host)
182
+ execute("docker", "exec", "--tty",
183
+ fetch(:ruby_container_name),
184
+ shared_path.join('bundle', 'bin', 'bluepill'),
185
+ fetch(:application), "stop")
186
+ end
@@ -4,20 +4,7 @@ namespace :deploy do
4
4
  task :bundle_command_map => ['deployinator:deployment_user'] do
5
5
  set :bundle_binstubs, -> { shared_path.join('bundle', 'bin') }
6
6
  set :bundle_gemfile, -> { release_path.join('Gemfile') }
7
- SSHKit.config.command_map[:bundle] = [
8
- "/usr/bin/env docker run --rm --tty",
9
- "--user", fetch(:deployment_user_id),
10
- "-e", "GEM_HOME=#{shared_path.join('bundle')}",
11
- "-e", "GEM_PATH=#{shared_path.join('bundle')}",
12
- "-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
13
- "--entrypoint", "#{shared_path.join('bundle', 'bin', 'bundle')}",
14
- "--volume $SSH_AUTH_SOCK:/ssh-agent --env SSH_AUTH_SOCK=/ssh-agent",
15
- "--volume #{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
16
- "--volume /etc/passwd:/etc/passwd:ro",
17
- "--volume /etc/group:/etc/group:ro",
18
- "--volume /home:/home:rw",
19
- fetch(:ruby_image_name)
20
- ].join(' ')
7
+ SSHKit.config.command_map[:bundle] = sshkit_bundle_command_map
21
8
  end
22
9
  before 'bundler:install', 'deploy:check:bundle_command_map'
23
10
 
@@ -26,6 +13,14 @@ namespace :deploy do
26
13
  SSHKit.config.command_map[:rm] = "/usr/bin/env sudo rm"
27
14
  end
28
15
 
16
+ before 'deploy:check', :brakeman_reminder do
17
+ run_locally do
18
+ warn "Remember to run brakeman before deploying!"
19
+ ask :return_to_continue, nil
20
+ set :nothing, fetch(:return_to_continue)
21
+ end
22
+ end
23
+
29
24
  if Rake::Task.task_defined?("deploy:cleanup")
30
25
  # Append dependancy to existing cleanup task
31
26
  task 'deploy:cleanup' => 'deploy:check:rm_command_map'
@@ -45,13 +40,13 @@ namespace :deploy do
45
40
  # TODO make this better
46
41
  before 'deploy:check', :templates do
47
42
  run_locally do
48
- keys_template = File.expand_path("./templates/deploy/deployment_authorized_keys.erb")
49
- bluepill_template = File.expand_path("./templates/deploy/bluepill.rb.erb")
50
- unicorn_template = File.expand_path("./templates/deploy/unicorn.rb.erb")
43
+ keys_template = File.expand_path("./#{fetch(:deploy_templates_path)}/deployment_authorized_keys.erb")
44
+ bluepill_template = File.expand_path("./#{fetch(:deploy_templates_path)}/bluepill.rb.erb")
45
+ unicorn_template = File.expand_path("./#{fetch(:deploy_templates_path)}/unicorn.rb.erb")
51
46
  {
52
- "You need a templates/deploy/deployment_authorized_keys.erb file." => keys_template,
53
- "You need a templates/deploy/bluepill.rb.erb file." => bluepill_template,
54
- "You need a templates/deploy/unicorn.rb.erb file." => unicorn_template,
47
+ "You need a #{fetch(:deploy_templates_path)}/deployment_authorized_keys.erb file." => keys_template,
48
+ "You need a #{fetch(:deploy_templates_path)}/bluepill.rb.erb file." => bluepill_template,
49
+ "You need a #{fetch(:deploy_templates_path)}/unicorn.rb.erb file." => unicorn_template,
55
50
  }.each do |message, file|
56
51
  fatal(message) and raise unless File.exists? file
57
52
  end
@@ -64,9 +59,9 @@ namespace :deploy do
64
59
  task :root_dir_permissions => ['deployinator:deployment_user', 'deployinator:webserver_user'] do
65
60
  on roles(:app) do
66
61
  as :root do
67
- [fetch(:deploy_to), Pathname.new(fetch(:deploy_to)).join("../")].each do |dir|
62
+ [fetch(:deploy_to), Pathname.new(fetch(:deploy_to)).join("../"), shared_path].each do |dir|
68
63
  if directory_exists?(dir)
69
- execute "chown", "#{fetch(:deployment_user_id)}:#{fetch(:webserver_user_id)}", dir
64
+ execute "chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}", dir
70
65
  execute "chmod", "2750", dir
71
66
  end
72
67
  end
@@ -75,53 +70,29 @@ namespace :deploy do
75
70
  end
76
71
  before 'deploy:check:directories', 'deploy:check:root_dir_permissions'
77
72
 
78
- before 'deploy:check', :webserver_running do
79
- on roles(:app) do
80
- if container_exists?(fetch(:webserver_container_name))
81
- unless container_is_running?(fetch(:webserver_container_name))
82
- warn "The webserver container named #{fetch(:webserver_container_name)} exists but is not running. You can still deploy your code, but you need this, start it, or re-run setup with something like nginxinator."
83
- ask :return_to_continue, nil
84
- set :nothing, fetch(:return_to_continue)
85
- end
86
- else
87
- warn "No webserver container named #{fetch(:webserver_container_name)} exists! You can still deploy your code, but you need this, set it up with something like nginxinator."
88
- ask :return_to_continue, nil
89
- set :nothing, fetch(:return_to_continue)
90
- end
91
- end
92
- end
93
-
94
73
  before 'deploy:check', :postgres_running do
95
- on primary fetch(:migration_role) do
96
- if container_exists?(fetch(:postgres_container_name))
97
- if container_is_running?(fetch(:postgres_container_name))
98
- unless localhost_port_responding?(fetch(:postgres_port))
99
- fatal "Port #{fetch(:postgres_port)} is not responding, we won't be able to db:migrate!"
100
- raise
101
- end
102
- else
103
- fatal "#{fetch(:postgres_container_name)} exists but is not running, we won't be able to db:migrate!"
104
- raise
105
- end
106
- else
107
- fatal "#{fetch(:postgres_container_name)} does not exist, we won't be able to db:migrate!"
74
+ on roles(:app) do
75
+ unless localhost_port_responding?(fetch(:postgres_port))
76
+ fatal "Port #{fetch(:postgres_port)} is not responding, we won't be able to db:migrate!"
108
77
  raise
109
78
  end
110
79
  end
111
80
  end
112
81
 
113
82
  before 'deploy:check', :ensure_cadvisor do
114
- on roles(:app), in: :sequence, wait: 5 do
83
+ on roles(:app) do |host|
115
84
  if fetch(:use_cadvisor, true)
116
85
  if container_exists?("cadvisor")
117
86
  if container_is_running?("cadvisor")
118
87
  info "cadvisor is already running."
119
88
  else
120
- info "Restarting existing cadvisor container."
121
- execute "docker", "start", "cadvisor"
89
+ info "Starting existing cadvisor container."
90
+ start_container("cadvisor")
122
91
  end
123
92
  else
124
- execute("docker", "run", fetch(:docker_run_cadvisor_command))
93
+ warn "Starting a new container named 'cadvisor' on #{host}"
94
+ deploy_run_cadvisor(host)
95
+ check_stayed_running("cadvisor")
125
96
  end
126
97
  else
127
98
  info "Not using cadvisor."
@@ -1,24 +1,109 @@
1
+ module Capistrano
2
+ module TaskEnhancements
3
+ alias_method :deploy_original_default_tasks, :default_tasks
4
+ def default_tasks
5
+ deploy_original_default_tasks + [
6
+ "deployinator:write_built_in",
7
+ "deployinator:write_example_configs",
8
+ "deployinator:write_example_configs:in_place"
9
+ ]
10
+ end
11
+ end
12
+ end
13
+
1
14
  namespace :deployinator do
2
15
 
16
+ set :example, "_example"
17
+
3
18
  desc 'Write example config files'
4
19
  task :write_example_configs do
5
20
  run_locally do
6
- execute "mkdir", "-p", "config/deploy", "templates/deploy"
21
+ execute "mkdir", "-p", "config/deploy", fetch(:deploy_templates_path, 'templates/deploy')
7
22
  {
8
- "examples/Capfile" => "Capfile_example",
9
- "examples/config/deploy.rb" => "config/deploy_example.rb",
10
- "examples/config/deploy/staging.rb" => "config/deploy/staging_example.rb",
11
- "examples/Dockerfile" => "templates/deploy/Dockerfile_example",
12
- "examples/deployment_authorized_keys.erb" => "templates/deploy/deployment_authorized_keys_example.erb",
13
- "examples/unicorn.rb.erb" => "templates/deploy/unicorn_example.rb.erb",
14
- "examples/bluepill.rb.erb" => "templates/deploy/bluepill_example.rb.erb"
23
+ "examples/Capfile" => "Capfile#{fetch(:example)}",
24
+ "examples/config/deploy.rb" => "config/deploy#{fetch(:example)}.rb",
25
+ "examples/config/deploy/staging.rb" => "config/deploy/staging#{fetch(:example)}.rb",
26
+ "examples/Dockerfile" => "#{fetch(:deploy_templates_path, 'templates/deploy')}/Dockerfile#{fetch(:example)}",
27
+ "examples/deployment_authorized_keys.erb" => "#{fetch(:deploy_templates_path, 'templates/deploy')}/deployment_authorized_keys#{fetch(:example)}.erb",
28
+ "examples/unicorn.rb.erb" => "#{fetch(:deploy_templates_path, 'templates/deploy')}/unicorn#{fetch(:example)}.rb.erb",
29
+ "examples/bluepill.rb.erb" => "#{fetch(:deploy_templates_path, 'templates/deploy')}/bluepill#{fetch(:example)}.rb.erb"
15
30
  }.each do |source, destination|
16
31
  config = File.read(File.dirname(__FILE__) + "/#{source}")
17
32
  File.open("./#{destination}", 'w') { |f| f.write(config) }
18
33
  info "Wrote '#{destination}'"
19
34
  end
20
- info "Now remove the '_example' portion of their names or diff with existing files and add the needed lines."
35
+ unless fetch(:example).empty?
36
+ info "Now remove the '#{fetch(:example)}' portion of their names or diff with existing files and add the needed lines."
37
+ end
38
+ end
39
+ end
40
+
41
+ desc 'Write example config files (will overwrite any existing config files).'
42
+ namespace :write_example_configs do
43
+ task :in_place do
44
+ set :example, ""
45
+ Rake::Task['deployinator:write_example_configs'].invoke
46
+ end
47
+ end
48
+
49
+ desc 'Write a file showing the built-in overridable settings.'
50
+ task :write_built_in do
51
+ run_locally do
52
+ {
53
+ 'built-in.rb' => 'built-in.rb',
54
+ }.each do |source, destination|
55
+ config = File.read(File.dirname(__FILE__) + "/#{source}")
56
+ File.open("./#{destination}", 'w') { |f| f.write(config) }
57
+ info "Wrote '#{destination}'"
58
+ end
59
+ info "Now examine the file and copy-paste into your deploy.rb or <stage>.rb and customize."
60
+ end
61
+ end
62
+
63
+ # These are the only two tasks using :preexisting_ssh_user
64
+ namespace :deployment_user do
65
+ #desc "Setup or re-setup the deployment user, idempotently"
66
+ task :setup do
67
+ on roles(:all) do |h|
68
+ on "#{fetch(:preexisting_ssh_user)}@#{h}" do |host|
69
+ as :root do
70
+ deployment_user_setup(fetch(:deploy_templates_path, 'templates/deploy'))
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ task :deployment_user do
78
+ on roles(:all) do |h|
79
+ on "#{fetch(:preexisting_ssh_user)}@#{h}" do |host|
80
+ as :root do
81
+ if unix_user_exists?(fetch(:deployment_username))
82
+ info "User #{fetch(:deployment_username)} already exists. You can safely re-setup the user with 'deployinator:deployment_user:setup'."
83
+ else
84
+ Rake::Task['deployinator:deployment_user:setup'].invoke
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ task :webserver_user do
92
+ on roles(:app) do
93
+ as :root do
94
+ unix_user_add(fetch(:webserver_username)) unless unix_user_exists?(fetch(:webserver_username))
95
+ end
96
+ end
97
+ end
98
+
99
+ task :file_permissions => [:deployment_user, :webserver_user] do
100
+ on roles(:app) do
101
+ as :root do
102
+ setup_file_permissions
103
+ end
21
104
  end
22
105
  end
106
+ after 'deploy:check', 'deployinator:file_permissions'
107
+ before 'deploy:restart', 'deployinator:file_permissions'
23
108
 
24
109
  end
@@ -3,6 +3,22 @@ lock '3.2.1'
3
3
 
4
4
  namespace :deploy do
5
5
 
6
+ before :starting, :log_level do
7
+ SSHKit.config.output_verbosity = fetch(:deploy_log_level)
8
+ end
9
+
10
+ before :starting, 'deployinator:sshkit_umask'
11
+
12
+ # Default branch is :master
13
+ before :starting, :set_branch do
14
+ unless ENV['from_local']
15
+ # Always use the master branch in production:
16
+ unless "#{fetch(:stage)}" == "production"
17
+ ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call
18
+ end
19
+ end
20
+ end
21
+
6
22
  #desc 'Copies .git folder to support .gemspecs that run git commands'
7
23
  task :copy_git do
8
24
  unless ENV['from_local'] == "true"
@@ -17,22 +33,11 @@ namespace :deploy do
17
33
 
18
34
  if Rake::Task.task_defined?("deploy:assets:precompile")
19
35
  # Overwrite :assets:precompile to use docker
20
- Rake::Task["deploy:assets:precompile"].clear
36
+ Rake::Task["deploy:assets:precompile"].clear_actions
21
37
  namespace :assets do
22
38
  task :precompile => ['deployinator:deployment_user'] do
23
- on roles(fetch(:assets_roles)) do
24
- execute(
25
- "docker", "run", "--rm", "--tty", "--user", fetch(:webserver_username),
26
- "-w", release_path,
27
- "--link", "#{fetch(:postgres_container_name)}:postgres",
28
- "--entrypoint", "/bin/bash",
29
- "--volume", "/etc/passwd:/etc/passwd:ro",
30
- "--volume", "/etc/group:/etc/group:ro",
31
- "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
32
- fetch(:ruby_image_name), "-c",
33
- "\"umask", "0007", "&&", "#{shared_path.join('bundle', 'bin', 'rake')}",
34
- "assets:precompile\""
35
- )
39
+ on roles(fetch(:assets_roles)) do |host|
40
+ deploy_assets_precompile(host)
36
41
  end
37
42
  end
38
43
  end
@@ -40,64 +45,37 @@ namespace :deploy do
40
45
 
41
46
  if Rake::Task.task_defined?("deploy:cleanup_assets")
42
47
  # Overwrite :cleanup_assets to use docker
43
- Rake::Task["deploy:cleanup_assets"].clear
48
+ Rake::Task["deploy:cleanup_assets"].clear_actions
44
49
  desc 'Cleanup expired assets'
45
50
  task :cleanup_assets => [:set_rails_env] do
46
- on roles(fetch(:assets_roles)) do
47
- execute(
48
- "docker", "run", "--rm", "--tty",
49
- "-e", "RAILS_ENV=#{fetch(:rails_env)}",
50
- "-w", release_path,
51
- "--entrypoint", shared_path.join('bundle', 'bin', 'bundle'),
52
- "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
53
- fetch(:ruby_image_name), "exec", "rake", "assets:clean"
54
- )
51
+ on roles(fetch(:assets_roles)) do |host|
52
+ deploy_assets_cleanup(host)
55
53
  end
56
54
  end
57
55
  end
58
56
 
59
57
  if Rake::Task.task_defined?("deploy:migrate")
60
58
  # Overwrite :migrate to use docker
61
- Rake::Task["deploy:migrate"].clear
59
+ Rake::Task["deploy:migrate"].clear_actions
62
60
  desc 'Runs rake db:migrate if migrations are set'
63
61
  task :migrate => [:set_rails_env, 'deploy:check:postgres_running'] do
64
- on primary fetch(:migration_role) do
62
+ on primary fetch(:migration_role) do |host|
65
63
  conditionally_migrate = fetch(:conditionally_migrate)
66
64
  info '[deploy:migrate] Checking changes in /db/migrate' if conditionally_migrate
67
65
  if conditionally_migrate && test("diff -q #{release_path}/db/migrate #{current_path}/db/migrate")
68
66
  info '[deploy:migrate] Skip `deploy:migrate` (nothing changed in db/migrate)'
69
67
  else
70
68
  info '[deploy:migrate] Run `rake db:migrate`' if conditionally_migrate
71
- execute(
72
- "docker", "run", "--rm", "--tty",
73
- "--link", "#{fetch(:postgres_container_name)}:postgres",
74
- "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
75
- "-e", "RAILS_ENV=#{fetch(:rails_env)}",
76
- "--entrypoint", shared_path.join('bundle', 'bin', 'rake'),
77
- "-w", release_path,
78
- fetch(:ruby_image_name), "db:migrate"
79
- )
69
+ deploy_rake_db_migrate(host)
80
70
  end
81
71
  end
82
72
  end
83
73
  end
84
74
 
85
75
  task :install_bundler => ['deployinator:deployment_user'] do
86
- on roles(:app), in: :sequence, wait: 5 do
76
+ on roles(:app) do |host|
87
77
  unless file_exists?(shared_path.join('bundle', 'bin', 'bundle'))
88
- execute(
89
- "docker", "run", "--rm", "--tty", "--user", fetch(:deployment_user_id),
90
- "-e", "GEM_HOME=#{shared_path.join('bundle')}",
91
- "-e", "GEM_PATH=#{shared_path.join('bundle')}",
92
- "-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
93
- "--entrypoint", "/bin/bash",
94
- "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
95
- fetch(:ruby_image_name), "-c",
96
- "\"umask", "0007", "&&" "/usr/local/bin/gem", "install",
97
- "--install-dir", "#{shared_path.join('bundle')}",
98
- "--bindir", shared_path.join('bundle', 'bin'),
99
- "--no-ri", "--no-rdoc", "--quiet", "bundler", "-v'#{fetch(:bundler_version)}'\""
100
- )
78
+ deploy_install_bundler(host)
101
79
  end
102
80
  end
103
81
  end
@@ -105,26 +83,24 @@ namespace :deploy do
105
83
 
106
84
  desc 'Restart application using bluepill restart inside the docker container.'
107
85
  task :restart => ['deployinator:webserver_user', :install_config_files] do
108
- on roles(:app), in: :sequence, wait: 5 do
109
- if container_exists?(fetch(:ruby_container_name))
110
- if container_is_restarting?(fetch(:ruby_container_name))
111
- execute("docker", "stop", fetch(:ruby_container_name))
86
+ on roles(:app) do |host|
87
+ name = fetch(:ruby_container_name)
88
+ if container_exists?(name)
89
+ if container_is_restarting?(name)
90
+ execute("docker", "stop", name)
112
91
  end
113
- if container_is_running?(fetch(:ruby_container_name))
114
- execute(
115
- "docker", "exec", "--tty",
116
- fetch(:ruby_container_name),
117
- shared_path.join('bundle', 'bin', 'bluepill'),
118
- fetch(:application), "restart"
119
- )
92
+ if container_is_running?(name)
93
+ deploy_bluepill_restart(host)
120
94
  else
121
- execute("docker", "start", fetch(:ruby_container_name))
95
+ execute("docker", "start", name)
122
96
  end
123
97
  else
124
98
  as :root do
125
99
  execute("rm", "-f", fetch(:webserver_socket_path).join('unicorn.pid'))
126
100
  end
127
- execute("docker", "run", fetch(:docker_run_bluepill_command))
101
+ warn "Starting a new container named #{name} on #{host}"
102
+ deploy_run_bluepill(host)
103
+ check_stayed_running(name)
128
104
  end
129
105
  end
130
106
  end
@@ -133,15 +109,10 @@ namespace :deploy do
133
109
  desc 'Restart application by recreating the docker container.'
134
110
  namespace :restart do
135
111
  task :force do
136
- on roles(:app), in: :sequence, wait: 5 do
112
+ on roles(:app) do |host|
137
113
  if container_exists?(fetch(:ruby_container_name))
138
114
  if container_is_running?(fetch(:ruby_container_name))
139
- execute(
140
- "docker", "exec", "--tty",
141
- fetch(:ruby_container_name),
142
- shared_path.join('bundle', 'bin', 'bluepill'),
143
- fetch(:application), "stop"
144
- )
115
+ deploy_bluepill_stop(host)
145
116
  sleep 5
146
117
  execute("docker", "stop", fetch(:ruby_container_name))
147
118
  execute("docker", "wait", fetch(:ruby_container_name))
@@ -173,33 +144,37 @@ namespace :deploy do
173
144
  # end
174
145
 
175
146
  task :install_config_files => ['deployinator:deployment_user', 'deployinator:webserver_user'] do
176
- on roles(:app), in: :sequence, wait: 5 do
147
+ on roles(:app) do |host|
177
148
  set :bluepill_config, -> { "bluepill.rb" }
178
149
  set :unicorn_config, -> { "unicorn.rb" }
179
150
  set :socket_path, -> { fetch(:webserver_socket_path) }
180
151
  [fetch(:bluepill_config), fetch(:unicorn_config)].each do |config_file|
181
- template_path = File.expand_path("./templates/deploy/#{config_file}.erb")
152
+ template_path = File.expand_path("./#{fetch(:deploy_templates_path)}/#{config_file}.erb")
182
153
  generated_config_file = ERB.new(File.new(template_path).read).result(binding)
183
154
  set :final_path, -> { release_path.join('config', config_file) }
184
155
  upload! StringIO.new(generated_config_file), "/tmp/#{config_file}"
185
156
  execute("mv", "/tmp/#{config_file}", fetch(:final_path))
186
157
  as :root do
187
- execute("chown", "#{fetch(:deployment_user_id)}:#{fetch(:webserver_user_id)}", fetch(:final_path))
158
+ execute("chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}", fetch(:final_path))
188
159
  end
189
160
  end
190
161
  end
191
162
  end
192
163
 
193
- task :print_rails_console do
194
- run_locally do
195
- command = [
196
- "docker", "exec", "--interactive", "--tty",
197
- fetch(:ruby_container_name),
198
- "bash", "-c", "\"cd", current_path, "&&",
199
- shared_path.join('bundle', 'bin', 'rails'),
200
- "console", "#{fetch(:rails_env)}\""
201
- ].join(' ')
202
- info command
164
+ desc "Enter the Rails console."
165
+ task :rails_console do
166
+ on roles(:app) do |host|
167
+ info "Entering Rails Console inside #{fetch(:ruby_container_name)} on #{host}"
168
+ system deploy_rails_console(host)
169
+ end
170
+ end
171
+
172
+ namespace :rails_console do
173
+ task :print do
174
+ on roles(:app) do |host|
175
+ info "You can SSH into #{host} and run the following command to enter the Rails Console."
176
+ info deploy_rails_console_print(host)
177
+ end
203
178
  end
204
179
  end
205
180
 
@@ -1,99 +1,21 @@
1
- # config valid only for Capistrano 3.1
1
+ # config valid only for Capistrano 3.2.1
2
2
  lock '3.2.1'
3
3
 
4
- set :application, 'my_app_name'
5
- set :repo_url, 'git@example.com:me/my_repo.git'
6
- set :preexisting_ssh_user, ENV['USER']
7
- set :deployment_username, "deployer" # user with SSH access and passwordless sudo rights
8
- set :webserver_username, "www-data" # less trusted web server user with limited write permissions
9
-
10
- set :webserver_owned_dirs, [shared_path.join('tmp', 'cache'), shared_path.join('public', 'assets')]
11
- set :webserver_writeable_dirs, [shared_path.join('run'), shared_path.join("tmp"), shared_path.join("log")]
12
- set :webserver_executable_dirs, [shared_path.join("bundle", "bin")]
13
- set :ignore_permissions_dirs, [shared_path.join("postgres"), shared_path.join("nginx")]
14
- set :webserver_socket_path, shared_path.join('run')
15
-
16
- # Default branch is :master
17
- # Always use the master branch in production:
18
- set :current_stage, -> { fetch(:stage).to_s.strip }
19
- unless fetch(:current_stage) == "production"
20
- ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call
21
- end
22
-
23
- # Default deploy_to directory is /var/www/my_app
24
- # set :deploy_to, '/var/www/my_app'
25
-
26
- # Default value for :log_level is :debug
27
- # set :log_level, :debug
28
-
29
- # Default value for :linked_files is []
30
- # set :linked_files, %w{config/database.yml}
4
+ ##### deployinator
5
+ ### ------------------------------------------------------------------
6
+ set :repo_url, 'git@example.com:me/my_repo.git'
7
+ set :application, 'my_app_name'
8
+ set :preexisting_ssh_user, ENV['USER']
9
+ set :deployment_username, "deployer" # user with SSH access and passwordless sudo rights
10
+ set :webserver_username, "www-data" # less trusted web server user with limited write permissions
11
+ set :webserver_owned_dirs, [shared_path.join('tmp', 'cache'), shared_path.join('public', 'assets')]
12
+ set :webserver_writeable_dirs, [shared_path.join('run'), shared_path.join("tmp"), shared_path.join("log")]
13
+ set :webserver_executable_dirs, [shared_path.join("bundle", "bin")]
14
+ set :ignore_permissions_dirs, [shared_path.join("postgres"), shared_path.join("nginx")]
31
15
 
32
16
  # Default value for linked_dirs is []
33
17
  # set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
34
18
 
35
- # Default value for default_env is {}
36
- # set :default_env, { path: "/opt/ruby/bin:$PATH" }
37
-
38
- # Default value for keep_releases is 5
39
- # set :keep_releases, 5
40
-
41
-
42
- #----------------------------------------------------
43
- ## The values below shouldn't need changed under the majority of circumstances.
44
-
45
- # Use `cap <stage> deploy from_local=true` to deploy your
46
- # locally changed code instead of the code in the git repo. You can also add --trace.
47
- if ENV['from_local']
48
- if fetch(:current_stage) == "production"
49
- run_locally do
50
- fatal "You are trying to deploy to production using from_local, this should pretty much never be done."
51
- end
52
- ask :yes_no, "Are you positive you want to continue?"
53
- if fetch(:yes_no).chomp.downcase == "yes"
54
- set :scm, :copy
55
- else
56
- exit
57
- end
58
- end
59
- else
60
- set :scm, :git
61
- end
62
-
63
- #set :bundle_roles, :all # this is default
64
- #set :bundle_servers, -> { release_roles(fetch(:bundle_roles)) } # this is default
65
- #set :bundle_binstubs, -> { shared_path.join('bin') } # this is default
66
- #set :bundle_binstubs, -> { shared_path.join('bundle', 'bin') } # this will be overwritten by deployinator
67
- #set :bundle_gemfile, -> { release_path.join('Gemfile') } # this will be overwritten by deployinator
68
- #set :bundle_path, -> { shared_path.join('bundle') } # this is default
69
- #set :bundle_without, %w{development test}.join(' ') # this is default
70
- #set :bundle_flags, '--deployment --quiet' # this is default
71
- #set :bundle_flags, '--deployment'
72
- #set :bundle_env_variables, {} # this is default
73
-
74
- set :docker_run_bluepill_command, -> { [
75
- "--tty", "--detach",
76
- "--name", fetch(:ruby_container_name),
77
- "-e", "GEM_HOME=#{shared_path.join('bundle')}",
78
- "-e", "GEM_PATH=#{shared_path.join('bundle')}",
79
- "-e", "BUNDLE_GEMFILE=#{current_path.join('Gemfile')}",
80
- "-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
81
- "--link", "#{fetch(:postgres_container_name)}:postgres",
82
- "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
83
- "--entrypoint", shared_path.join('bundle', 'bin', 'bluepill'),
84
- "--restart", "always", "--memory", "#{fetch(:ruby_container_max_mem_mb)}m",
85
- fetch(:ruby_image_name), "load",
86
- current_path.join('config', 'bluepill.rb')
87
- ] }
88
-
89
- set :docker_run_cadvisor_command, -> { [
90
- "--detach",
91
- "--name", "cadvisor",
92
- "--volume", "/:/rootfs:ro",
93
- "--volume", "/var/run:/var/run:rw",
94
- "--volume", "/sys:/sys:ro",
95
- "--volume", "/var/lib/docker/:/var/lib/docker:ro",
96
- "--publish", "127.0.0.1:8080:8080",
97
- "--restart", "always",
98
- "google/cadvisor:latest"
99
- ] }
19
+ set :bundler_version, "1.7.4"
20
+ set :use_cadvisor, true
21
+ ### ------------------------------------------------------------------
@@ -1,21 +1,12 @@
1
- set :domain, "my-app-staging.example.com"
2
- set :user_host, "#{fetch(:deployment_username)}@#{fetch(:domain)}"
3
-
4
- role :app, fetch(:user_host)
5
- role :web, fetch(:user_host)
6
- role :db, fetch(:user_host)
7
-
8
- set :rails_env, 'production'
9
- set :migration_role, 'app' # Defaults to 'db'
10
- #set :conditionally_migrate, true # Defaults to false. If true, it's skip migration if files in db/migrate not modified
11
- set :assets_roles, [:app] # Defaults to [:web]
12
- #set :assets_prefix, 'prepackaged-assets' # Defaults to 'assets' this should match config.assets.prefix in your rails config/application.rb
13
-
14
- set :webserver_container_name, "my-app-staging.example.com-nginx-80-443"
15
- set :postgres_container_name, "my-app-staging.example.com-postgres-5432-master"
16
- set :postgres_port, "5432"
17
- set :ruby_image_name, "snarlysodboxer/ruby:1.9.3-p547"
18
- set :ruby_container_name, "#{fetch(:domain)}-ruby-bluepill"
19
- set :ruby_container_max_mem_mb, "1024"
20
- set :bundler_version, "1.7.4"
21
- set :use_cadvisor, true
1
+ ##### deployinator
2
+ ### ------------------------------------------------------------------
3
+ set :domain, "my-app-staging.example.com"
4
+ server fetch(:domain),
5
+ :user => fetch(:deployment_username),
6
+ :roles => ["app", "web", "db"]
7
+ set :rails_env, 'production'
8
+ set :ruby_image_name, "snarlysodboxer/ruby:1.9.3-p547"
9
+ set :ruby_container_name, "#{fetch(:domain)}-ruby-bluepill"
10
+ set :ruby_container_max_mem_mb, "1024"
11
+ set :postgres_port, "5432"
12
+ ### ------------------------------------------------------------------
@@ -1,141 +1,95 @@
1
1
  namespace :deployinator do
2
2
 
3
- # These are the only two tasks using :preexisting_ssh_user
4
- namespace :deployment_user do
5
- #desc "Setup or re-setup the deployment user, idempotently"
6
- task :setup do
7
- on "#{fetch(:preexisting_ssh_user)}@#{fetch(:domain)}" do
8
- as :root do
9
- unix_user_add(fetch(:deployment_username)) unless unix_user_exists?(fetch(:deployment_username))
10
- execute "usermod", "-a", "-G", "sudo,docker,#{fetch(:webserver_username)}", fetch(:deployment_username)
11
- execute "mkdir", "-p", "/home/#{fetch(:deployment_username)}/.ssh"
12
- template_path = File.expand_path("./templates/deploy/deployment_authorized_keys.erb")
13
- generated_config_file = ERB.new(File.new(template_path).read).result(binding)
14
- # upload! does not yet honor "as" and similar scoping methods
15
- upload! StringIO.new(generated_config_file), "/tmp/authorized_keys"
16
- execute "mv", "-b", "/tmp/authorized_keys", "/home/#{fetch(:deployment_username)}/.ssh/authorized_keys"
17
- execute "chown", "-R", "#{fetch(:deployment_username)}:#{fetch(:deployment_username)}", "/home/#{fetch(:deployment_username)}/.ssh"
18
- execute "chmod", "700", "/home/#{fetch(:deployment_username)}/.ssh"
19
- execute "chmod", "600", "/home/#{fetch(:deployment_username)}/.ssh/authorized_keys"
20
- end
21
- end
22
- end
23
- end
24
-
25
- task :deployment_user do
26
- on "#{fetch(:preexisting_ssh_user)}@#{fetch(:domain)}" do
27
- as :root do
28
- if unix_user_exists?(fetch(:deployment_username))
29
- info "User #{fetch(:deployment_username)} already exists. You can safely re-setup the user with 'deployinator:deployment_user:setup'."
30
- else
31
- Rake::Task['deployinator:deployment_user:setup'].invoke
32
- end
33
- set :deployment_user_id, unix_user_get_id(fetch(:deployment_username))
34
- end
35
- end
36
- end
37
-
38
- task :webserver_user do
39
- on roles(:app) do
40
- as :root do
41
- unix_user_add(fetch(:webserver_username)) unless unix_user_exists?(fetch(:webserver_username))
42
- set :webserver_user_id, unix_user_get_id(fetch(:webserver_username))
43
- end
44
- end
45
- end
46
-
47
3
  task :sshkit_umask do
48
4
  SSHKit.config.umask = "0027"
49
5
  end
50
- if Rake::Task.task_defined?('deploy:started')
51
- before 'deploy:started', 'deployinator:sshkit_umask'
52
- end
53
-
54
- task :file_permissions => [:deployment_user, :webserver_user] do
55
- on roles(:app) do
56
- as :root do
57
- ignore_options = fetch(:ignore_permissions_dirs).collect do |dir|
58
- ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
59
- end
60
-
61
- chown_ignore_options = fetch(:webserver_owned_dirs).collect do |dir|
62
- ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
63
- end
64
-
65
- # chown webserver owned
66
- fetch(:webserver_owned_dirs).each do |dir|
67
- if directory_exists?(dir)
68
- execute "find", dir, ignore_options,
69
- "-exec", "chown", "#{fetch(:webserver_user_id)}:#{fetch(:webserver_user_id)}", "{}", "+"
70
- end
71
- end
72
-
73
- # chown
74
- execute "find", fetch(:deploy_to), ignore_options, chown_ignore_options,
75
- "-exec", "chown", "#{fetch(:deployment_user_id)}:#{fetch(:webserver_user_id)}", "{}", "+"
76
-
77
- # chmod executable
78
- fetch(:webserver_executable_dirs).each do |dir|
79
- if directory_exists?(dir)
80
- execute "find", dir, "-type", "f",
81
- "-exec", "chmod", "0750", "{}", "+"
82
- end
83
- ignore_options += ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
84
- end
85
-
86
- # chmod writable
87
- fetch(:webserver_writeable_dirs).each do |dir|
88
- if directory_exists?(dir)
89
- execute "find", "-L", dir, "-type", "d",
90
- "-exec", "chmod", "2770", "{}", "+"
91
- execute "find", "-L", dir, "-type", "f",
92
- "-exec", "chmod", "0660", "{}", "+"
93
- end
94
- ignore_options += ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
95
- end
96
-
97
- # chmod
98
- execute "find", fetch(:deploy_to), "-type", "d", ignore_options,
99
- "-exec", "chmod", "2750", "{}", "+"
100
- execute "find", fetch(:deploy_to), "-type", "f", ignore_options,
101
- "-exec", "chmod", "0640", "{}", "+"
102
- end
103
- end
104
- end
105
- after 'deploy:check', 'deployinator:file_permissions'
106
- before 'deploy:restart', 'deployinator:file_permissions'
107
-
108
6
 
109
7
  task :settings, [:absolute_path, :relative_path] do |t, args|
110
8
  run_locally do
9
+ if fetch(:print_all)
10
+ lines = "\nThe following settings are needed in your config (#{args.relative_path}).\n"
11
+ lines += File.read(args.absolute_path)
12
+ info lines
13
+ break
14
+ end
15
+
111
16
  need_moar_settings = false
112
17
  settings = File.read(args.absolute_path).split("\nset").collect do |line|
113
18
  "set#{line}" if line =~ /^ :/
114
19
  end.compact
115
- if fetch(:print_all, false)
116
- lines = "\nThe following settings are needed in your config (#{args.relative_path}).\n"
117
- else
118
- lines = "\nAdd the following setting(s) to your config (#{args.relative_path}) and try again:\n"
119
- end
20
+ lines = "\nAdd the following setting(s) to your config (#{args.relative_path}) and try again:\n"
120
21
  settings.each do |setting|
121
- if fetch(setting.split(',')[0].split(':')[1].to_sym).nil? or fetch(:print_all, false)
22
+ if fetch(setting.split(',')[0].split(':')[1].to_sym).nil?
122
23
  lines += setting.chomp == setting ? "#{setting}\n" : setting
123
24
  need_moar_settings = true
124
25
  end
125
26
  end
126
- if need_moar_settings
127
- if fetch(:print_all, false)
128
- info lines
129
- else
130
- fatal lines if lines.lines.count > 2
131
- exit
132
- end
133
- end
27
+ fatal(lines) if(lines.lines.count > 2) if(need_moar_settings)
28
+ exit if need_moar_settings
134
29
  end
135
30
  end
136
31
 
137
32
  end
138
33
 
34
+
35
+ def deployment_user_setup(templates_path)
36
+ require 'erb' unless defined?(ERB)
37
+ name = fetch(:deployment_username)
38
+ unix_user_add(name) unless unix_user_exists?(name)
39
+ execute "usermod", "-a", "-G", "sudo,docker,#{fetch(:webserver_username)}", name
40
+ execute "mkdir", "-p", "/home/#{name}/.ssh"
41
+ template_path = File.expand_path("./#{templates_path}/deployment_authorized_keys.erb")
42
+ generated_config_file = ERB.new(File.new(template_path).read).result(binding)
43
+ # upload! does not yet honor "as" and similar scoping methods
44
+ upload! StringIO.new(generated_config_file), "/tmp/authorized_keys"
45
+ execute "mv", "-b", "/tmp/authorized_keys", "/home/#{name}/.ssh/authorized_keys"
46
+ execute "chown", "-R", "#{name}:#{name}", "/home/#{name}"
47
+ execute "chmod", "700", "/home/#{name}/.ssh"
48
+ execute "chmod", "600", "/home/#{name}/.ssh/authorized_keys"
49
+ end
50
+
51
+ def setup_file_permissions
52
+ ignore_options = fetch(:ignore_permissions_dirs).collect do |dir|
53
+ ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
54
+ end
55
+ chown_ignore_options = fetch(:webserver_owned_dirs).collect do |dir|
56
+ ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
57
+ end
58
+ # chown webserver owned
59
+ fetch(:webserver_owned_dirs).each do |dir|
60
+ if directory_exists?(dir)
61
+ execute "find", dir, ignore_options,
62
+ "-exec", "chown", "#{fetch(:webserver_username)}:#{fetch(:webserver_username)}", "{}", "+"
63
+ end
64
+ end
65
+ # chown
66
+ execute "find", fetch(:deploy_to), ignore_options, chown_ignore_options,
67
+ "-exec", "chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}", "{}", "+"
68
+ # chmod executable
69
+ fetch(:webserver_executable_dirs).each do |dir|
70
+ if directory_exists?(dir)
71
+ execute "find", dir, "-type", "f",
72
+ "-exec", "chmod", "0750", "{}", "+"
73
+ end
74
+ ignore_options += ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
75
+ end
76
+ # chmod writable
77
+ fetch(:webserver_writeable_dirs).each do |dir|
78
+ if directory_exists?(dir)
79
+ execute "find", "-L", dir, "-type", "d",
80
+ "-exec", "chmod", "2770", "{}", "+"
81
+ execute "find", "-L", dir, "-type", "f",
82
+ "-exec", "chmod", "0660", "{}", "+"
83
+ end
84
+ ignore_options += ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
85
+ end
86
+ # chmod
87
+ execute "find", fetch(:deploy_to), "-type", "d", ignore_options,
88
+ "-exec", "chmod", "2750", "{}", "+"
89
+ execute "find", fetch(:deploy_to), "-type", "f", ignore_options,
90
+ "-exec", "chmod", "0640", "{}", "+"
91
+ end
92
+
139
93
  def container_exists?(container_name)
140
94
  test "bash", "-c", "\"docker", "inspect", container_name, "&>", "/dev/null\""
141
95
  end
@@ -150,6 +104,30 @@ def container_is_restarting?(container_name)
150
104
  container_name, "2>&1`\"", "=", "\"true\"", "]"
151
105
  end
152
106
 
107
+ def check_stayed_running(name)
108
+ sleep 3
109
+ unless container_is_running?(name)
110
+ fatal "Container #{name} on #{fetch(:domain)} did not stay running more than 3 seconds"
111
+ exit
112
+ end
113
+ if container_is_restarting?(name)
114
+ fatal "Container #{name} on #{fetch(:domain)} is stuck restarting itself."
115
+ exit
116
+ end
117
+ end
118
+
119
+ def start_container(name)
120
+ warn "Starting an existing but non-running container named #{name}"
121
+ execute("docker", "start", name)
122
+ check_stayed_running(name)
123
+ end
124
+
125
+ def restart_container(name)
126
+ warn "Restarting a running container named #{name}"
127
+ execute("docker", "restart", name)
128
+ check_stayed_running(name)
129
+ end
130
+
153
131
  def localhost_port_responding?(port)
154
132
  test "nc", "127.0.0.1", port, "<", "/dev/null", ">", "/dev/null;",
155
133
  "[", "`echo", "$?`", "-eq", "0", "]"
@@ -163,10 +141,14 @@ def unix_user_add(user)
163
141
  execute "adduser", "--disabled-password", "--gecos", "\"\"", user
164
142
  end
165
143
 
166
- def unix_user_get_id(user)
144
+ def unix_user_get_uid(user)
167
145
  capture("id", "-u", user).strip
168
146
  end
169
147
 
148
+ def unix_user_get_gid(user)
149
+ capture("id", "-g", user).strip
150
+ end
151
+
170
152
  def file_exists?(file)
171
153
  test "[", "-f", file, "]"
172
154
  end
@@ -175,32 +157,6 @@ def directory_exists?(dir)
175
157
  test "[", "-d", dir, "]"
176
158
  end
177
159
 
178
- def check_stayed_running(name)
179
- sleep 3
180
- unless container_is_running?(name)
181
- fatal "Container #{name} on #{fetch(:domain)} did not stay running more than 3 seconds"
182
- exit
183
- end
184
- if container_is_restarting?(name)
185
- fatal "Container #{name} on #{fetch(:domain)} is stuck restarting itself."
186
- exit
187
- end
188
- end
189
-
190
- def create_container(name, command)
191
- warn "Starting a new container named #{name} on #{fetch(:domain)}"
192
- execute("docker", "run", command)
193
- check_stayed_running(name)
194
- end
195
-
196
- def start_container(name)
197
- warn "Starting an existing but non-running container named #{name}"
198
- execute("docker", "start", name)
199
- check_stayed_running(name)
200
- end
201
-
202
- def restart_container(name)
203
- warn "Restarting a running container named #{name}"
204
- execute("docker", "restart", name)
205
- check_stayed_running(name)
160
+ def files_in_directory?(dir)
161
+ test("[", "\"$(ls", "-A", "#{dir})\"", "]")
206
162
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deployinator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,14 +9,14 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-01-06 00:00:00.000000000 Z
12
+ date: 2015-01-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: capistrano
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - '='
19
+ - - ~>
20
20
  - !ruby/object:Gem::Version
21
21
  version: 3.2.1
22
22
  type: :runtime
@@ -24,10 +24,42 @@ dependencies:
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
- - - '='
27
+ - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: 3.2.1
30
- description: An Opinionated Deployment gem
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 10.3.2
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 10.3.2
46
+ - !ruby/object:Gem::Dependency
47
+ name: sshkit
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 1.5.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.5.1
62
+ description: Deploy Ruby on Rails using Capistrano and Docker
31
63
  email: davidamick@ctisolutionsinc.com
32
64
  executables: []
33
65
  extensions: []
@@ -38,6 +70,7 @@ files:
38
70
  - lib/deployinator/check.rb
39
71
  - lib/deployinator/config.rb
40
72
  - lib/deployinator/helpers.rb
73
+ - lib/deployinator/built-in.rb
41
74
  - lib/deployinator/examples/Capfile
42
75
  - lib/deployinator/examples/config/deploy.rb
43
76
  - lib/deployinator/examples/config/deploy/staging.rb
@@ -57,14 +90,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
57
90
  requirements:
58
91
  - - ! '>='
59
92
  - !ruby/object:Gem::Version
60
- version: '0'
93
+ version: 1.9.3
61
94
  required_rubygems_version: !ruby/object:Gem::Requirement
62
95
  none: false
63
96
  requirements:
64
97
  - - ! '>='
65
98
  - !ruby/object:Gem::Version
66
99
  version: '0'
67
- requirements: []
100
+ requirements:
101
+ - Docker ~> 1.3.1
68
102
  rubyforge_project:
69
103
  rubygems_version: 1.8.23.2
70
104
  signing_key: