Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix IPv6 support and support listening to a specific IP #2226

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

tvogel
Copy link

@tvogel tvogel commented Oct 11, 2024

For running logflare on fly.io with their IPv6 based private networking, I had to fix/improve a few things. Please take a look and pick what you like!

(My first exposure to Elixir/Erlang, so thanks for that!)

Reorder build steps such that intermediate steps can more likely be reused,
in particular installed apt, npm and mix packages.
config/runtime.exs:
new variable PHX_HTTP_IP for specifying IP address to bind to;
Logflare.Repo,
:postgres_backend_adapter:
	set socket-options for IPv6;

SharedRepo,
ContextCache.Supervisor:
hand socket-options on;

update docs;
update .template.env;
config/runtime.exs Outdated Show resolved Hide resolved
config/runtime.exs Outdated Show resolved Hide resolved
mix.exs Outdated Show resolved Hide resolved
@Ziinc
Copy link
Contributor

Ziinc commented Oct 15, 2024

Thanks for the PR, looks like a good addition for self hosting setup

runtime.exs:
adapt logic from supabase/realtime:Realtime.Database.detect_ip_version/1;
use :inet.parse_address/1 instead of IP.from_string!/1;

shared_repo.ex:
apply code-review suggestion;
@tvogel tvogel requested a review from Ziinc October 18, 2024 23:10
Copy link
Contributor

@Ziinc Ziinc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the adjustments, was OOO. I can take over the postgres adaptor backend adjustments needed.

mix.exs Outdated Show resolved Hide resolved
Comment on lines +236 to +242
socket_options_for_url = fn url when is_binary(url) ->
case URI.parse(url) do
%URI{host: host} -> socket_options_for_host.(host)
_ -> raise "Failed to parse URL: #{inspect(url)}"
end
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
socket_options_for_url = fn url when is_binary(url) ->
case URI.parse(url) do
%URI{host: host} -> socket_options_for_host.(host)
_ -> raise "Failed to parse URL: #{inspect(url)}"
end
end
socket_options_for_url = fn
url when is_binary(url) ->
case URI.parse(url) do
%URI{host: host} -> socket_options_for_host.(host)
_ -> raise "Failed to parse URL: #{inspect(url)}"
end
_url -> nil
end

This will give an error without a fallback clause
Screenshot 2024-11-04 at 11 36 20 AM

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can also group all the anonymous functions together by moving this function up so that they are easier to maintain and grok.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I am an Elixir newbie, I don't fully understand the fallback-clause. Shouldn't the nil-case be excluded by the when is_binary() clause? Why can a fallback cover for it in this "overload"?

Comment on lines +7 to +22
detect_ip_version = fn host when is_binary(host) ->
host = String.to_charlist(host)

cond do
match?({:ok, _}, :inet6_tcp.getaddr(host)) -> {:ok, :inet6}
match?({:ok, _}, :inet.gethostbyname(host)) -> {:ok, :inet}
true -> {:error, :nxdomain}
end
end

socket_options_for_host = fn host when is_binary(host) ->
case detect_ip_version.(host) do
{:ok, ip_version} -> [ip_version]
{:error, reason} -> raise "Failed to detect IP version: #{reason}"
end
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
detect_ip_version = fn host when is_binary(host) ->
host = String.to_charlist(host)
cond do
match?({:ok, _}, :inet6_tcp.getaddr(host)) -> {:ok, :inet6}
match?({:ok, _}, :inet.gethostbyname(host)) -> {:ok, :inet}
true -> {:error, :nxdomain}
end
end
socket_options_for_host = fn host when is_binary(host) ->
case detect_ip_version.(host) do
{:ok, ip_version} -> [ip_version]
{:error, reason} -> raise "Failed to detect IP version: #{reason}"
end
end
detect_ip_version = fn host ->
host = String.to_charlist(host)
cond do
match?({:ok, _}, :inet6_tcp.getaddr(host)) -> {:ok, :inet6}
match?({:ok, _}, :inet.gethostbyname(host)) -> {:ok, :inet}
true -> {:error, :nxdomain}
end
end
socket_options_for_host = fn
host when is_binary(host) ->
case detect_ip_version.(host) do
{:ok, ip_version} -> [ip_version]
{:error, reason} -> raise "Failed to detect IP version: #{reason}"
end
_host -> []
end

Needs fallback option. nested anon function then doesn't need the guard anymore if we do the check at the top level.
Screenshot 2024-11-04 at 11 36 20 AM

@@ -45,6 +45,8 @@ defmodule Logflare.Backends.Adaptor.PostgresAdaptor.SharedRepo do
opts ++ fields
end

opts = opts ++ [socket_options: config[:socket_options]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tvogel this shouldn't use the global config actually, we can add this in temporarily but it should be part of the backend's config instead. This would require adjusting the self-hosted backend config building.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why shouldn't it use the socket_options determined for the respective DB_HOSTNAME which it determines in

          Map.take(config, [:username, :password, :hostname, :database, :port, :ssl])

? In which cases would you use different options?

@@ -45,6 +45,8 @@ defmodule Logflare.Backends.Adaptor.PostgresAdaptor.SharedRepo do
opts ++ fields
end

opts = opts ++ [socket_options: config[:socket_options]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
opts = opts ++ [socket_options: config[:socket_options]]
if Logflare.SingleTenant.single_tenant?() do
opts = opts ++ [socket_options: config[:socket_options]]
else
opts
end

lets do itonly for single tenant for now

Co-authored-by: Ziinc <Ziinc@users.noreply.github.com>
@tvogel
Copy link
Author

tvogel commented Nov 4, 2024

(Sorry for the late replies - I was traveling.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants