/
docker_compose.ex
225 lines (187 loc) · 6.43 KB
/
docker_compose.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
defmodule DockerCompose do
@moduledoc """
Docker Compose CLI
Uses `docker-compose` executable, it must be installed and working.
"""
@type exit_code :: non_neg_integer
@type output :: Collectable.t()
@doc """
docker-compose up
The command is executed in detached mode, result is returned after the whole command finishes,
which might take a while if the images need to be pulled.
## Options
- `compose_path: path` - path to the compose if not in the standard location
- `project_name: name` - compose project name
- `force_recreate: true` - if true all specified services are forcefully recreated
- `remove_orphans: true` - if true orphaned containers are removed
- `service: name` - name of the service that should be started, can be specified multiple times
to start multiple services. If it's not specified at all then all services are started.
- `compatibility: true` - if true, runs compose in backward compatibility mode
- `quiet_pull: true` - if true, pull without printing progress information
"""
@spec up(Keyword.t()) :: {:ok, output} | {:error, exit_code, output}
def up(opts) do
args =
[
compose_opts(opts),
"up",
up_opts(opts),
["-d", "--no-color" | service_opts(opts)]
]
|> List.flatten()
args
|> execute(opts)
|> result()
end
@doc """
docker-compose down
## Options
- `compose_path: path` - path to the compose if not in the standard location
- `project_name: name` - compose project name
- `remove_orphans: true` - if true orphaned containers are removed
- `compatibility: true` - if true, runs compose in backward compatibility mode
## Result
The function returns either `{:ok, summary}` if the request is successful or `{:error, exit_code,
summary}`. The exit code is the exit code of the docker-compose process that failed.
Summary is a map with
- `stopped_containers` - which containers were stopped
- `removed_containers` - which containers were removed
- `removed_networks` - which networks were removed
- `removed_orphan_containers` - which containers were removed if `remove_orphans: true` is
specified
"""
@spec down(Keyword.t()) :: {:ok, output} | {:error, exit_code, output}
def down(opts) do
args =
[
compose_opts(opts),
"down",
down_opts(opts)
]
|> List.flatten()
args
|> execute(opts)
|> result()
end
# OPTS
# - service - optional, by default all
@doc """
docker-compose restart
## Options
- `compose_path: path` - path to the compose if not in the standard location
- `project_name: name` - compose project name
- `service: name` - name of the service to be restarted, can be specified multiple times to
restart multiple services at once. If not specified at all then all services are restarted.
- `compatibility: true` - if true, runs compose in backward compatibility mode
"""
@spec restart(Keyword.t()) :: {:ok, output} | {:error, exit_code, output}
def restart(opts) do
args =
[
compose_opts(opts),
"restart",
service_opts(opts)
]
|> List.flatten()
args
|> execute(opts)
|> result()
end
@doc """
docker-compose stop
## Options
- `compose_path: path` - path to the compose if not in the standard location
- `project_name: name` - compose project name
- `service: name` - name of the service to be stopped, can be specified multiple times to stop
multiple services at once. If not specified at all then all services are stopped.
- `compatibility: true` - if true, runs compose in backward compatibility mode
"""
@spec stop(Keyword.t()) :: {:ok, output} | {:error, exit_code, output}
def stop(opts) do
args =
[
compose_opts(opts),
"stop",
service_opts(opts)
]
|> List.flatten()
args
|> execute(opts)
|> result()
end
@doc """
docker-compose start
Note this can only be used to start previously created and stopped services. If you want to create
and start the services use `up/1`.
## Options
- `compose_path: path` - path to the compose if not in the standard location
- `project_name: name` - compose project name
- `service: name` - name of the service to be started, can be specified multiple times to start
multiple services at once. If not specified at all then all services are started.
"""
@spec start(Keyword.t()) :: {:ok, output} | {:error, exit_code, output}
def start(opts) do
args =
[
compose_opts(opts),
"start",
service_opts(opts)
]
|> List.flatten()
args
|> execute(opts)
|> result()
end
defp execute(args, opts) do
System.cmd("docker", ["compose", "--ansi", "never" | args], [
{:stderr_to_stdout, true} | cmd_opts(opts)
])
end
defp compose_opts([{:compose_path, path} | rest]) do
["-f", Path.basename(path) | compose_opts(rest)]
end
defp compose_opts([{:project_name, name} | rest]) do
["-p", name | compose_opts(rest)]
end
defp compose_opts([{:compatibility, true} | rest]) do
["--compatibility" | compose_opts(rest)]
end
defp compose_opts([_ | rest]), do: compose_opts(rest)
defp compose_opts([]), do: []
defp up_opts(opts) do
opts
|> Keyword.take([:force_recreate, :remove_orphans, :quiet_pull])
|> command_opts()
end
defp down_opts(opts) do
opts
|> Keyword.take([:remove_orphans])
|> command_opts()
end
defp command_opts([{:force_recreate, true} | rest]),
do: ["--force-recreate" | command_opts(rest)]
defp command_opts([{:remove_orphans, true} | rest]),
do: ["--remove-orphans" | command_opts(rest)]
defp command_opts([{:quiet_pull, true} | rest]),
do: ["--quiet-pull" | command_opts(rest)]
defp command_opts([_ | rest]), do: command_opts(rest)
defp command_opts([]), do: []
defp service_opts([{:service, name} | rest]), do: [name | service_opts(rest)]
defp service_opts([_ | rest]), do: service_opts(rest)
defp service_opts([]), do: []
defp cmd_opts([{:compose_path, path} | rest]) do
[{:cd, Path.dirname(path)} | cmd_opts(rest)]
end
defp cmd_opts([{:into, _collectable} = into | rest]) do
[into | cmd_opts(rest)]
end
defp cmd_opts([_ | rest]), do: cmd_opts(rest)
defp cmd_opts([]), do: []
defp result({output, exit_code}) do
if exit_code == 0 do
{:ok, output}
else
{:error, exit_code, output}
end
end
end