dockerapi 0.6.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90acd383975c4846ca2d6bfb91aa15d9898ce0101557ca50481f20729871ef73
4
- data.tar.gz: 03d01594692f5c2093bf3e91b4f67635d2bd8e1bf0360217747ea4aa8d2c6840
3
+ metadata.gz: aeb3c1971c26c62d0737576e5ec79f2abcf536b1148be5272be8f501dfcae852
4
+ data.tar.gz: 1392073ca52d6fecfc12e642368713c2fa44a9ebbcd7629de5fb54faf9ac7209
5
5
  SHA512:
6
- metadata.gz: 56a36a3c8b73fc0a8ae02cc68bd93b6b858be21d8c9c6d033b5f1d34d581f646dbb9e77df2e0a9d216c2a835eec3bd8e1abb62ade82aa6ec818ef081b5181d5d
7
- data.tar.gz: 101c74b35333664dc5573d5443f2c7d75d5c8de9a43a2f70a7a54e5bb5673091eebe31dfc9ed5845c1052f47907dc6d7873f3bbe84a5015e10f5411458993cb9
6
+ metadata.gz: 3b03b8e5ce6d95f19c8dd6d357277a102fcc170b35ac989cd080db27c66efcad63125aaedab1c971a8ed435bed7c7447979d332a1b7f43686a2217907bf21fe8
7
+ data.tar.gz: 62cd2888ad859834cf949a6189f6e863e1b2f23ce9849fce4a39a1248cfa74efeaff5e0e6220a165d6b7980445a7773dc4bc3f8d4a678fc364a06b205fc07630
@@ -1,16 +1,70 @@
1
+ # 0.10.0
2
+
3
+ Add `Docker::API::Service` methods:
4
+ * create
5
+ * update
6
+ * list
7
+ * details
8
+ * logs
9
+ * delete
10
+
11
+ # 0.9.0
12
+
13
+ Significant change: `#inspect` is now deprecated and replaced by `#details` in the following classes:
14
+ * `Docker::API::Container`
15
+ * `Docker::API::Image`
16
+ * `Docker::API::Network`
17
+ * `Docker::API::Volume`
18
+ * `Docker::API::Exec`
19
+ * `Docker::API::Swarm`
20
+ * `Docker::API::Node`
21
+
22
+ The method will be removed in the refactoring phase.
23
+
24
+ # 0.8.1
25
+
26
+ Restore the default `#inspect` output for `Docker::API` classes.
27
+
28
+ Most of the overriding methods take an argument, therefore calling using the expect arguments will return a `Docker::API::Response` object, while calling without arguments will return `Kernel#inspect`. To avoid this confusing schema, next release will rename `#inspect` within `Docker::API` to something else.
29
+
30
+ # 0.8.0
31
+
32
+ Add `Docker::API::Swarm` methods:
33
+ * init
34
+ * update
35
+ * ~~inspect~~ details
36
+ * unlock_key
37
+ * unlock
38
+ * join
39
+ * leave
40
+
41
+ Add `Docker::API::Node` methods:
42
+ * list
43
+ * ~~inspect~~ details
44
+ * update
45
+ * delete
46
+
47
+ Query parameters and request body json can now skip the validation step with `:skip_validation => true` option.
48
+
49
+ # 0.7.0
50
+
51
+ Significant changes: `Docker::API::Connection` is now a regular class intead of a Singleton, allowing multiple connections to be stablished within the same program (replacing the connect_to implementation). To leverage this feature, API-related classes must be initialized and may or may not receive a `Docker::API::Connection` as parameter, or it'll connect to `/var/run/docker.sock` by default. For this reason, class methods were replaced with instance methods. Documentation will reflect this changes of implementation.
52
+
53
+ Bug fix: Image push returns a 20X status even when the push is unsucessful. To prevent false positives, it now requires the authentication parameters to be provided, generating a 403 status for invalid credentials or an error if they are absent.
54
+
1
55
  # 0.6.0
2
56
 
3
57
  Add connection parameters specifications with connect_to in Docker::API::Connection.
4
58
 
5
- Add Docker::API::Exec methods:
59
+ Add `Docker::API::Exec` methods:
6
60
  * create
7
61
  * start
8
62
  * resize
9
- * inspect
63
+ * ~~inspect~~ details
10
64
 
11
65
  # 0.5.0
12
66
 
13
- Add Docker::API::System methods:
67
+ Add `Docker::API::System` methods:
14
68
  * auth
15
69
  * ping
16
70
  * info
@@ -18,7 +72,7 @@ Add Docker::API::System methods:
18
72
  * events
19
73
  * df
20
74
 
21
- Add new response class Docker::API::Response with the following methods:
75
+ Add new response class `Docker::API::Response` with the following methods:
22
76
  * json
23
77
  * path
24
78
  * success?
@@ -27,9 +81,9 @@ Error classes output better error messages.
27
81
 
28
82
  # 0.4.0
29
83
 
30
- Add Docker::API::Network methods:
84
+ Add `Docker::API::Network` methods:
31
85
  * list
32
- * inspect
86
+ * ~~inspect~~ details
33
87
  * create
34
88
  * remove
35
89
  * prune
@@ -38,9 +92,9 @@ Add Docker::API::Network methods:
38
92
 
39
93
  # 0.3.0
40
94
 
41
- Add Docker::API::Volume methods:
95
+ Add `Docker::API::Volume` methods:
42
96
  * list
43
- * inspect
97
+ * ~~inspect~~ details
44
98
  * create
45
99
  * remove
46
100
  * prune
@@ -48,8 +102,8 @@ Add Docker::API::Volume methods:
48
102
 
49
103
  # 0.2.0
50
104
 
51
- Add Docker::API::Image methods:
52
- * inspect
105
+ Add `Docker::API::Image` methods:
106
+ * ~~inspect~~ details
53
107
  * history
54
108
  * list
55
109
  * search
@@ -64,13 +118,13 @@ Add Docker::API::Image methods:
64
118
  * build
65
119
  * delete_cache
66
120
 
67
- Add Docker::API::System.auth (untested) for basic authentication
121
+ Add `Docker::API::System.auth` (untested) for basic authentication
68
122
 
69
123
  # 0.1.0
70
124
 
71
- Add Docker::API::Container methods:
125
+ Add `Docker::API::Container` methods:
72
126
  * list
73
- * inspect
127
+ * ~~inspect~~ details
74
128
  * top
75
129
  * changes
76
130
  * start
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dockerapi (0.6.0)
4
+ dockerapi (0.10.0)
5
5
  excon (~> 0.74.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -23,68 +23,71 @@ Or install it yourself as:
23
23
  ### Images
24
24
 
25
25
  ```ruby
26
+ # Connect to local image endpoints
27
+ image = Docker::API::Image.new
28
+
26
29
  # Pull from a public repository
27
- Docker::API::Image.create( fromImage: "nginx:latest" )
30
+ image.create( fromImage: "nginx:latest" )
28
31
 
29
32
  # Pull from a private repository
30
- Docker::API::Image.create( {fromImage: "private/repo:tag"}, {username: "janedoe", password: "password"} )
33
+ image.create( {fromImage: "private/repo:tag"}, {username: "janedoe", password: "password"} )
31
34
 
32
35
  # Create image from local tar file
33
- Docker::API::Image.create( fromSrc: "/path/to/file.tar", repo: "repo:tag" )
36
+ image.create( fromSrc: "/path/to/file.tar", repo: "repo:tag" )
34
37
 
35
38
  # Create image from remote tar file
36
- Docker::API::Image.create( fromSrc: "https://url.to/file.tar", repo: "repo:tag" )
39
+ image.create( fromSrc: "https://url.to/file.tar", repo: "repo:tag" )
37
40
 
38
41
  # List images
39
- Docker::API::Image.list
42
+ image.list
40
43
 
41
44
  # Inspect image
42
- Docker::API::Image.inspect("image")
45
+ image.details("image")
43
46
 
44
47
  # History
45
- Docker::API::Image.history("image")
48
+ image.history("image")
46
49
 
47
50
  # Search image
48
- Docker::API::Image.search(term: "busybox", limit: 2)
49
- Docker::API::Image.search(term: "busybox", filters: {"is-automated": {"true": true}})
50
- Docker::API::Image.search(term: "busybox", filters: {"is-official": {"true": true}})
51
+ image.search(term: "busybox", limit: 2)
52
+ image.search(term: "busybox", filters: {"is-automated": {"true": true}})
53
+ image.search(term: "busybox", filters: {"is-official": {"true": true}})
51
54
 
52
55
  # Tag image
53
- Docker::API::Image.tag("current:tag", repo: "new:tag") # or
54
- Docker::API::Image.tag("current:tag", repo: "new", tag: "tag")
56
+ image.tag("current:tag", repo: "new:tag") # or
57
+ image.tag("current:tag", repo: "new", tag: "tag")
55
58
 
56
59
  # Push image
57
- Docker::API::Image.push("repo:tag") # to dockerhub
58
- Docker::API::Image.push("localhost:5000/repo:tag") # to local registry
59
- Docker::API::Image.push("private/repo", {tag: "tag"}, {username: "janedoe", password: "password"} # to private repository
60
+ image.push("repo:tag") # to dockerhub
61
+ image.push("localhost:5000/repo:tag") # to local registry
62
+ image.push("private/repo", {tag: "tag"}, {username: "janedoe", password: "password"} # to private repository
60
63
 
61
64
  # Remove image
62
- Docker::API::Image.remove("image")
63
- Docker::API::Image.remove("image", force: true)
65
+ image.remove("image")
66
+ image.remove("image", force: true)
64
67
 
65
68
  # Remove unsued images (prune)
66
- Docker::API::Image.prune(filters: {dangling: {"false": true}})
69
+ image.prune(filters: {dangling: {"false": true}})
67
70
 
68
71
  # Create image from a container (commit)
69
- Docker::API::Image.commit(container: container, repo: "my/image", tag: "latest", comment: "Comment from commit", author: "dockerapi", pause: false )
72
+ image.commit(container: container, repo: "my/image", tag: "latest", comment: "Comment from commit", author: "dockerapi", pause: false )
70
73
 
71
74
  # Build image from a local tar file
72
- Docker::API::Image.build("/path/to/file.tar")
75
+ image.build("/path/to/file.tar")
73
76
 
74
77
  # Build image from a remote tar file
75
- Docker::API::Image.build(nil, remote: "https://url.to/file.tar")
78
+ image.build(nil, remote: "https://url.to/file.tar")
76
79
 
77
80
  # Build image from a remote Dockerfile
78
- Docker::API::Image.build(nil, remote: "https://url.to/Dockerfile")
81
+ image.build(nil, remote: "https://url.to/Dockerfile")
79
82
 
80
83
  # Delete builder cache
81
- Docker::API::Image.delete_cache
84
+ image.delete_cache
82
85
 
83
86
  # Export repo
84
- Docker::API::Image.export("repo:tag", "~/exported_image.tar")
87
+ image.export("repo:tag", "~/exported_image.tar")
85
88
 
86
89
  # Import repo
87
- Docker::API::Image.import("/path/to/file.tar")
90
+ image.import("/path/to/file.tar")
88
91
  ```
89
92
 
90
93
  ### Containers
@@ -93,140 +96,258 @@ Let's test a Nginx container
93
96
 
94
97
  ```ruby
95
98
  # Pull nginx image
96
- Docker::API::Image.create( fromImage: "nginx:latest" )
99
+ Docker::API::Image.new.create( fromImage: "nginx:latest" )
100
+
101
+ # Connect to local container endpoints
102
+ container = Docker::API::Container.new
97
103
 
98
104
  # Create container
99
- Docker::API::Container.create( {name: "nginx"}, {Image: "nginx:latest", HostConfig: {PortBindings: {"80/tcp": [ {HostIp: "0.0.0.0", HostPort: "80"} ]}}})
105
+ container.create( {name: "nginx"}, {Image: "nginx:latest", HostConfig: {PortBindings: {"80/tcp": [ {HostIp: "0.0.0.0", HostPort: "80"} ]}}})
100
106
 
101
107
  # Start container
102
- Docker::API::Container.start("nginx")
108
+ container.start("nginx")
103
109
 
104
110
  # Open localhost or machine IP to check the container running
105
111
 
106
112
  # Restart container
107
- Docker::API::Container.restart("nginx")
113
+ container.restart("nginx")
108
114
 
109
115
  # Pause/unpause container
110
- Docker::API::Container.pause("nginx")
111
- Docker::API::Container.unpause("nginx")
116
+ container.pause("nginx")
117
+ container.unpause("nginx")
112
118
 
113
119
  # List containers
114
- Docker::API::Container::list
120
+ container.list
115
121
 
116
122
  # List containers (including stopped ones)
117
- Docker::API::Container::list(all: true)
123
+ container.list(all: true)
118
124
 
119
125
  # Inspect container
120
- Docker::API::Container.inspect("nginx")
126
+ container.details("nginx")
121
127
 
122
128
  # View container's processes
123
- Docker::API::Container.top("nginx")
129
+ container.top("nginx")
124
130
 
125
- # Let's enhance the output
126
- JSON.parse(Docker::API::Container.top("nginx").body)
131
+ # Using json output
132
+ container.top("nginx").json
127
133
 
128
134
  # View filesystem changes
129
- Docker::API::Container.changes("nginx")
135
+ container.changes("nginx")
130
136
 
131
- # View filesystem logs
132
- Docker::API::Container.logs("nginx", stdout: true)
133
- Docker::API::Container.logs("nginx", stdout: true, follow: true)
137
+ # View container logs
138
+ container.logs("nginx", stdout: true)
139
+ container.logs("nginx", stdout: true, follow: true)
134
140
 
135
141
  # View filesystem stats
136
- Docker::API::Container.stats("nginx", stream: true)
142
+ container.stats("nginx", stream: true)
137
143
 
138
144
  # Export container
139
- Docker::API::Container.export("nginx", "~/exported_container")
145
+ container.export("nginx", "~/exported_container")
140
146
 
141
147
  # Get files from container
142
- Docker::API::Container.archive("nginx", "~/html.tar", path: "/usr/share/nginx/html/")
148
+ container.archive("nginx", "~/html.tar", path: "/usr/share/nginx/html/")
143
149
 
144
150
  # Stop container
145
- Docker::API::Container.stop("nginx")
151
+ container.stop("nginx")
146
152
 
147
153
  # Remove container
148
- Docker::API::Container.remove("nginx")
154
+ container.remove("nginx")
149
155
 
150
156
  # Remove stopped containers (prune)
151
- Docker::API::Container.prune
157
+ container.prune
152
158
  ```
153
159
 
154
160
  ### Volumes
155
161
 
156
162
  ```ruby
163
+ # Connect to local volume endpoints
164
+ volume = Docker::API::Volume.new
165
+
157
166
  # Create volume
158
- Docker::API::Volume.create( Name:"my-volume" )
167
+ volume.create( Name:"my-volume" )
159
168
 
160
169
  # List volumes
161
- Docker::API::Volume.list
170
+ volume.list
162
171
 
163
172
  # Inspect volume
164
- Docker::API::Volume.inspect("my-volume")
173
+ volume.details("my-volume")
165
174
 
166
175
  # Remove volume
167
- Docker::API::Volume.remove("my-volume")
176
+ volume.remove("my-volume")
168
177
 
169
178
  # Remove unused volumes (prune)
170
- Docker::API::Volume.prune
179
+ volume.prune
171
180
  ```
172
181
 
173
182
  ### Network
174
183
 
175
184
  ```ruby
185
+ # Connect to local network endpoints
186
+ network = Docker::API::Network.new
187
+
176
188
  # List networks
177
- Docker::API::Network.list
189
+ network.list
178
190
 
179
191
  # Inspect network
180
- Docker::API::Network.inspect("bridge")
192
+ network.details("bridge")
181
193
 
182
194
  # Create network
183
- Docker::API::Network.create( Name:"my-network" )
195
+ network.create( Name:"my-network" )
184
196
 
185
197
  # Remove network
186
- Docker::API::Network.remove("my-network")
198
+ network.remove("my-network")
187
199
 
188
200
  # Remove unused network (prune)
189
- Docker::API::Network.prune
201
+ network.prune
190
202
 
191
203
  # Connect container to a network
192
- Docker::API::Network.connect( "my-network", Container: "my-container" )
204
+ network.connect( "my-network", Container: "my-container" )
193
205
 
194
206
  # Disconnect container to a network
195
- Docker::API::Network.disconnect( "my-network", Container: "my-container" )
207
+ network.disconnect( "my-network", Container: "my-container" )
196
208
  ```
197
209
 
198
210
  ### System
199
211
 
200
212
  ```ruby
213
+ # Connect to local system endpoints
214
+ sys = Docker::API::System.new
215
+
201
216
  # Ping docker api
202
- Docker::API::System.ping
217
+ sys.ping
203
218
 
204
219
  # Docker components versions
205
- Docker::API::System.version
220
+ sys.version
206
221
 
207
222
  # System info
208
- Docker::API::System.info
223
+ sys.info
209
224
 
210
225
  # System events (stream)
211
- Docker::API::System.events(until: Time.now.to_i)
226
+ sys.events(until: Time.now.to_i)
212
227
 
213
228
  # Data usage information
214
- Docker::API::System.df
229
+ sys.df
215
230
  ```
216
231
 
217
232
  ### Exec
218
233
 
219
234
  ```ruby
235
+ # Connect to local exec endpoints
236
+ exe = Docker::API::Exec.new
237
+
220
238
  # Create exec instance, get generated exec ID
221
- response = Docker::API::Exec.create(container, AttachStdout:true, Cmd: ["ls", "-l"])
239
+ response = exe.create(container, AttachStdout:true, Cmd: ["ls", "-l"])
222
240
  id = response.json["Id"]
223
241
 
224
242
  # Execute the command, stream from Stdout is stored in response data
225
- response = Docker::API::Exec.start(id)
243
+ response = exe.start(id)
226
244
  print response.data[:stream]
227
245
 
228
246
  # Inspect exec instance
229
- Docker::API::Exec.inspect(id)
247
+ exe.details(id)
248
+ ```
249
+
250
+ ### Swarm
251
+ ```ruby
252
+ # Connect to local swarm endpoints
253
+ swarm = Docker::API::Swarm.new
254
+
255
+ # Init swarm
256
+ swarm.init({AdvertiseAddr: "local-ip-address:2377", ListenAddr: "0.0.0.0:4567"})
257
+
258
+ # Inspect swarm
259
+ swarm.details
260
+
261
+ # Update swarm
262
+ swarm.update(version, {rotateWorkerToken: true})
263
+ swarm.update(version, {rotateManagerToken: true})
264
+ swarm.update(version, {rotateManagerUnlockKey: true})
265
+ swarm.update(version, {EncryptionConfig: { AutoLockManagers: true }})
266
+
267
+ # Get unlock key
268
+ swarm.unlock_key
269
+
270
+ # Unlock swarm
271
+ swarm.unlock(UnlockKey: "key-value")
272
+
273
+ # Join an existing swarm
274
+ swarm.join(RemoteAddrs: ["remote-manager-address:2377"], JoinToken: "Join-Token-Here")
275
+
276
+ # Leave a swarm
277
+ swarm.leave(force: true)
278
+ ```
279
+
280
+ ### Node
281
+ ```ruby
282
+ # Connect to local node endpoints
283
+ node = Docker::API::Node.new
284
+
285
+ # List nodes
286
+ node.list
287
+
288
+ # Inspect node
289
+ node.details("node-id")
290
+
291
+ # Update node (version, Role and Availability must be present)
292
+ node.update("node-id", {version: "version"}, {Role: "worker", Availability: "pause" })
293
+ node.update("node-id", {version: "version"}, {Role: "worker", Availability: "active" })
294
+ node.update("node-id", {version: "version"}, {Role: "manager", Availability: "active" })
295
+
296
+ # Delete node
297
+ node.delete("node-id")
298
+ ```
299
+
300
+ ### Service
301
+ ```ruby
302
+ # Connect to local service endpoints
303
+ service = Docker::API::Service.new
304
+
305
+ # List services
306
+ service.list
307
+
308
+ # Create a service
309
+ service.create({Name: "nginx-service",
310
+ TaskTemplate: {ContainerSpec: { Image: "nginx:alpine" }},
311
+ Mode: { Replicated: { Replicas: 2 } },
312
+ EndpointSpec: { Ports: [ {Protocol: "tcp", PublishedPort: 80, TargetPort: 80} ] }
313
+ })
314
+
315
+ # Update a service (needs version and current Spec)
316
+ version = service.details( service ).json["Version"]["Index"]
317
+ spec = service.details(service).json["Spec"]
318
+ service.update("nginx-service", {version: version}, spec.merge!({ Mode: { Replicated: { Replicas: 1 } } }))
319
+
320
+ # View service logs
321
+ service.logs("nginx-service", stdout: true)
322
+
323
+ # Inspect service
324
+ service.details("nginx-service")
325
+
326
+ # Delete service
327
+ service.delete("nginx-service")
328
+
329
+ ```
330
+
331
+ ### Connection
332
+
333
+ By default Docker::API::Connection will connect to local Docker socket at `/var/run/docker.sock`. See examples below to use a different path or connect to a remote address.
334
+
335
+ ```ruby
336
+ # Setting different connections
337
+ local = Docker::API::Connection.new('unix:///', socket: "/path/to/docker.sock")
338
+ remote = Docker::API::Connection.new("http://127.0.0.1:2375") # change the IP address accordingly
339
+
340
+ # Using default /var/run/docker.sock
341
+ image_default = Docker::API::Image.new
342
+ image_default.list
343
+
344
+ # Using custom socket path
345
+ image_custom = Docker::API::Image.new(local)
346
+ image_custom.list
347
+
348
+ # Using remote address
349
+ image_remote = Docker::API::Image.new(remote)
350
+ image_remote.list
230
351
  ```
231
352
 
232
353
  ### Requests
@@ -238,7 +359,7 @@ Requests should work as described in [Docker API documentation](https://docs.doc
238
359
  All requests return a response class that inherits from Excon::Response. Available attribute readers and methods include: `status`, `data`, `body`, `headers`, `json`, `path`, `success?`.
239
360
 
240
361
  ```ruby
241
- response = Docker::API::Image.create(fromImage: "busybox:latest")
362
+ response = Docker::API::Image.new.create(fromImage: "busybox:latest")
242
363
 
243
364
  response
244
365
  => #<Docker::API::Response:0x000055bb390b35c0 ... >
@@ -269,6 +390,8 @@ response.success?
269
390
 
270
391
  `Docker::API::InvalidParameter` and `Docker::API::InvalidRequestBody` may be raised when an invalid option is passed as argument (ie: an option not described in Docker API documentation for request query parameters nor request body (json) parameters). Even if no errors were raised, consider validating the status code and/or message of the response to check if the Docker daemon has fulfilled the operation properly.
271
392
 
393
+ To completely skip the validation process, add `:skip_validation => true` in the hash to be validated.
394
+
272
395
  ## Development
273
396
 
274
397
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -277,28 +400,22 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
277
400
 
278
401
  ### Road to 1.0.0
279
402
 
280
- NS: Not Started
281
-
282
- WIP: Work In Progress
283
-
284
-
285
403
  | Class | Tests | Implementation | Refactoring |
286
404
  |---|---|---|---|
287
- | Container | Ok | Ok | NS |
288
- | Image | Ok | Ok | NS |
289
- | Volume | Ok | Ok | NS |
290
- | Network | Ok | Ok | NS |
291
- | System | Ok | Ok | NS |
292
- | Exec | Ok | Ok | NS |
293
- | Swarm | NS | NS | NS |
294
- | Node | NS | NS | NS |
295
- | Service | NS | NS | NS |
296
- | Task | NS | NS | NS |
297
- | Secret | NS | NS | NS |
298
-
299
- Misc:
300
- * ~~Improve response object~~
301
- * ~~Improve error objects~~
405
+ | Image | Ok | Ok | 8/7 |
406
+ | Container | Ok | Ok | 8/14 |
407
+ | Volume | Ok | Ok | 8/21 |
408
+ | Network | Ok | Ok | 8/21 |
409
+ | System | Ok | Ok | 8/21 |
410
+ | Exec | Ok | Ok | 8/21 |
411
+ | Swarm | Ok | Ok | 8/28 |
412
+ | Node | Ok | Ok | 8/28 |
413
+ | Service | 7/17 | 7/17 | 8/28 |
414
+ | Task | 7/17 | 7/17 | 9/4 |
415
+ | Secret | 7/17 | 7/17 | 9/4 |
416
+ | Config | 7/17 | 7/17 | 9/4 |
417
+ | Distribution | 7/17 | 7/17 | 9/4 |
418
+ | Plugin | 7/24 | 7/24 | 9/4 |
302
419
 
303
420
  ## Contributing
304
421