Skip to content
This repository was archived by the owner on Dec 24, 2025. It is now read-only.

Commit f899518

Browse files
committed
Expose ports
1 parent a553adc commit f899518

7 files changed

Lines changed: 147 additions & 35 deletions

File tree

.formatter.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ locals_without_parens = [
55
standalone: 1,
66
app: 2,
77
from_docker_image: 1,
8-
volume: 2
8+
volume: 2,
9+
expose_port: 2
910
]
1011

1112
[

lib/makina/docker.ex

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ defmodule Makina.Docker do
1212
docker(server, "run", [
1313
"-d",
1414
"--restart",
15-
"always",
15+
"unless-stopped",
1616
name(app),
1717
labels(app),
1818
volumes(app),
1919
envs(app),
20+
ports(app),
2021
image(app),
2122

2223
# should always be the last one as it provides additional parameters
@@ -92,6 +93,13 @@ defmodule Makina.Docker do
9293
end)
9394
end
9495

96+
defp ports(%Application{} = app) do
97+
app.exposed_ports
98+
|> Enum.flat_map(fn p ->
99+
["--port", "#{p.internal}:#{p.external}"]
100+
end)
101+
end
102+
95103
defp command(%Application{} = app) do
96104
app.__docker__.command
97105
end

lib/makina/dsl/app.ex

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ defmodule Makina.DSL.App do
3535
end
3636
end
3737

38+
@doc """
39+
Mounts a volume to the given app.
40+
41+
## Usage
42+
```elixir
43+
makina "example" do
44+
app name: "foo" do
45+
46+
volume "source", "destination"
47+
48+
end
49+
end
50+
```
51+
"""
3852
defmacro volume(source, destination) when is_binary(source) and is_binary(destination) do
3953
quote bind_quoted: [source: source, destination: destination] do
4054
@current_application Application.put_volume(@current_application,
@@ -43,4 +57,29 @@ defmodule Makina.DSL.App do
4357
)
4458
end
4559
end
60+
61+
@doc """
62+
Exposes a port on the given app
63+
64+
## Usage
65+
```elixir
66+
makina "example" do
67+
app name: "foo" do
68+
69+
# expose_port <internal port>, <external port>
70+
expose_port 8080, 80
71+
72+
end
73+
end
74+
```
75+
"""
76+
defmacro expose_port(internal, external)
77+
when is_number(internal) and is_number(external) do
78+
quote bind_quoted: [internal: internal, external: external] do
79+
@current_application Application.put_exposed_port(@current_application,
80+
internal: internal,
81+
external: external
82+
)
83+
end
84+
end
4685
end

lib/makina/models/application.ex

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ defmodule Makina.Models.Application do
3232

3333
alias Makina.Models.Internal
3434

35-
@hashable_keys ~w[name docker_image env_vars volumes]a
35+
@hashable_keys ~w[name docker_image env_vars volumes exposed_ports]a
3636

3737
@derive {JSON.Encoder, []}
3838
defstruct __hash__: nil,
@@ -44,7 +44,8 @@ defmodule Makina.Models.Application do
4444
name: nil,
4545
docker_image: nil,
4646
volumes: [],
47-
env_vars: []
47+
env_vars: [],
48+
exposed_ports: []
4849

4950
def new(opts) do
5051
app = struct(__MODULE__, opts)
@@ -68,6 +69,13 @@ defmodule Makina.Models.Application do
6869
set_private(app, :__hash__, hash(app))
6970
end
7071

72+
def put_exposed_port(%__MODULE__{} = app, port) when is_list(port) do
73+
port = Enum.into(port, %{})
74+
app = %__MODULE__{app | exposed_ports: [port | app.exposed_ports]}
75+
76+
set_private(app, :__hash__, hash(app))
77+
end
78+
7179
def set_docker_image(%__MODULE__{} = app, image) when is_list(image) do
7280
image = Enum.into(image, %{})
7381
app = %__MODULE__{app | docker_image: image}

test/makina/dsl_test.exs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,30 @@ defmodule Makina.DSLTest do
125125
assert volume == %{source: "foo", destination: "/app/data"}
126126
end
127127

128+
test "allow exposed port to be specified" do
129+
import DSL
130+
131+
term =
132+
makina "app-test-specify-port" do
133+
standalone do
134+
app name: "test" do
135+
expose_port 8080, 80
136+
end
137+
end
138+
end
139+
140+
module = elem(term, 1)
141+
context = module.collect_context()
142+
143+
app = List.first(context.standalone_applications)
144+
145+
assert is_list(app.exposed_ports)
146+
147+
port = List.first(app.exposed_ports)
148+
149+
assert port == %{internal: 8080, external: 80}
150+
end
151+
128152
test "raises if app block is not invoked correctly" do
129153
import DSL
130154

test/makina/models/application_test.exs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,22 @@ defmodule Makina.Models.ApplicationTest do
6464
end
6565
end
6666

67+
describe "put_exposed_port/2" do
68+
test "adds an exposed port pair to the list" do
69+
params = [name: "foo"]
70+
71+
app = Application.new(params)
72+
init_hash = app.__hash__
73+
74+
assert app.env_vars == []
75+
76+
app = app |> Application.put_exposed_port(internal: 80, external: 8080)
77+
78+
assert app.exposed_ports == [%{internal: 80, external: 8080}]
79+
assert app.__hash__ != init_hash
80+
end
81+
end
82+
6783
describe "set_private/3" do
6884
test "sets private fields" do
6985
params = [name: "foo"]

test/makina/models/docker_test.exs

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ defmodule Makina.Models.DockerTest do
4141
assert cmd.server == server
4242

4343
assert cmd.cmd ==
44-
"docker run -d --restart always --name foo --label org.makina.app.hash=#{app.__hash__} nginx:1.16"
44+
"docker run -d --restart unless-stopped --name foo --label org.makina.app.hash=#{app.__hash__} nginx:1.16"
4545
end
4646

4747
test "contains volumes" do
@@ -57,7 +57,7 @@ defmodule Makina.Models.DockerTest do
5757
cmd = Docker.run(server, app)
5858

5959
assert cmd.cmd ==
60-
"docker run -d --restart always --name foo --label org.makina.app.hash=#{app.__hash__} --volume foo:/app/data nginx:1.16"
60+
"docker run -d --restart unless-stopped --name foo --label org.makina.app.hash=#{app.__hash__} --volume foo:/app/data nginx:1.16"
6161
end
6262

6363
test "contains environment variables" do
@@ -73,36 +73,52 @@ defmodule Makina.Models.DockerTest do
7373
cmd = Docker.run(server, app)
7474

7575
assert cmd.cmd ==
76-
"docker run -d --restart always --name foo --label org.makina.app.hash=#{app.__hash__} --env ENV=prod nginx:1.16"
76+
"docker run -d --restart unless-stopped --name foo --label org.makina.app.hash=#{app.__hash__} --env ENV=prod nginx:1.16"
7777
end
78-
end
7978

80-
test "contains command arguments" do
81-
server =
82-
Server.new(host: "example.com")
83-
|> Server.put_private(:conn_ref, self())
84-
85-
app =
86-
Application.new(name: "foo")
87-
|> Application.set_docker_image(name: "traefik", tag: "v3.3")
88-
|> Application.put_volume(
89-
source: "/var/run/docker.sock",
90-
destination: "/var/run/docker.sock"
91-
)
92-
93-
app =
94-
app
95-
|> Application.set_private(:__docker__, %{
96-
app.__docker__
97-
| command: [
98-
"--api.insecure=true",
99-
"--providers.docker"
100-
]
101-
})
102-
103-
cmd = Docker.run(server, app)
104-
105-
assert cmd.cmd ==
106-
"docker run -d --restart always --name foo --label org.makina.app.hash=#{app.__hash__} --volume /var/run/docker.sock:/var/run/docker.sock traefik:v3.3 --api.insecure=true --providers.docker"
79+
test "contains command arguments" do
80+
server =
81+
Server.new(host: "example.com")
82+
|> Server.put_private(:conn_ref, self())
83+
84+
app =
85+
Application.new(name: "foo")
86+
|> Application.set_docker_image(name: "traefik", tag: "v3.3")
87+
|> Application.put_volume(
88+
source: "/var/run/docker.sock",
89+
destination: "/var/run/docker.sock"
90+
)
91+
92+
app =
93+
app
94+
|> Application.set_private(:__docker__, %{
95+
app.__docker__
96+
| command: [
97+
"--api.insecure=true",
98+
"--providers.docker"
99+
]
100+
})
101+
102+
cmd = Docker.run(server, app)
103+
104+
assert cmd.cmd ==
105+
"docker run -d --restart unless-stopped --name foo --label org.makina.app.hash=#{app.__hash__} --volume /var/run/docker.sock:/var/run/docker.sock traefik:v3.3 --api.insecure=true --providers.docker"
106+
end
107+
108+
test "contains exposed ports" do
109+
server =
110+
Server.new(host: "example.com")
111+
|> Server.put_private(:conn_ref, self())
112+
113+
app =
114+
Application.new(name: "foo")
115+
|> Application.set_docker_image(name: "nginx", tag: "1.16")
116+
|> Application.put_exposed_port(internal: 80, external: 80)
117+
118+
cmd = Docker.run(server, app)
119+
120+
assert cmd.cmd ==
121+
"docker run -d --restart unless-stopped --name foo --label org.makina.app.hash=#{app.__hash__} --port 80:80 nginx:1.16"
122+
end
107123
end
108124
end

0 commit comments

Comments
 (0)