Current section
Files
Jump to
Current section
Files
lib/bottler/install.ex
require Logger, as: L
require Bottler.Helpers, as: H
alias SSHEx, as: S
defmodule Bottler.Install do
@moduledoc """
Functions to install an already shipped release on remote servers.
Actually running release is not touched. Next restart will run
the new release.
"""
@doc """
Install previously shipped release on remote servers, making it _current_
release.
Returns `{:ok, details}` when done, `{:error, details}` if anything fails.
"""
def install(config) do
:ssh.start # sometimes it's not already started at this point...
config[:servers] |> Keyword.values # each ip
|> Enum.map(fn(s) -> s ++ [ user: config[:remote_user] ] end) # add user
|> H.in_tasks( fn(args) -> on_server(args) end )
end
defp on_server(args) do
ip = args[:ip] |> to_char_list
user = args[:user] |> to_char_list
L.info "Installing #{Mix.Project.get!.project[:version]} on #{ip}..."
{:ok, conn} = :ssh.connect(ip, 22,
[{:user,user},{:silently_accept_hosts,true}], 5000)
place_files conn, user, ip
make_current conn, user, ip
cleanup_old_releases conn, user, ip
:ok
end
# Decompress release file, put it in place, and make needed movements
#
defp place_files(conn, user, ip) do
L.info "Settling files on #{ip}..."
vsn = Mix.Project.get!.project[:version]
app = Mix.Project.get!.project[:app]
path = '/home/#{user}/#{app}/'
S.cmd! conn, 'mkdir -p #{path}releases/#{vsn}'
S.cmd! conn, 'mkdir -p #{path}log'
S.cmd! conn, 'mkdir -p #{path}tmp'
{:ok, _, 0} = S.run conn,
'tar --directory #{path}releases/#{vsn}/ ' ++
'-xf /tmp/#{app}.tar.gz'
S.cmd! conn, 'ln -sfn #{path}tmp ' ++
'#{path}releases/#{vsn}/tmp'
S.cmd! conn, 'ln -sfn #{path}log ' ++
'#{path}releases/#{vsn}/log'
S.cmd! conn,
'ln -sfn #{path}releases/#{vsn}/releases/#{vsn} ' ++
'#{path}releases/#{vsn}/boot'
S.cmd! conn,
'ln -sfn #{path}releases/#{vsn}/lib/#{app}-#{vsn}/scripts ' ++
'#{path}releases/#{vsn}/scripts'
end
defp make_current(conn, user, ip) do
L.info "Marking release as current on #{ip}..."
app = Mix.Project.get!.project[:app]
vsn = Mix.Project.get!.project[:version]
{:ok, _, 0} = S.run conn,
'ln -sfn /home/#{user}/#{app}/releases/#{vsn} ' ++
' /home/#{user}/#{app}/current'
end
defp cleanup_old_releases(conn, user, ip) do
L.info "Cleaning up old releases on #{ip}..."
app = Mix.Project.get!.project[:app]
{:ok, res, 0} = S.run conn, 'ls -t /home/#{user}/#{app}/releases'
excess_releases = res |> String.split("\n") |> Enum.slice(5..-2)
for r <- excess_releases do
L.info "Cleaning up old #{r}..."
{:ok, _, 0} = S.run conn, 'rm -fr /home/#{user}/#{app}/releases/#{r}'
end
end
end