presidium 0.16.8 → 0.16.9
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.
- package/.eslintrc.js +1 -1
- package/Docker.js +12 -1
- package/DockerService.js +10 -2
- package/DockerService.test.js +123 -111
- package/package.json +1 -1
package/.eslintrc.js
CHANGED
package/Docker.js
CHANGED
|
@@ -995,6 +995,9 @@ const has = property => value => {
|
|
|
995
995
|
* email?: string,
|
|
996
996
|
* serveraddress?: string,
|
|
997
997
|
* identitytoken?: string,
|
|
998
|
+
*
|
|
999
|
+
* // user-defined metadata
|
|
1000
|
+
* labels: object,
|
|
998
1001
|
* }) -> Promise<HttpResponse>
|
|
999
1002
|
* ```
|
|
1000
1003
|
*/
|
|
@@ -1010,6 +1013,7 @@ Docker.prototype.updateService = function dockerUpdateService(service, options)
|
|
|
1010
1013
|
|
|
1011
1014
|
body: stringifyJSON(defaultsDeep(get('spec', {})(options))({
|
|
1012
1015
|
Name: service,
|
|
1016
|
+
Labels: options.labels ?? {},
|
|
1013
1017
|
TaskTemplate: {
|
|
1014
1018
|
ContainerSpec: {
|
|
1015
1019
|
...options.image && { Image: options.image },
|
|
@@ -1116,6 +1120,14 @@ Docker.prototype.updateService = function dockerUpdateService(service, options)
|
|
|
1116
1120
|
},
|
|
1117
1121
|
},
|
|
1118
1122
|
|
|
1123
|
+
...options.network && {
|
|
1124
|
+
Networks: [{
|
|
1125
|
+
Target: options.network,
|
|
1126
|
+
Aliases: [],
|
|
1127
|
+
DriverOpts: {},
|
|
1128
|
+
}],
|
|
1129
|
+
},
|
|
1130
|
+
|
|
1119
1131
|
...options.publish && {
|
|
1120
1132
|
EndpointSpec: {
|
|
1121
1133
|
Ports: Object.entries(options.publish).map(pipe([
|
|
@@ -1317,7 +1329,6 @@ Docker.prototype.createNetwork = function createNetwork(options) {
|
|
|
1317
1329
|
Name: options.name,
|
|
1318
1330
|
Driver: options.driver,
|
|
1319
1331
|
CheckDuplicate: true,
|
|
1320
|
-
Attachable: true,
|
|
1321
1332
|
})),
|
|
1322
1333
|
})
|
|
1323
1334
|
}
|
package/DockerService.js
CHANGED
|
@@ -193,12 +193,20 @@ DockerService.prototype.update = async function update(options) {
|
|
|
193
193
|
...options,
|
|
194
194
|
spec: this.spec,
|
|
195
195
|
version: this.version,
|
|
196
|
-
}).then(response => {
|
|
197
|
-
|
|
196
|
+
}).then(async response => {
|
|
197
|
+
await this.synchronize()
|
|
198
198
|
return response.json()
|
|
199
199
|
})
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
/**
|
|
203
|
+
* @name DockerService.prototype.inspect
|
|
204
|
+
*
|
|
205
|
+
* @synopsis
|
|
206
|
+
* ```coffeescript [specscript]
|
|
207
|
+
* new DockerService(...).inspect() -> Promise<{}>
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
202
210
|
DockerService.prototype.inspect = async function inspect() {
|
|
203
211
|
await this.ready
|
|
204
212
|
return this.docker.inspectService(this.name)
|
package/DockerService.test.js
CHANGED
|
@@ -6,117 +6,129 @@ const DockerService = require('./DockerService')
|
|
|
6
6
|
const inspect = require('util').inspect
|
|
7
7
|
const always = require('rubico/always')
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
.before(async function () {
|
|
11
|
-
this.docker = new Docker()
|
|
12
|
-
await this.docker.leaveSwarm({ force: true })
|
|
13
|
-
await this.docker.pruneContainers()
|
|
14
|
-
await this.docker.pruneImages()
|
|
15
|
-
await this.docker.initSwarm('[::1]:2377')
|
|
16
|
-
})
|
|
17
|
-
.case({
|
|
18
|
-
name: 'my-service',
|
|
19
|
-
image: 'nginx:1.19',
|
|
20
|
-
replicas: 1,
|
|
21
|
-
}, async function (myService) {
|
|
22
|
-
{
|
|
23
|
-
const info = await myService.inspect()
|
|
24
|
-
this.serviceId = info.ID
|
|
25
|
-
assert.equal(info.ID, this.serviceId)
|
|
26
|
-
assert.equal(info.Spec.UpdateConfig.Parallelism, 2) // defaults
|
|
27
|
-
assert.equal(info.Spec.UpdateConfig.Delay, 1e9)
|
|
28
|
-
assert.equal(info.Spec.UpdateConfig.FailureAction, 'pause')
|
|
29
|
-
assert.equal(info.Spec.UpdateConfig.Monitor, 15e9)
|
|
30
|
-
assert.equal(info.Spec.UpdateConfig.MaxFailureRatio, 0.15)
|
|
31
|
-
assert.equal(info.Spec.RollbackConfig.Parallelism, 1)
|
|
32
|
-
assert.equal(info.Spec.RollbackConfig.Delay, 1e9)
|
|
33
|
-
assert.equal(info.Spec.RollbackConfig.FailureAction, 'pause')
|
|
34
|
-
assert.equal(info.Spec.RollbackConfig.Monitor, 15e9)
|
|
35
|
-
assert.equal(info.Spec.RollbackConfig.MaxFailureRatio, 0.15)
|
|
36
|
-
}
|
|
9
|
+
const test = new Test('DockerService', DockerService)
|
|
37
10
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
updateMaxFailureRatio: 0.3,
|
|
46
|
-
rollbackParallelism: 3,
|
|
47
|
-
rollbackDelay: 2e9,
|
|
48
|
-
rollbackFailureAction: 'continue',
|
|
49
|
-
rollbackMonitor: 30e9,
|
|
50
|
-
rollbackMaxFailureRatio: 0.3,
|
|
51
|
-
env: { FOO: 'foo' },
|
|
52
|
-
workdir: '/opt',
|
|
53
|
-
mounts: [{
|
|
54
|
-
source: 'other-volume',
|
|
55
|
-
target: '/opt/other-volume',
|
|
56
|
-
}],
|
|
57
|
-
publish: { 8080: 80 },
|
|
58
|
-
healthCmd: ['curl', '0.0.0.0:80'],
|
|
59
|
-
restart: 'on-failure:5',
|
|
60
|
-
memory: 512e6, // bytes
|
|
61
|
-
})
|
|
62
|
-
}
|
|
11
|
+
.before(async function () {
|
|
12
|
+
this.docker = new Docker()
|
|
13
|
+
await this.docker.leaveSwarm({ force: true })
|
|
14
|
+
await this.docker.pruneContainers()
|
|
15
|
+
await this.docker.pruneImages()
|
|
16
|
+
await this.docker.initSwarm('[::1]:2377')
|
|
17
|
+
})
|
|
63
18
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
assert.deepEqual(
|
|
85
|
-
info.Spec.TaskTemplate.ContainerSpec.Mounts,
|
|
86
|
-
[{ Type: 'volume', Source: 'other-volume', Target: '/opt/other-volume' }])
|
|
87
|
-
assert.equal(info.Spec.TaskTemplate.RestartPolicy.Condition, 'on-failure')
|
|
88
|
-
assert.equal(info.Spec.TaskTemplate.RestartPolicy.MaxAttempts, 5)
|
|
89
|
-
assert.equal(info.Spec.TaskTemplate.Resources.Limits.MemoryBytes, 512e6)
|
|
90
|
-
this.myServiceSpec = myService.spec
|
|
91
|
-
}
|
|
19
|
+
.case({
|
|
20
|
+
name: 'my-service',
|
|
21
|
+
image: 'nginx:1.19',
|
|
22
|
+
replicas: 1,
|
|
23
|
+
}, async function (myService) {
|
|
24
|
+
{
|
|
25
|
+
const info = await myService.inspect()
|
|
26
|
+
this.serviceId = info.ID
|
|
27
|
+
assert.equal(info.ID, this.serviceId)
|
|
28
|
+
assert.equal(info.Spec.UpdateConfig.Parallelism, 2) // defaults
|
|
29
|
+
assert.equal(info.Spec.UpdateConfig.Delay, 1e9)
|
|
30
|
+
assert.equal(info.Spec.UpdateConfig.FailureAction, 'pause')
|
|
31
|
+
assert.equal(info.Spec.UpdateConfig.Monitor, 15e9)
|
|
32
|
+
assert.equal(info.Spec.UpdateConfig.MaxFailureRatio, 0.15)
|
|
33
|
+
assert.equal(info.Spec.RollbackConfig.Parallelism, 1)
|
|
34
|
+
assert.equal(info.Spec.RollbackConfig.Delay, 1e9)
|
|
35
|
+
assert.equal(info.Spec.RollbackConfig.FailureAction, 'pause')
|
|
36
|
+
assert.equal(info.Spec.RollbackConfig.Monitor, 15e9)
|
|
37
|
+
assert.equal(info.Spec.RollbackConfig.MaxFailureRatio, 0.15)
|
|
38
|
+
}
|
|
92
39
|
|
|
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
|
-
await
|
|
122
|
-
|
|
40
|
+
{
|
|
41
|
+
const result = await myService.update({
|
|
42
|
+
labels: { foo: 'bar' },
|
|
43
|
+
replicas: 2,
|
|
44
|
+
updateParallelism: 3,
|
|
45
|
+
updateDelay: 2e9,
|
|
46
|
+
updateFailureAction: 'continue',
|
|
47
|
+
updateMonitor: 30e9,
|
|
48
|
+
updateMaxFailureRatio: 0.3,
|
|
49
|
+
rollbackParallelism: 3,
|
|
50
|
+
rollbackDelay: 2e9,
|
|
51
|
+
rollbackFailureAction: 'continue',
|
|
52
|
+
rollbackMonitor: 30e9,
|
|
53
|
+
rollbackMaxFailureRatio: 0.3,
|
|
54
|
+
env: { FOO: 'foo' },
|
|
55
|
+
workdir: '/opt',
|
|
56
|
+
mounts: [{
|
|
57
|
+
source: 'other-volume',
|
|
58
|
+
target: '/opt/other-volume',
|
|
59
|
+
}],
|
|
60
|
+
publish: { 8080: 80 },
|
|
61
|
+
healthCmd: ['curl', '0.0.0.0:80'],
|
|
62
|
+
restart: 'on-failure:5',
|
|
63
|
+
memory: 512e6, // bytes
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
{
|
|
68
|
+
const info = await myService.inspect()
|
|
69
|
+
assert.equal(info.ID, this.serviceId)
|
|
70
|
+
// assert.equal(info.Spec.Labels.foo, 'bar')
|
|
71
|
+
assert.equal(info.Spec.UpdateConfig.Parallelism, 3)
|
|
72
|
+
assert.equal(info.Spec.UpdateConfig.Delay, 2e9)
|
|
73
|
+
assert.equal(info.Spec.UpdateConfig.FailureAction, 'continue')
|
|
74
|
+
assert.equal(info.Spec.UpdateConfig.Monitor, 30e9)
|
|
75
|
+
assert.equal(info.Spec.UpdateConfig.MaxFailureRatio, 0.3)
|
|
76
|
+
assert.equal(info.Spec.RollbackConfig.Parallelism, 3)
|
|
77
|
+
assert.equal(info.Spec.RollbackConfig.Delay, 2e9)
|
|
78
|
+
assert.equal(info.Spec.RollbackConfig.FailureAction, 'continue')
|
|
79
|
+
assert.equal(info.Spec.RollbackConfig.Monitor, 30e9)
|
|
80
|
+
assert.equal(info.Spec.RollbackConfig.MaxFailureRatio, 0.3)
|
|
81
|
+
assert.equal(info.Spec.Mode.Replicated.Replicas, 2)
|
|
82
|
+
assert.equal(info.Spec.TaskTemplate.ContainerSpec.Env.length, 1)
|
|
83
|
+
assert.equal(info.Spec.TaskTemplate.ContainerSpec.Env[0], 'FOO=foo')
|
|
84
|
+
assert.equal(info.Spec.TaskTemplate.ContainerSpec.Dir, '/opt')
|
|
85
|
+
assert.deepEqual(
|
|
86
|
+
info.Spec.TaskTemplate.ContainerSpec.Healthcheck.Test,
|
|
87
|
+
['CMD', 'curl', '0.0.0.0:80'])
|
|
88
|
+
assert.deepEqual(
|
|
89
|
+
info.Spec.TaskTemplate.ContainerSpec.Mounts,
|
|
90
|
+
[{ Type: 'volume', Source: 'other-volume', Target: '/opt/other-volume' }])
|
|
91
|
+
assert.equal(info.Spec.TaskTemplate.RestartPolicy.Condition, 'on-failure')
|
|
92
|
+
assert.equal(info.Spec.TaskTemplate.RestartPolicy.MaxAttempts, 5)
|
|
93
|
+
assert.equal(info.Spec.TaskTemplate.Resources.Limits.MemoryBytes, 512e6)
|
|
94
|
+
this.myServiceSpec = myService.spec
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
{
|
|
98
|
+
const logResponseStream = await myService.getLogs({ stdout: true, stderr: true })
|
|
99
|
+
logResponseStream.pipe(process.stdout)
|
|
100
|
+
await new Promise(resolve => logResponseStream.on('end', resolve))
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
.case({
|
|
105
|
+
name: 'my-service',
|
|
106
|
+
image: 'nginx:1.19',
|
|
107
|
+
replicas: 2,
|
|
108
|
+
}, async function (myService) {
|
|
109
|
+
await myService.ready
|
|
110
|
+
// TODO test for update on construction assert.deepEqual(myService.spec, this.myServiceSpec)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
.case({
|
|
114
|
+
name: 'bad-request',
|
|
115
|
+
image: 'nginx:1.19',
|
|
116
|
+
replicas: 2,
|
|
117
|
+
restart: 'always', // coulda fooled me
|
|
118
|
+
}, async function (errorService) {
|
|
119
|
+
assert.rejects(
|
|
120
|
+
always(errorService.ready),
|
|
121
|
+
new Error('{"message":"invalid RestartCondition: \\"always\\""}\n'))
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
.after(async function () {
|
|
125
|
+
await this.docker.pruneContainers()
|
|
126
|
+
await this.docker.pruneImages()
|
|
127
|
+
await this.docker.leaveSwarm({ force: true })
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
if (process.argv[1] == __filename) {
|
|
131
|
+
test()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
module.exports = test
|