Current section

Files

Jump to
testcontainers lib connection connection.ex
Raw

lib/connection/connection.ex

# SPDX-License-Identifier: MIT
defmodule Testcontainers.Connection do
@moduledoc false
require Logger
alias DockerEngineAPI.Connection
alias Testcontainers.Constants
alias Testcontainers.DockerHostFromEnvStrategy
alias Testcontainers.DockerHostFromPropertiesStrategy
alias Testcontainers.DockerHostStrategyEvaluator
alias Testcontainers.DockerSocketPathStrategy
alias Testcontainers.DockerUrl
@timeout 300_000
def get_connection(options \\ []) do
{docker_host_url, docker_host} =
get_docker_host_url() |> tap(&Logger.info("Docker host: #{inspect(&1, pretty: false)}"))
options =
Keyword.merge(options,
base_url: docker_host_url,
recv_timeout: @timeout,
user_agent: Constants.user_agent()
)
options = maybe_add_tls_options(options, docker_host_url)
{Connection.new(options), docker_host_url, docker_host}
end
@doc """
Builds the list of `:ssl_options` for a TLS-secured Docker daemon.
Loads `ca.pem`, `cert.pem` and `key.pem` from `DOCKER_CERT_PATH`
(falling back to `~/.docker`). Missing files are skipped with a debug log.
When `DOCKER_TLS_VERIFY` is truthy, `verify: :verify_peer` is used; otherwise
`verify: :verify_none` with a warning log.
"""
def build_ssl_options do
cert_dir = cert_dir()
ssl_options = [verify: verify_mode()]
ssl_options
|> maybe_put_file(:cacertfile, Path.join(cert_dir, "ca.pem"))
|> maybe_put_file(:certfile, Path.join(cert_dir, "cert.pem"))
|> maybe_put_file(:keyfile, Path.join(cert_dir, "key.pem"))
end
defp cert_dir do
case System.get_env("DOCKER_CERT_PATH") do
nil -> Path.expand("~/.docker")
"" -> Path.expand("~/.docker")
path -> path
end
end
defp verify_mode do
if DockerUrl.tls_verify?() do
:verify_peer
else
Logger.warning(
"Docker TLS connection without DOCKER_TLS_VERIFY; peer certificate will NOT be verified"
)
:verify_none
end
end
defp maybe_put_file(opts, key, path) do
if File.exists?(path) do
Keyword.put(opts, key, path)
else
Logger.debug("Docker TLS cert file #{path} not found; skipping #{key}")
opts
end
end
defp maybe_add_tls_options(options, url) do
if DockerUrl.https?(url) do
ssl_options = build_ssl_options()
adapter_opts = [
recv_timeout: Keyword.get(options, :recv_timeout, @timeout),
ssl_options: ssl_options
]
Keyword.put(options, :adapter, {Tesla.Adapter.Hackney, adapter_opts})
else
options
end
end
defp get_docker_host_url do
case get_docker_host() do
{:ok, docker_host} ->
{DockerUrl.construct(docker_host), docker_host}
{:error, error} ->
exit(error)
end
end
defp get_docker_host do
strategies = [
%DockerHostFromPropertiesStrategy{key: "tc.host"},
%DockerHostFromPropertiesStrategy{key: "docker.host"},
%DockerHostFromEnvStrategy{},
%DockerSocketPathStrategy{}
]
DockerHostStrategyEvaluator.run_strategies(strategies, [])
end
end