Skip to content

Commit

Permalink
Merge pull request #107 from upmaru/feature/merge-hosts-when-setting-…
Browse files Browse the repository at this point in the history
…up-routing

Setup merging for hosts
  • Loading branch information
zacksiri authored Dec 23, 2024
2 parents a778f51 + 8160065 commit aedce2c
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 14 deletions.
34 changes: 31 additions & 3 deletions lib/uplink/clients/caddy/config/builder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,15 @@ defmodule Uplink.Clients.Caddy.Config.Builder do
) do
main_routing = Map.get(metadata.main_port, :routing)

main_paths =
main_routing_hosts =
if main_routing do
main_routing.hosts
else
[]
end

main_paths =
if main_routing && main_routing.paths != [] do
main_routing.paths
else
["*"]
Expand Down Expand Up @@ -187,11 +194,17 @@ defmodule Uplink.Clients.Caddy.Config.Builder do
}
end)

main_hosts =
metadata.hosts
|> Enum.concat(main_routing_hosts)
|> Enum.uniq()
|> Enum.sort()

main_route = %{
group: main_group,
match: [
%{
host: metadata.hosts,
host: main_hosts,
path: main_paths
}
],
Expand Down Expand Up @@ -233,8 +246,23 @@ defmodule Uplink.Clients.Caddy.Config.Builder do

routing = Map.get(port, :routing)

paths =
routing_hosts =
if routing do
Enum.map(routing.hosts, fn host ->
port.slug <> "." <> host
end)
else
[]
end

hosts =
hosts
|> Enum.concat(routing_hosts)
|> Enum.uniq()
|> Enum.sort()

paths =
if routing && routing.paths != [] do
routing.paths
else
["*"]
Expand Down
3 changes: 2 additions & 1 deletion lib/uplink/packages/metadata/port.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ defmodule Uplink.Packages.Metadata.Port do

embeds_one :routing, Routing, primary_key: false do
field :router_id, :integer
field :hosts, {:array, :string}, default: []
field :paths, {:array, :string}, default: ["*"]
end
end
Expand All @@ -23,7 +24,7 @@ defmodule Uplink.Packages.Metadata.Port do

defp routing_changeset(routing, params) do
routing
|> cast(params, [:router_id, :paths])
|> cast(params, [:router_id, :hosts, :paths])
|> validate_required([:router_id, :paths])
end
end
8 changes: 7 additions & 1 deletion test/scenarios/deployment.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@ defmodule Uplink.Scenarios.Deployment do
"target" => 4000,
"routing" => %{
"router_id" => 1,
"hosts" => ["another.com", "something.com"],
"paths" => ["/configure*"]
}
},
"ports" => [
%{
"slug" => "grpc",
"source" => 49153,
"target" => 6000
"target" => 6000,
"routing" => %{
"router_id" => 1,
"hosts" => ["another.com", "something.com"],
"paths" => ["/*"]
}
}
],
"hosts" => ["something.com"],
Expand Down
162 changes: 153 additions & 9 deletions test/uplink/clients/caddy/config/builder_test.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
defmodule Uplink.Clients.Caddy.Config.BuilderTest do
use ExUnit.Case

alias Uplink.Members
alias Uplink.Packages
alias Uplink.Secret
alias Uplink.Cache

alias Uplink.Packages.Metadata

import Uplink.Scenarios.Deployment

setup [:setup_endpoints, :setup_base]
Expand Down Expand Up @@ -66,36 +73,173 @@ defmodule Uplink.Clients.Caddy.Config.BuilderTest do
"provider" => %{"api_token" => "something", "name" => "cloudflare"}
} = dns

assert %{routes: [first_route, second_route, third_route]} = server
assert %{routes: routes} = server

routes = Enum.sort(routes)

[first_route, second_route, third_route] = routes

assert %{handle: [handle], match: [match]} = first_route
assert %{handle: [second_handle], match: [second_match]} = second_route
assert %{handle: [third_handle], match: [third_match]} = third_route

assert match.host == ["another.com", "something.com"]
assert match.path == ["/configure*"]

assert third_match.path == ["*"]
assert second_match.path == ["/*"]

assert second_match.path == ["/how-to*"]
assert third_match.path == ["/how-to*"]

assert "grpc.something.com" in third_match.host
assert "grpc.something.com" in second_match.host
assert "grpc.another.com" in second_match.host

[third_upstream] = third_handle.upstreams
[second_upstream] = second_handle.upstreams

assert third_upstream.dial =~ "6000"
assert second_upstream.dial =~ "6000"

assert %{handler: "reverse_proxy"} = handle
assert %{host: _hosts} = match

[second_upstream] = second_handle.upstreams
[third_upstream] = third_handle.upstreams

assert %{protocol: "http", tls: %{}} = second_handle.transport
assert %{protocol: "http", tls: %{}} = third_handle.transport

assert second_upstream.dial == "proxy.webflow.com:80"
assert third_upstream.dial == "proxy.webflow.com:80"

assert %{identity: identity} = admin
assert %{identifiers: ["127.0.0.1"]} = identity

assert %{module: "s3"} = storage
end

describe "when routing is nil" do
setup do
deployment_params = %{
"hash" => "a-different-hash",
"archive_url" => "http://localhost/archives/packages.zip",
"stack" => "alpine/3.14",
"channel" => "develop",
"metadata" => %{
"id" => 1,
"slug" => "uplink-web",
"main_port" => %{
"slug" => "web",
"source" => 49152,
"target" => 4000
},
"ports" => [
%{
"slug" => "grpc",
"source" => 49153,
"target" => 6000
}
],
"hosts" => ["something.com"],
"variables" => [
%{"key" => "SOMETHING", "value" => "blah"}
],
"channel" => %{
"slug" => "develop",
"package" => %{
"slug" => "something-1640927800",
"credential" => %{
"public_key" => "public_key"
},
"organization" => %{
"slug" => "upmaru"
}
}
},
"instances" => [
%{
"id" => 1,
"slug" => "something-1",
"node" => %{
"slug" => "some-node"
}
}
]
}
}

{:ok, actor} =
Members.get_or_create_actor(%{
"identifier" => "zacksiri",
"provider" => "instellar",
"id" => "1"
})

metadata = Map.get(deployment_params, "metadata")

{:ok, metadata} = Packages.parse_metadata(metadata)

app =
metadata
|> Metadata.app_slug()
|> Packages.get_or_create_app()

{:ok, deployment} =
Packages.get_or_create_deployment(app, deployment_params)

{:ok, %{resource: preparing_deployment}} =
Packages.transition_deployment_with(deployment, actor, "prepare")

{:ok, %{resource: deployment}} =
Packages.transition_deployment_with(
preparing_deployment,
actor,
"complete"
)

{:ok, install} =
Packages.create_install(deployment, %{
"installation_id" => 1,
"deployment" => deployment_params
})

signature = Secret.Signature.compute_signature(deployment.hash)

Cache.put(
{:deployment, signature, install.instellar_installation_id},
metadata
)

{:ok, %{resource: validating_install}} =
Packages.transition_install_with(install, actor, "validate")

{:ok, %{resource: _executing_install}} =
Packages.transition_install_with(validating_install, actor, "execute")

:ok
end

test "render port when routing is nil correctly" do
assert %{apps: apps} = Uplink.Clients.Caddy.build_new_config()

assert %{http: %{servers: %{"uplink" => server}}} = apps

assert %{routes: routes} = server

routes = Enum.sort(routes)

[first_route, second_route] = routes

assert %{handle: [handle], match: [match]} = first_route
assert %{handle: [second_handle], match: [second_match]} = second_route

assert match.host == ["something.com"]
assert match.path == ["*"]

assert second_match.path == ["*"]

assert "grpc.something.com" in second_match.host

[second_upstream] = second_handle.upstreams

assert second_upstream.dial =~ "6000"

assert %{handler: "reverse_proxy"} = handle
assert %{host: _hosts} = match
end
end
end

0 comments on commit aedce2c

Please sign in to comment.