Top Level Namespace

Defined Under Namespace

Modules: Capistrano

Instance Method Summary collapse

Instance Method Details

#check_stayed_running(name) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
# File 'lib/deployinator/helpers.rb', line 136

def check_stayed_running(name)
  sleep 3
  unless container_is_running?(name)
    fatal "Container #{name} on #{fetch(:domain)} did not stay running more than 3 seconds"
    exit
  end
  if container_is_restarting?(name)
    fatal "Container #{name} on #{fetch(:domain)} is stuck restarting itself."
    exit
  end
end

#container_exists?(container_name) ⇒ Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/deployinator/helpers.rb', line 122

def container_exists?(container_name)
  test "bash", "-c", "\"docker", "inspect", container_name, "&>", "/dev/null\""
end

#container_is_restarting?(container_name) ⇒ Boolean

Returns:

  • (Boolean)


131
132
133
134
# File 'lib/deployinator/helpers.rb', line 131

def container_is_restarting?(container_name)
  test "[", "\"`docker", "inspect", "--format='{{.State.Restarting}}'",
    container_name, "2>&1`\"", "=", "\"true\"", "]"
end

#container_is_running?(container_name) ⇒ Boolean

Returns:

  • (Boolean)


126
127
128
129
# File 'lib/deployinator/helpers.rb', line 126

def container_is_running?(container_name)
  test "[", "\"`docker", "inspect", "--format='{{.State.Running}}'",
    "#{container_name} 2>&1`\"", "=", "\"true\"", "]"
end

#deploy_assets_cleanup(host) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
# File 'lib/deployinator/built-in.rb', line 190

def deploy_assets_cleanup(host)
  execute(
    "docker", "run", "--rm", "--tty",
    "-e", "RAILS_ENV=#{fetch(:rails_env)}",
    "-w", release_path,
    fetch(:deploy_custom_container_options),
    "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
    "--entrypoint", shared_path.join('bundle', 'bin', 'bundle'),
    fetch(:ruby_image_name), "exec", "rake", "assets:clean"
  )
end

#deploy_assets_precompile(host) ⇒ Object



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/deployinator/built-in.rb', line 173

def deploy_assets_precompile(host)
  execute(
    "docker", "run", "--rm", "--tty", "--user", fetch(:webserver_username),
    "-e", "APP_STAGE=#{fetch(:stage)}",
    "-e", "RAILS_ROOT=#{current_path}",
    "-w", release_path,
    "--volume", "/home:/home:rw",
    "--volume", "/etc/passwd:/etc/passwd:ro",
    "--volume", "/etc/group:/etc/group:ro",
    "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
    fetch(:deploy_custom_container_options),
    "--entrypoint", "/bin/bash",
    fetch(:ruby_image_name), "-c",
    "\"umask", "0007", "&&", "#{shared_path.join('bundle', 'bin', 'rake')}",
    "assets:precompile\""
  )
end

#deploy_bluepill_restart(host) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/deployinator/built-in.rb', line 89

def deploy_bluepill_restart(host)
  execute(
    "docker", "exec", "--tty",
    fetch(:ruby_container_name),
    shared_path.join('bundle', 'bin', 'bluepill'),
    fetch(:application), "restart"
  )
end

#deploy_bluepill_stop(host) ⇒ Object



97
98
99
100
101
102
103
104
# File 'lib/deployinator/built-in.rb', line 97

def deploy_bluepill_stop(host)
  execute(
    "docker", "exec", "--tty",
    fetch(:ruby_container_name),
    shared_path.join('bundle', 'bin', 'bluepill'),
    fetch(:application), "stop"
  )
end

#deploy_install_bundler(host) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/deployinator/built-in.rb', line 214

def deploy_install_bundler(host)
  execute(
    "docker", "run", "--rm", "--tty", "--user", fetch(:deployment_username),
    "-e", "GEM_HOME=#{shared_path.join('bundle')}",
    "-e", "GEM_PATH=#{shared_path.join('bundle')}",
    "-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
    "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
    "--volume", "/home:/home:rw",
    "--volume", "/etc/passwd:/etc/passwd:ro",
    "--volume", "/etc/group:/etc/group:ro",
    "--entrypoint", "/bin/bash",
    fetch(:ruby_image_name), "-c",
    "\"umask", "0007", "&&" "/usr/local/bin/gem", "install",
    "--install-dir", "#{shared_path.join('bundle')}",
    "--bindir", shared_path.join('bundle', 'bin'),
    "--no-ri", "--no-rdoc", "--quiet", "bundler", "-v'#{fetch(:bundler_version)}'\""
  )
end

#deploy_rails_console(host) ⇒ Object



138
139
140
141
142
143
144
145
146
147
# File 'lib/deployinator/built-in.rb', line 138

def deploy_rails_console(host)
  [
    "ssh", "-t", "#{host}", "\"docker", "exec", "--interactive", "--tty",
    fetch(:ruby_container_name),
    # "sudo", "-u", fetch(:webserver_username), TODO, make sure it works to add this line
    "bash", "-c", "'cd", current_path, "&&",
    shared_path.join('bundle', 'bin', 'rails'),
    "console", "#{fetch(:rails_env)}'\""
  ].join(' ')
end

#deploy_rails_console_print(host) ⇒ Object



148
149
150
151
152
153
154
155
156
# File 'lib/deployinator/built-in.rb', line 148

def deploy_rails_console_print(host)
  [
    "docker", "exec", "--interactive", "--tty",
    fetch(:ruby_container_name),
    "bash", "-c", "\"cd", current_path, "&&",
    shared_path.join('bundle', 'bin', 'rails'),
    "console", "#{fetch(:rails_env)}\""
  ].join(' ')
end

#deploy_rake_db_migrate(host) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/deployinator/built-in.rb', line 201

def deploy_rake_db_migrate(host)
  execute(
    "docker", "run", "--rm", "--tty",
    "-w", release_path,
    "-e", "APP_STAGE=#{fetch(:stage)}",
    "-e", "RAILS_ROOT=#{current_path}",
    "-e", "RAILS_ENV=#{fetch(:rails_env)}",
    fetch(:deploy_custom_container_options),
    "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
    "--entrypoint", shared_path.join('bundle', 'bin', 'rake'),
    fetch(:ruby_image_name), "db:migrate"
  )
end

#deploy_run_bluepill(host) ⇒ Object

# TODO: fix from_local, right now you have to copy-paste the set_scm method to your deploy.rb # Use ‘cap <stage> deploy from_local=true` to deploy your locally changed code # instead of the code in the git repo. You can also add –trace. # You can set include_dir and exclude_dir settings (from capistrano-scm-copy gem). # These will only apply when using the from_local=true option # set :include_dir, ’../.*‘ # set :exclude_dir, [“../.$”, “../..”, ’.././infrastructure’] def set_scm

if ENV['from_local']
  if "#{fetch(:stage)}" == "production"
    run_locally do
      fatal("You are trying to deploy to production using from_local, " +
        "this should pretty much never be done.")
    end
    ask :yes_no, "Are you positive you want to continue?"
    case fetch(:yes_no).chomp.downcase
    when "yes"
    when "no"
      exit
    else
      warn "Please enter 'yes' or 'no'"
      set_scm
    end
  end
  set :scm, :copy
else
  set :scm, :git
end

end set_scm



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/deployinator/built-in.rb', line 70

def deploy_run_bluepill(host)
  warn "Starting a new container named #{fetch(:ruby_container_name)} on #{host}"
  execute(
    "docker", "run", "--tty", "--detach",
    "--name", fetch(:ruby_container_name),
    "-e", "APP_STAGE=#{fetch(:stage)}",
    "-e", "RAILS_ROOT=#{current_path}",
    "-e", "GEM_HOME=#{shared_path.join('bundle')}",
    "-e", "GEM_PATH=#{shared_path.join('bundle')}",
    "-e", "BUNDLE_GEMFILE=#{current_path.join('Gemfile')}",
    "-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
    fetch(:deploy_custom_container_options),
    "--restart", "always", "--memory", "#{fetch(:ruby_container_max_mem_mb)}m",
    "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
    "--entrypoint", shared_path.join('bundle', 'bin', 'bluepill'),
    fetch(:ruby_image_name), "load",
    current_path.join('config', 'bluepill.rb')
  )
end

#deploy_run_bluepill_jobs(host) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/deployinator/built-in.rb', line 105

def deploy_run_bluepill_jobs(host)
  execute(
    "docker", "run", "--tty", "--detach",
    "-w", current_path,
    "--user", fetch(:webserver_username),
    "--name", fetch(:ruby_jobs_container_name),
    "-e", "APP_STAGE=#{fetch(:stage)}",
    "-e", "RAILS_ROOT=#{current_path}",
    "-e", "GEM_HOME=#{shared_path.join('bundle')}",
    "-e", "GEM_PATH=#{shared_path.join('bundle')}",
    "-e", "BUNDLE_GEMFILE=#{current_path.join('Gemfile')}",
    "-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
    fetch(:deploy_custom_container_options),
    "--restart", "always", "--memory", "#{fetch(:ruby_jobs_container_max_mem_mb)}m",
    "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
    "--entrypoint", shared_path.join('bundle', 'bin', 'rabid_jobs_tasker'),
    fetch(:ruby_image_name), "--rails_root", current_path,
    "--environment", fetch(:rails_env), "--pid", "#{fetch(:webserver_socket_path)}/jobs.pid", "--maxworkers", "3"
  )
end

#deploy_run_cadvisor(host) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/deployinator/built-in.rb', line 125

def deploy_run_cadvisor(host)
  execute(
    "docker", "run", "--detach",
    "--name", "cadvisor",
    "--volume", "/:/rootfs:ro",
    "--volume", "/var/run:/var/run:rw",
    "--volume", "/sys:/sys:ro",
    "--volume", "/var/lib/docker/:/var/lib/docker:ro",
    "--publish", "127.0.0.1:8080:8080",
    "--restart", "always",
    "google/cadvisor:latest"
  )
end

#deployment_user_setup(templates_path) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/deployinator/helpers.rb', line 35

def deployment_user_setup(templates_path)
  require 'erb'
  name = fetch(:deployment_username)
  unix_user_add(name) unless unix_user_exists?(name)
  execute "usermod", "-a", "-G", "sudo,docker,#{fetch(:webserver_username)}", name
  execute "mkdir", "-p", "/home/#{name}/.ssh"
  template_path = File.expand_path("./#{templates_path}/deployment_authorized_keys.erb")
  generated_config_file = ERB.new(File.new(template_path).read).result(binding)
  # upload! does not yet honor "as" and similar scoping methods
  upload! StringIO.new(generated_config_file), "/tmp/authorized_keys"
  execute "mv", "-b", "/tmp/authorized_keys", "/home/#{name}/.ssh/authorized_keys"
  execute "chown", "-R", "#{name}:#{name}", "/home/#{name}"
  execute "chmod", "700", "/home/#{name}/.ssh"
  execute "chmod", "600", "/home/#{name}/.ssh/authorized_keys"
end

#directory_exists?(dir) ⇒ Boolean

Returns:

  • (Boolean)


185
186
187
# File 'lib/deployinator/helpers.rb', line 185

def directory_exists?(dir)
  test "[", "-d", dir, "]"
end

#file_exists?(file) ⇒ Boolean

Returns:

  • (Boolean)


181
182
183
# File 'lib/deployinator/helpers.rb', line 181

def file_exists?(file)
  test "[", "-f", file, "]"
end

#files_in_directory?(dir) ⇒ Boolean

Returns:

  • (Boolean)


189
190
191
# File 'lib/deployinator/helpers.rb', line 189

def files_in_directory?(dir)
  test("[", "\"$(ls", "-A", "#{dir})\"", "]")
end

#localhost_port_responding?(port) ⇒ Boolean

Returns:

  • (Boolean)


160
161
162
163
# File 'lib/deployinator/helpers.rb', line 160

def localhost_port_responding?(port)
  test "nc", "127.0.0.1", port, "<", "/dev/null", ">", "/dev/null;",
    "[", "`echo", "$?`", "-eq", "0", "]"
end

#restart_container(name) ⇒ Object



154
155
156
157
158
# File 'lib/deployinator/helpers.rb', line 154

def restart_container(name)
  warn "Restarting a running container named #{name}"
  execute("docker", "restart", name)
  check_stayed_running(name)
end

#setup_file_permissionsObject

TODO when replacing this method with the new one, make sure the releases dir itself gets permissioned, just not it’s contents.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/deployinator/helpers.rb', line 52

def setup_file_permissions

  ignore_options = fetch(:ignore_permissions_dirs).collect do |dir|
    ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
  end
  ignore_options += ["-not", "-path", "\"#{fetch(:deploy_to)}/releases/*\""]
  chown_ignore_options = fetch(:webserver_owned_dirs).collect do |dir|
    ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
  end

  # chown webserver owned
  fetch(:webserver_owned_dirs).each do |dir|
    if directory_exists?(dir)
      execute "find", dir, ignore_options,
        '\(', "-not", "-user", fetch(:webserver_username), "-or",
        "-not", "-group", fetch(:webserver_username), '\)',
        "-print0", "|", "xargs", "--no-run-if-empty", "--null",
        "chown", "#{fetch(:webserver_username)}:#{fetch(:webserver_username)}"
    else
      execute "mkdir", "-p", dir
      execute "chown", "#{fetch(:webserver_username)}:#{fetch(:webserver_username)}", dir
    end
  end

  # chown
  execute "find", fetch(:deploy_to), ignore_options, chown_ignore_options,
    '\(', "-not", "-user", fetch(:deployment_username), "-or",
    "-not", "-group", fetch(:webserver_username), '\)',
    "-print0", "|", "xargs", "--no-run-if-empty", "--null",
    "chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}"

  # chmod executable
  fetch(:webserver_executable_dirs).each do |dir|
    if directory_exists?(dir)
      execute "find", dir, "-type", "f",
        "-not", "-perm", "0750",
        "-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "0750"
    # else # don't do this mkdir because it gets run as root and doesn't chown parent dirs
    #   execute "mkdir", "-p", dir
    #   execute "chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}", dir
    end
    ignore_options += ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
  end

  # chmod writable
  fetch(:webserver_writeable_dirs).each do |dir|
    if directory_exists?(dir)
      execute "find", "-L", dir, "-type", "d",
        "-not", "-perm", "2770",
        "-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "2770"
      execute "find", "-L", dir, "-type", "f",
        "-not", "-perm", "0660",
        "-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "0660"
    else
      execute "mkdir", "-p", dir
      execute "chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}", dir
      execute "chmod", "2770", dir
    end
    ignore_options += ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
  end

  # chmod
  execute "find", fetch(:deploy_to), "-type", "d", ignore_options,
    "-not", "-perm", "2750",
    "-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "2750"
  execute "find", fetch(:deploy_to), "-type", "f", ignore_options,
    "-not", "-perm", "0640",
    "-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "0640"
end

#sshkit_bundle_command_mapObject



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/deployinator/built-in.rb', line 157

def sshkit_bundle_command_map
  [
    "/usr/bin/env docker run --rm --tty",
    "--user", fetch(:deployment_username),
    "-e", "GEM_HOME=#{shared_path.join('bundle')}",
    "-e", "GEM_PATH=#{shared_path.join('bundle')}",
    "-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
    "--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
    "--volume", "$SSH_AUTH_SOCK:/ssh-agent:rw", "--env SSH_AUTH_SOCK=/ssh-agent",
    "--volume", "/home:/home:rw",
    "--volume", "/etc/passwd:/etc/passwd:ro",
    "--volume", "/etc/group:/etc/group:ro",
    "--entrypoint", "#{shared_path.join('bundle', 'bin', 'bundle')}",
    fetch(:ruby_image_name)
  ].join(' ')
end

#start_container(name) ⇒ Object



148
149
150
151
152
# File 'lib/deployinator/helpers.rb', line 148

def start_container(name)
  warn "Starting an existing but non-running container named #{name}"
  execute("docker", "start", name)
  check_stayed_running(name)
end

#unix_user_add(user) ⇒ Object



169
170
171
# File 'lib/deployinator/helpers.rb', line 169

def unix_user_add(user)
  execute "adduser", "--disabled-password", "--gecos", "\"\"", user
end

#unix_user_exists?(user) ⇒ Boolean

Returns:

  • (Boolean)


165
166
167
# File 'lib/deployinator/helpers.rb', line 165

def unix_user_exists?(user)
  test "bash", "-c", "\"id", user, "&>", "/dev/null\""
end

#unix_user_get_gid(user) ⇒ Object



177
178
179
# File 'lib/deployinator/helpers.rb', line 177

def unix_user_get_gid(user)
  capture("id", "-g", user).strip
end

#unix_user_get_uid(user) ⇒ Object



173
174
175
# File 'lib/deployinator/helpers.rb', line 173

def unix_user_get_uid(user)
  capture("id", "-u", user).strip
end