Clone
defmodule Deploy.SSH do
@moduledoc """
Shared SSH utilities for deployment mix tasks.
Provides ssh_exec/2, scp_upload/3, and get_deploy_config/1
used by Mix.Tasks.Deploy, Deploy.Service, and Deploy.Nginx.
"""
require Logger
@doc """
Load and merge deployment config for the given environment.
Returns a map with all config keys merged from base + env.
"""
def get_deploy_config(env) do
base_config = Application.get_all_env(:deploy)
env_config = Keyword.get(base_config, env, [])
if env_config == [] do
Logger.error("No configuration found for environment: #{env}")
exit(1)
end
app_name = Keyword.get(base_config, :app_name) || (Mix.Project.config()[:app] |> to_string())
base_config
|> Keyword.delete(:production)
|> Keyword.delete(:staging)
|> Keyword.merge(env_config)
|> Keyword.put(:env, env)
|> Keyword.put(:app_name, app_name)
|> Map.new()
end
@doc """
Execute a command on the remote server via SSH.
Returns {output, exit_code}.
"""
def ssh_exec(config, command) do
port_opt = if config.port && config.port != 22, do: "-p #{config.port}", else: ""
ssh_command = """
ssh -T -A -o ConnectTimeout=10 #{port_opt} \
#{config.user}@#{config.domain} '#{command}'
"""
Logger.debug("SSH command: #{inspect(ssh_command)}")
Logger.debug("Remote command: #{inspect(command)}")
System.cmd("bash", ["-c", ssh_command], stderr_to_stdout: true)
end
@doc """
Upload a local file to the remote server via SCP.
Returns {output, exit_code}.
"""
def scp_upload(config, local_file, remote_file) do
port_opt = if config.port && config.port != 22, do: "-P #{config.port}", else: ""
scp_command = """
scp #{port_opt} #{local_file} \
#{config.user}@#{config.domain}:#{remote_file}
"""
System.cmd("bash", ["-c", scp_command], stderr_to_stdout: true)
end
end