-
Notifications
You must be signed in to change notification settings - Fork 13
/
core.clj
333 lines (274 loc) · 10.5 KB
/
core.clj
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
; This file is part of clj-docker-client.
;
; clj-docker-client is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; clj-docker-client is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with clj-docker-client. If not, see <http://www.gnu.org/licenses/>.
(ns clj-docker-client.core
(:require [byte-streams :as bs]
[clj-docker-client.utils :as u]
[clj-docker-client.formatters :as f])
(:import (java.nio.file Paths)
(com.spotify.docker.client DefaultDockerClient
DockerClient
DockerClient$ListImagesParam
DockerClient$BuildParam
DockerClient$ListContainersParam
DockerClient$LogsParam
LogMessage
DockerClient$ListNetworksParam)
(com.spotify.docker.client.messages ContainerCreation
RegistryAuth
NetworkConfig)))
;; TODO: Add more connection options
(defn connect
"Connects to the local/remote Docker daemon with default settings.
Returns the connection.
Supply the URI as a string with protocol for a remote connection."
([]
(.build (DefaultDockerClient/fromEnv)))
([^String uri]
(-> (DefaultDockerClient/builder)
(.uri uri)
(.build))))
(defn disconnect
"Closes the connection to the Docker server."
[^DockerClient connection]
(.close connection))
(defn ping
"Healthiness check for the connection to the Docker server.
Returns OK if everything is fine."
[^DockerClient connection]
(.ping connection))
(defn register
"Builds login info for a Docker registry."
[^String username ^String password]
(-> (RegistryAuth/builder)
(.username username)
(.password password)
(.build)))
(defn info
"Fetches system wide info about the connected Docker server."
[^DockerClient connection]
(f/format-info (.info connection)))
;; Images
(defn pull
"Pulls an image by *name*.
The *name* is represented by <repo>:<tag>."
[^DockerClient connection ^String name]
(do (.pull connection name)
name))
(defn build
"Builds an image from a provided directory, repo and optional tag.
Returns the id of the built image.
Assumes a Dockerfile to be present in that directory."
([^DockerClient connection ^String path ^String repo]
(build connection path repo "latest"))
([^DockerClient connection ^String path ^String repo ^String tag]
(let [build-path (Paths/get path (into-array String []))]
(.build
connection
build-path
(format "%s:%s" repo tag)
(into-array DockerClient$BuildParam [])))))
(defn push
"Pushes an image by *name*.
Returns the name of the pushed image.
The *name* is represented by <repo>:<tag>."
[^DockerClient connection ^String name ^RegistryAuth auth]
(do (.push connection name auth)
name))
(defn image-rm
"Deletes an image by *name* or id.
Returns the name of the removed image.
If forced? is set removal is forced.
If no-prune? is set untagged parents aren't removed.
The *name* is represented by <repo>:<tag>."
([^DockerClient connection ^String name]
(image-rm connection name false false))
([^DockerClient connection ^String name force? no-prune?]
(do (.removeImage connection name force? no-prune?)
name)))
(defn image-ls
"Lists all available images."
[^DockerClient connection]
(->> (.listImages
connection
(into-array DockerClient$ListImagesParam
[(DockerClient$ListImagesParam/allImages)]))
(mapv f/format-image)))
(defn commit-container
"Creates an image from the changes of a container by name or id.
Takes the repo, tag of the image and the new entry point command.
Returns the id of the new image."
[^DockerClient connection ^String id ^String repo ^String tag ^String command]
(-> connection
(.commitContainer id
repo
tag
(u/config-of (-> connection
(.inspectContainer id)
(.config)
(.image))
(u/sh-tokenize! command))
nil
nil)
(.id)
(u/format-id)))
;; Containers
(defn create
"Creates a container.
Takes the image, entry point command, env vars and host->container port mapping.
Returns the id of the created container."
[^DockerClient connection image cmd env-vars exposed-ports]
(let [config (u/config-of image
(u/sh-tokenize! cmd)
(f/format-env-vars env-vars)
exposed-ports)
creation ^ContainerCreation (.createContainer connection config)]
(u/format-id (.id creation))))
(defn ps
"Lists all containers.
Lists all running containers by default, all can be listed by passing a true param to *all?*"
([^DockerClient connection] (ps connection false))
([^DockerClient connection all?]
(->> (.listContainers
connection
(into-array DockerClient$ListContainersParam
[(DockerClient$ListContainersParam/allContainers all?)]))
(mapv f/format-container-ps))))
(defn start
"Starts a created container asynchronously by name or id.
Returns the name or id."
[^DockerClient connection name]
(do (.startContainer connection name)
name))
(defn stop
"Stops a container with SIGTERM by name or id.
Waits for timeout secs or value of timeout before killing.
Returns the name or id."
([^DockerClient connection name] (stop connection name 30))
([^DockerClient connection name timeout]
(do (.stopContainer connection name timeout)
name)))
(defn kill
"Kills container with SIGKILL by name or id.
Assumes the container to be running.
Returns the name or id."
[^DockerClient connection name]
(do (.killContainer connection name)
name))
(defn restart
"Restarts a container with by name or id.
Waits for timeout secs or value of timeout before killing.
Returns the name or id."
([^DockerClient connection name] (restart connection name 30))
([^DockerClient connection name timeout]
(do (.restartContainer connection name timeout)
name)))
(defn pause
"Pauses a container by name or id.
Returns the name or id."
[^DockerClient connection name]
(do (.pauseContainer connection name)
name))
(defn un-pause
"Un-pauses a container by name or id.
Returns the name or id."
[^DockerClient connection name]
(do (.unpauseContainer connection name)
name))
(defn logs
"Returns a lazy seq of logs split by lines from a container by name or id."
[^DockerClient connection name]
(->> (.logs connection
name
(into-array DockerClient$LogsParam
[(DockerClient$LogsParam/stdout)
(DockerClient$LogsParam/stderr)]))
(iterator-seq)
(map #(.content ^LogMessage %))
(bs/to-input-stream)
(clojure.java.io/reader)
(line-seq)))
(defn container-state
"Returns the current state of a created container by name or id."
[^DockerClient connection name]
(-> connection
(.inspectContainer name)
(.state)
(f/format-state)))
(defn wait-container
"Waits for the exit of a container by id or name."
[^DockerClient connection name]
(.statusCode (.waitContainer connection name)))
(defn run
"Runs a container with a specified image, command, env vars and host->container port mappings.
Returns the container id.
Runs synchronously by default, i.e. waits for the container exit.
If detached? flag is true, executes asynchronously."
([^DockerClient connection image command env-vars exposed-ports]
(run connection image command env-vars exposed-ports false))
([^DockerClient connection image command env-vars exposed-ports detached?]
(let [id (->> (create connection image command env-vars exposed-ports)
(start connection))]
(if (not detached?)
(do (wait-container connection id)
id)
id))))
(defn rm
"Removes a container by name or id.
Pass true to force kill a running container and remove it.
Returns the name or id."
([^DockerClient connection name] (rm connection name false))
([^DockerClient connection name force?]
(do (when force?
(kill connection name))
(.removeContainer connection name)
name)))
;; Networks
(defn network-create
"Creates a new docker network with a unique name."
([^DockerClient connection name]
(network-create connection name true true))
([^DockerClient connection name check-duplicate?]
(network-create connection name check-duplicate? true))
([^DockerClient connection name check-duplicate? attachable?]
(let [config (-> (NetworkConfig/builder)
(.checkDuplicate check-duplicate?)
(.attachable attachable?)
(.name name)
(.build))]
(do (.createNetwork connection config)
name))))
(defn network-rm
"Removes a network by name."
[^DockerClient connection name]
(do (.removeNetwork connection name)
name))
(defn network-ls
"Lists all networks."
[^DockerClient connection]
(->> (.listNetworks connection
(into-array DockerClient$ListNetworksParam []))
(map f/format-network)))
(defn network-connect
"Connects a container to a network.
Takes the name/id of the container and the name of the network."
[^DockerClient connection ^String network ^String container]
(do (.connectToNetwork connection container network)
container))
(defn network-disconnect
"Disconnects a container to a network.
Takes the name/id of the container and the name of the network."
[^DockerClient connection ^String network ^String container]
(do (.disconnectFromNetwork connection container network)
container))