Skip to content

Commit

Permalink
Improve PG unix sockets configuration (#4202)
Browse files Browse the repository at this point in the history
* improve pg unix sockets configuration

* changelog

* don't use test env in config tests
  • Loading branch information
ruslandoga committed Jul 15, 2024
1 parent 8a77968 commit b988364
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ All notable changes to this project will be documented in this file.
### Removed
- Deprecate `ECTO_IPV6` and `ECTO_CH_IPV6` env vars in CE plausible/analytics#4245
- Remove support for importing data from no longer available Universal Analytics
- Soft-deprecate `DATABASE_SOCKET_DIR` plausible/analytics#4202

### Changed
- Support Unix sockets in `DATABASE_URL` plausible/analytics#4202

- Realtime and hourly graphs now show visits lasting their whole duration instead when specific events occur
- Increase hourly request limit for API keys in CE from 600 to 1000000 (practically removing the limit) plausible/analytics#4200
Expand Down
63 changes: 47 additions & 16 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,6 @@ case secret_key_base do
nil
end

db_url =
get_var_from_path_or_env(
config_dir,
"DATABASE_URL",
"postgres://postgres:postgres@plausible_db:5432/plausible_db"
)

db_socket_dir = get_var_from_path_or_env(config_dir, "DATABASE_SOCKET_DIR")

super_admin_user_ids =
get_var_from_path_or_env(config_dir, "ADMIN_USER_IDS", "")
|> String.split(",")
Expand Down Expand Up @@ -333,7 +324,7 @@ config :plausible, PlausibleWeb.Endpoint,
websocket_url: websocket_url,
secure_cookie: secure_cookie

maybe_ipv6 =
db_maybe_ipv6 =
if get_var_from_path_or_env(config_dir, "ECTO_IPV6") do
if config_env() in [:ce, :ce_dev, :ce_test] do
Logger.warning(
Expand All @@ -346,23 +337,63 @@ maybe_ipv6 =
[]
end

db_url =
get_var_from_path_or_env(
config_dir,
"DATABASE_URL",
"postgres://postgres:postgres@plausible_db:5432/plausible_db"
)

if db_socket_dir = get_var_from_path_or_env(config_dir, "DATABASE_SOCKET_DIR") do
Logger.warning("""
DATABASE_SOCKET_DIR is deprecated, please use DATABASE_URL instead:
DATABASE_URL=postgresql://postgres:postgres@#{URI.encode_www_form(db_socket_dir)}/plausible_db
or
DATABASE_URL=postgresql:///plausible_db?host=#{db_socket_dir}"
""")
end

db_cacertfile = get_var_from_path_or_env(config_dir, "DATABASE_CACERTFILE", CAStore.file_path())
%URI{host: db_host} = db_uri = URI.parse(db_url)
db_socket_dir? = String.starts_with?(db_host, "%2F") or db_host == ""

if db_socket_dir? do
[database] = String.split(db_uri.path, "/", trim: true)

socket_dir =
if db_host == "" do
db_host = (db_uri.query || "") |> URI.decode_query() |> Map.get("host")
db_host || raise ArgumentError, "DATABASE_URL=#{db_url} doesn't include host info"
else
URI.decode_www_form(db_host)
end

if is_nil(db_socket_dir) do
config :plausible, Plausible.Repo,
socket_dir: socket_dir,
database: database

if userinfo = db_uri.userinfo do
[username, password] = String.split(userinfo, ":")

config :plausible, Plausible.Repo,
username: username,
password: password
end
else
config :plausible, Plausible.Repo,
url: db_url,
socket_options: maybe_ipv6,
socket_options: db_maybe_ipv6,
ssl_opts: [
cacertfile: db_cacertfile,
verify: :verify_peer,
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
]
else
config :plausible, Plausible.Repo,
socket_dir: db_socket_dir,
database: get_var_from_path_or_env(config_dir, "DATABASE_NAME", "plausible")
end

sentry_app_version = runtime_metadata[:version] || app_version
Expand Down
68 changes: 68 additions & 0 deletions test/plausible/config_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,74 @@ defmodule Plausible.ConfigTest do
end
end

describe "postgres" do
test "default" do
env = [{"DATABASE_URL", nil}]
config = runtime_config(env)

assert get_in(config, [:plausible, Plausible.Repo]) == [
url: "postgres://postgres:postgres@plausible_db:5432/plausible_db",
socket_options: [],
ssl_opts: [
cacertfile: CAStore.file_path(),
verify: :verify_peer,
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
]
]
end

test "socket_dir in hostname" do
env = [{"DATABASE_URL", "postgresql://postgres:postgres@%2Frun%2Fpostgresql/plausible_db"}]
config = runtime_config(env)

assert get_in(config, [:plausible, Plausible.Repo]) == [
socket_dir: "/run/postgresql",
database: "plausible_db",
username: "postgres",
password: "postgres"
]
end

test "socket_dir in query" do
env = [{"DATABASE_URL", "postgresql:///plausible_db?host=/run/postgresql"}]
config = runtime_config(env)

assert get_in(config, [:plausible, Plausible.Repo]) == [
socket_dir: "/run/postgresql",
database: "plausible_db"
]
end

test "socket_dir missing" do
env = [{"DATABASE_URL", "postgresql:///plausible_db"}]
assert_raise ArgumentError, ~r/doesn't include host info/, fn -> runtime_config(env) end
end

test "custom URL" do
env = [
{"DATABASE_URL",
"postgresql://your_username:[email protected]:25060/defaultdb"}
]

config = runtime_config(env)

assert get_in(config, [:plausible, Plausible.Repo]) == [
url:
"postgresql://your_username:[email protected]:25060/defaultdb",
socket_options: [],
ssl_opts: [
cacertfile: CAStore.file_path(),
verify: :verify_peer,
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
]
]
end
end

describe "extra config" do
test "no-op when no extra path is set" do
put_system_env_undo({"EXTRA_CONFIG_PATH", nil})
Expand Down

0 comments on commit b988364

Please sign in to comment.