presidium 0.15.32 → 0.15.36

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.
@@ -14,24 +14,63 @@ jobs:
14
14
 
15
15
  runs-on: ubuntu-latest
16
16
 
17
+ services:
18
+ dynamo:
19
+ image: amazon/dynamodb-local:1.15.0
20
+ ports:
21
+ - 8000:8000
22
+
23
+ registry:
24
+ image: registry:2.7
25
+ ports:
26
+ - 5000:5000
27
+ options: >-
28
+ --restart always
29
+ --name registry
30
+
31
+ mongo:
32
+ image: mongo:4.0.6
33
+ ports:
34
+ - 27017:27017
35
+
36
+ redis:
37
+ image: redis:6.0.9
38
+ ports:
39
+ - 6379:6379
40
+
41
+ elasticsearch:
42
+ image: docker.elastic.co/elasticsearch/elasticsearch:7.9.3
43
+ ports:
44
+ - 9200:9200
45
+ options: >-
46
+ -m "512m"
47
+ -e "discovery.type=single-node"
48
+ -e "ES_JAVA_OPTS=-Xms256m -Xmx256m"
49
+
50
+ gremlin:
51
+ image: tinkerpop/gremlin-server:3.4.4
52
+ ports:
53
+ - 8182:8182
54
+
55
+ minio:
56
+ image: minio/minio:edge-cicd
57
+ ports:
58
+ - 9000:9000
59
+ options: >-
60
+ -e "MINIO_ACCESS_KEY=minioadmin"
61
+ -e "MINIO_SECRET_KEY=minioadmin"
62
+
63
+ kinesis:
64
+ image: saidsef/aws-kinesis-local:latest
65
+ ports:
66
+ - 4567:4567
67
+
17
68
  strategy:
18
69
  matrix:
19
- node-version: [14.x, 15.x, 16.x]
70
+ node-version: [14.x, 15.x, 16.x, 17.x]
20
71
 
21
72
  steps:
22
73
  - uses: actions/checkout@v2
23
- - name: Run containers
24
- run:
25
- docker run -p 8000:8000 -d amazon/dynamodb-local:1.13.5
26
- && docker run -p 5000:5000 -d --restart always --name registry registry:2.7
27
- && docker run -p 27017:27017 -d mongo:4.0.6-xenial
28
- && docker run -p 6379:6379 -d redis:6.0.9
29
- && docker run -p 9200:9200 -d -m "512m" -e "discovery.type=single-node" -e "ES_JAVA_OPTS=-Xms256m -Xmx256m" docker.elastic.co/elasticsearch/elasticsearch:7.1.0
30
- && docker run -p 8182:8182 -d tinkerpop/gremlin-server:3.4.4
31
- && docker run -p 9000:9000 -d -e "MINIO_ACCESS_KEY=minioadmin" -e "MINIO_SECRET_KEY=minioadmin" minio/minio:edge-cicd server /data
32
- && docker run -p 4567:4567 -d saidsef/aws-kinesis-local:latest
33
- && docker pull node:15-alpine
34
-
35
74
 
36
75
  - name: Use Node.js ${{ matrix.node-version }}
37
76
  uses: actions/setup-node@v1
package/Docker.js CHANGED
@@ -863,6 +863,7 @@ Docker.prototype.createService = function dockerCreateService(service, options)
863
863
  },
864
864
  },
865
865
 
866
+ // TODO options.mode global
866
867
  Mode: {
867
868
  Replicated: { Replicas: options.replicas ?? 1 }
868
869
  },
@@ -1135,6 +1136,18 @@ Docker.prototype.updateService = function dockerUpdateService(service, options)
1135
1136
  })
1136
1137
  }
1137
1138
 
1139
+ /**
1140
+ * @name Docker.prototype.deleteService
1141
+ *
1142
+ * @synopsis
1143
+ * ```coffeescript [specscript]
1144
+ * new Docker().deleteService(id string) -> Promise<HttpResponse>
1145
+ * ```
1146
+ */
1147
+ Docker.prototype.deleteService = function deleteService(id) {
1148
+ return this.http.delete(`/services/${id}`)
1149
+ }
1150
+
1138
1151
  /**
1139
1152
  * @name Docker.prototype.listServices
1140
1153
  *
@@ -1188,6 +1201,23 @@ Docker.prototype.getServiceLogs = async function getServiceLogs(serviceId, optio
1188
1201
  }`)
1189
1202
  }
1190
1203
 
1204
+ /**
1205
+ * @name Docker.prototype.listTasks
1206
+ *
1207
+ * @synopsis
1208
+ * ```coffeescript [specscript]
1209
+ * new Docker().listTasks(options {
1210
+ * service?: string,
1211
+ * node?: string,
1212
+ * }) -> Promise<HttpResponse>
1213
+ * ```
1214
+ */
1215
+ Docker.prototype.listTasks = async function listTasks(options) {
1216
+ return this.http.get(`/tasks?${
1217
+ querystring.stringify(pick(['service', 'node'])(options))
1218
+ }`)
1219
+ }
1220
+
1191
1221
  /**
1192
1222
  * @name Docker.prototype.pruneImages
1193
1223
  *
package/Docker.test.js CHANGED
@@ -15,372 +15,401 @@ const {
15
15
  curry, __,
16
16
  } = rubico
17
17
 
18
- module.exports = [
18
+ const test = Test.all([
19
19
  Test('Docker - prune', Docker)
20
- .case(async docker => {
21
- {
22
- const response = await docker.pruneContainers()
23
- assert.equal(response.status, 200)
24
- }
25
- {
26
- const response = await docker.pruneVolumes()
27
- assert.equal(response.status, 200)
28
- }
29
- {
30
- const response = await docker.pruneImages()
31
- assert.equal(response.status, 200)
32
- }
33
- {
34
- const response = await docker.pruneNetworks()
35
- assert.equal(response.status, 200)
36
- }
37
- }),
20
+ .case(async docker => {
21
+ {
22
+ const response = await docker.pruneContainers()
23
+ assert.equal(response.status, 200)
24
+ }
25
+ {
26
+ const response = await docker.pruneVolumes()
27
+ assert.equal(response.status, 200)
28
+ }
29
+ {
30
+ const response = await docker.pruneImages()
31
+ assert.equal(response.status, 200)
32
+ }
33
+ {
34
+ const response = await docker.pruneNetworks()
35
+ assert.equal(response.status, 200)
36
+ }
37
+ }),
38
38
 
39
39
  Test('Docker - auth', Docker)
40
- .case(async docker => {
41
- const response = await docker.auth({
42
- username: 'admin',
43
- password: 'password',
44
- email: 'hey@example.com',
45
- serveraddress: 'localhost:5000',
46
- })
47
- assert.equal(response.status, 200)
48
- const body = await pipe([
49
- reduce((a, b) => a + b, ''),
50
- JSON.parse,
51
- ])(response.body)
52
- this.identitytoken = get('IdentityToken')(body)
53
- assert.equal(this.identitytoken, '')
54
- }),
40
+ .case(async docker => {
41
+ const response = await docker.auth({
42
+ username: 'admin',
43
+ password: 'password',
44
+ email: 'hey@example.com',
45
+ serveraddress: 'localhost:5000',
46
+ })
47
+ assert.equal(response.status, 200)
48
+ const body = await pipe([
49
+ reduce((a, b) => a + b, ''),
50
+ JSON.parse,
51
+ ])(response.body)
52
+ this.identitytoken = get('IdentityToken')(body)
53
+ assert.equal(this.identitytoken, '')
54
+ }),
55
55
 
56
56
  Test('Docker - image', Docker)
57
- .case(async function (docker) {
58
- {
59
- const response = await docker.buildImage('presidium-test:ayo', pathResolve(__dirname), {
60
- archive: {
61
- Dockerfile: `
62
- FROM node:15-alpine
63
- WORKDIR /opt
64
- COPY . .
65
- EXPOSE 8888`,
66
- },
67
- platform: 'linux/x86_64',
68
- })
69
- assert.equal(response.status, 200)
70
- response.body.pipe(process.stdout)
71
- await new Promise(resolve => {
72
- response.body.on('end', resolve)
73
- })
74
- }
75
- {
76
- const response = await docker.listImages()
77
- assert.equal(response.status, 200)
78
- const body = await response.json()
79
- assert(body.length > 1)
80
- this.initialBodyLength = body.length
81
- }
82
- {
83
- const response = await docker.tagImage('presidium-test:ayo', {
84
- tag: 'ayo',
85
- repo: 'localhost:5000/presidium-test',
86
- })
87
- response.body.pipe(process.stdout)
88
- await new Promise(resolve => {
89
- response.body.on('end', resolve)
90
- })
91
- }
92
- {
93
- const response = await docker.pushImage('presidium-test:ayo', 'localhost:5000', {
94
- identitytoken: this.identitytoken,
95
- })
96
- response.body.pipe(process.stdout)
97
- await new Promise(resolve => {
98
- response.body.on('end', resolve)
99
- })
100
- }
101
- {
102
- const response = await docker.inspectImage('localhost:5000/presidium-test:ayo')
103
- assert.equal(response.status, 200)
104
- }
105
- {
106
- const responses = await Promise.all([
107
- docker.removeImage('presidium-test:ayo'),
108
- docker.removeImage('localhost:5000/presidium-test:ayo'),
109
- ])
110
- for (const response of responses) {
111
- const response = await docker.removeImage('presidium-test:ayo')
112
- assert(response.status == 200 || response.status == 404)
113
- }
57
+ .case(async function (docker) {
58
+ {
59
+ const response = await docker.buildImage('presidium-test:ayo', pathResolve(__dirname), {
60
+ archive: {
61
+ Dockerfile: `
62
+ FROM node:15-alpine
63
+ WORKDIR /opt
64
+ COPY . .
65
+ EXPOSE 8888`,
66
+ },
67
+ platform: 'linux/x86_64',
68
+ })
69
+ assert.equal(response.status, 200)
70
+ response.body.pipe(process.stdout)
71
+ await new Promise(resolve => {
72
+ response.body.on('end', resolve)
73
+ })
74
+ }
75
+ {
76
+ const response = await docker.listImages()
77
+ assert.equal(response.status, 200)
78
+ const body = await response.json()
79
+ assert(body.length > 1)
80
+ this.initialBodyLength = body.length
81
+ }
82
+ {
83
+ const response = await docker.tagImage('presidium-test:ayo', {
84
+ tag: 'ayo',
85
+ repo: 'localhost:5000/presidium-test',
86
+ })
87
+ response.body.pipe(process.stdout)
88
+ await new Promise(resolve => {
89
+ response.body.on('end', resolve)
90
+ })
91
+ }
92
+ {
93
+ const response = await docker.pushImage('presidium-test:ayo', 'localhost:5000', {
94
+ identitytoken: this.identitytoken,
95
+ })
96
+ response.body.pipe(process.stdout)
97
+ await new Promise(resolve => {
98
+ response.body.on('end', resolve)
99
+ })
100
+ }
101
+ {
102
+ const response = await docker.inspectImage('localhost:5000/presidium-test:ayo')
103
+ assert.equal(response.status, 200)
104
+ }
105
+ {
106
+ const responses = await Promise.all([
107
+ docker.removeImage('presidium-test:ayo'),
108
+ docker.removeImage('localhost:5000/presidium-test:ayo'),
109
+ ])
110
+ for (const response of responses) {
111
+ const response = await docker.removeImage('presidium-test:ayo')
112
+ assert(response.status == 200 || response.status == 404)
114
113
  }
115
- }),
114
+ }
115
+ }),
116
116
 
117
117
  Test('Docker - container', Docker)
118
- .case(async function (docker) {
119
- {
120
- const createResponse = await docker.createContainer({
121
- name: 'test-alpine-3',
122
- image: 'node:15-alpine',
123
- cmd: ['node', '-e', 'console.log(\'heyy\')'],
124
- rm: true,
125
- })
126
- assert(createResponse.ok)
127
- const containerId = (await createResponse.json()).Id
128
- const attachResponse = await docker.attachContainer(containerId),
129
- startResponse = await docker.startContainer(containerId)
130
- assert(startResponse.ok)
131
- assert(attachResponse.ok)
132
-
133
- const body = await attachResponse.buffer()
134
- assert.equal(body.constructor, Buffer)
135
- assert.strictEqual(body[0], 1) // stdout
136
- assert.strictEqual(body[1], 0) // empty
137
- assert.strictEqual(body[2], 0) // empty
138
- assert.strictEqual(body[3], 0) // empty
139
- assert.strictEqual(body[4], 0) // SIZE1
140
- assert.strictEqual(body[5], 0) // SIZE2
141
- assert.strictEqual(body[6], 0) // SIZE3
142
- assert.strictEqual(body[7], 5) // SIZE4
143
- assert.strictEqual(body.slice(8).toString(), 'heyy\n')
144
-
145
- this.removedContainerId = containerId
146
- }
118
+ .case(async function (docker) {
119
+ {
120
+ const createResponse = await docker.createContainer({
121
+ name: 'test-alpine-3',
122
+ image: 'node:15-alpine',
123
+ cmd: ['node', '-e', 'console.log(\'heyy\')'],
124
+ rm: true,
125
+ })
126
+ assert(createResponse.ok)
127
+ const containerId = (await createResponse.json()).Id
128
+ const attachResponse = await docker.attachContainer(containerId),
129
+ startResponse = await docker.startContainer(containerId)
130
+ assert(startResponse.ok)
131
+ assert(attachResponse.ok)
147
132
 
148
- {
149
- const createResponse = await docker.createContainer({
150
- name: 'test-alpine-1',
151
- image: 'node:15-alpine',
152
- cmd: ['node', '-e', 'console.log(\'hey\')'],
153
- workdir: '/opt/heyo',
154
- expose: [22, 8888, '8889/udp'],
155
- env: { HEY: 'hey' },
156
- volume: ['/opt/my-volume'],
157
- mounts: [{
158
- source: 'other-volume',
159
- target: '/opt/other-volume',
160
- readonly: true,
161
- }],
162
- memory: 512e6, // bytes
163
- restart: 'on-failure:5',
164
-
165
- healthCmd: ['echo', 'ok'],
166
- healthInterval: 1e9,
167
- healthTimeout: 30e9,
168
- healthRetries: 10,
169
- healthStartPeriod: 5e9,
170
-
171
- publish: {
172
- 23: 22, // hostPort -> containerPort[/protocol]
173
- 8888: '8000/tcp',
174
- },
175
- logDriver: 'json-file',
176
- logDriverOptions: {
177
- 'max-file': '10',
178
- 'max-size': '100m',
179
- },
180
- })
181
- assert(createResponse.ok)
182
- const containerId = (await createResponse.json()).Id
183
- this.containerId = containerId
184
- const attachResponse = await docker.attachContainer(containerId),
185
- startResponse = await docker.startContainer(containerId)
186
- assert(startResponse.ok)
187
- assert(attachResponse.ok)
188
-
189
- const body = await attachResponse.buffer()
190
- assert.equal(body.constructor, Buffer)
191
- assert.strictEqual(body[0], 1) // stdout
192
- assert.strictEqual(body[1], 0) // empty
193
- assert.strictEqual(body[2], 0) // empty
194
- assert.strictEqual(body[3], 0) // empty
195
- assert.strictEqual(body[4], 0) // SIZE1
196
- assert.strictEqual(body[5], 0) // SIZE2
197
- assert.strictEqual(body[6], 0) // SIZE3
198
- assert.strictEqual(body[7], 4) // SIZE4
199
- assert.strictEqual(body.slice(8).toString(), 'hey\n')
200
- }
133
+ const body = await attachResponse.buffer()
134
+ assert.equal(body.constructor, Buffer)
135
+ assert.strictEqual(body[0], 1) // stdout
136
+ assert.strictEqual(body[1], 0) // empty
137
+ assert.strictEqual(body[2], 0) // empty
138
+ assert.strictEqual(body[3], 0) // empty
139
+ assert.strictEqual(body[4], 0) // SIZE1
140
+ assert.strictEqual(body[5], 0) // SIZE2
141
+ assert.strictEqual(body[6], 0) // SIZE3
142
+ assert.strictEqual(body[7], 5) // SIZE4
143
+ assert.strictEqual(body.slice(8).toString(), 'heyy\n')
201
144
 
202
- {
203
- const createResponse = await docker.createContainer({
204
- name: 'test-alpine-2',
205
- image: 'node:15-alpine',
206
- cmd: ['node', '-e', 'http.createServer((request, response) => response.end(\'hey0\')).listen(2999)'],
207
- rm: true,
208
- })
209
- assert(createResponse.ok)
210
- const containerId = (await createResponse.json()).Id
211
- assert((await docker.startContainer(containerId)).ok)
212
- const execResponse = await docker.execContainer(containerId, ['node', '-e', 'console.log(\'heyyy\')'])
213
- const body = await execResponse.buffer()
214
- assert.equal(body.constructor, Buffer)
215
- assert.strictEqual(body[0], 1) // stdout
216
- assert.strictEqual(body[1], 0) // empty
217
- assert.strictEqual(body[2], 0) // empty
218
- assert.strictEqual(body[3], 0) // empty
219
- assert.strictEqual(body[4], 0) // SIZE1
220
- assert.strictEqual(body[5], 0) // SIZE2
221
- assert.strictEqual(body[6], 0) // SIZE3
222
- assert.strictEqual(body[7], 6) // SIZE4
223
- assert.strictEqual(body.slice(8).toString(), 'heyyy\n')
224
- await docker.stopContainer(containerId, { time: 1 })
225
- }
145
+ this.removedContainerId = containerId
146
+ }
226
147
 
227
- {
228
- const response = await docker.inspectContainer(this.containerId)
229
- assert.equal(response.status, 200)
230
- const body = await response.json()
231
- assert.equal(body.Config.Image, 'node:15-alpine')
232
- assert.deepEqual(body.Config.Volumes, { '/opt/my-volume': {} })
233
- assert.equal(body.Config.WorkingDir, '/opt/heyo')
234
- assert.deepEqual(body.Config.ExposedPorts, { '22/tcp': {}, '8888/tcp': {}, '8889/udp': {} })
235
- assert.equal(body.HostConfig.Memory, 512e6)
236
- assert.deepEqual(body.HostConfig.PortBindings, {
237
- '22/tcp': [{ HostIp: '', HostPort: '23' }],
238
- '8000/tcp': [{ HostIp: '', HostPort: '8888' }]
239
- })
240
- assert.deepEqual(body.HostConfig.LogConfig, {
241
- Type: 'json-file',
242
- Config: {
243
- 'max-file': '10',
244
- 'max-size': '100m',
245
- },
246
- })
247
- assert.deepEqual(body.Config.Healthcheck, {
248
- Test: ['CMD', 'echo', 'ok'],
249
- Interval: 1000000000,
250
- Timeout: 30000000000,
251
- StartPeriod: 5000000000,
252
- Retries: 10,
253
- })
254
- assert.deepEqual(body.HostConfig.Mounts, [{
255
- Type: 'volume',
256
- Source: 'other-volume',
257
- Target: '/opt/other-volume',
258
- ReadOnly: true
259
- }])
260
- }
148
+ {
149
+ const createResponse = await docker.createContainer({
150
+ name: 'test-alpine-1',
151
+ image: 'node:15-alpine',
152
+ cmd: ['node', '-e', 'console.log(\'hey\')'],
153
+ workdir: '/opt/heyo',
154
+ expose: [22, 8888, '8889/udp'],
155
+ env: { HEY: 'hey' },
156
+ volume: ['/opt/my-volume'],
157
+ mounts: [{
158
+ source: 'other-volume',
159
+ target: '/opt/other-volume',
160
+ readonly: true,
161
+ }],
162
+ memory: 512e6, // bytes
163
+ restart: 'on-failure:5',
261
164
 
262
- {
263
- const containersResponse = await docker.listContainers()
264
- assert.equal(containersResponse.status, 200)
265
- const body = await containersResponse.json()
266
- assert(!body.map(get('Id')).includes(this.removedContainerId))
267
- }
268
- }),
165
+ healthCmd: ['echo', 'ok'],
166
+ healthInterval: 1e9,
167
+ healthTimeout: 30e9,
168
+ healthRetries: 10,
169
+ healthStartPeriod: 5e9,
170
+
171
+ publish: {
172
+ 23: 22, // hostPort -> containerPort[/protocol]
173
+ 8888: '8000/tcp',
174
+ },
175
+ logDriver: 'json-file',
176
+ logDriverOptions: {
177
+ 'max-file': '10',
178
+ 'max-size': '100m',
179
+ },
180
+ })
181
+ assert(createResponse.ok)
182
+ const containerId = (await createResponse.json()).Id
183
+ this.containerId = containerId
184
+ const attachResponse = await docker.attachContainer(containerId),
185
+ startResponse = await docker.startContainer(containerId)
186
+ assert(startResponse.ok)
187
+ assert(attachResponse.ok)
188
+
189
+ const body = await attachResponse.buffer()
190
+ assert.equal(body.constructor, Buffer)
191
+ assert.strictEqual(body[0], 1) // stdout
192
+ assert.strictEqual(body[1], 0) // empty
193
+ assert.strictEqual(body[2], 0) // empty
194
+ assert.strictEqual(body[3], 0) // empty
195
+ assert.strictEqual(body[4], 0) // SIZE1
196
+ assert.strictEqual(body[5], 0) // SIZE2
197
+ assert.strictEqual(body[6], 0) // SIZE3
198
+ assert.strictEqual(body[7], 4) // SIZE4
199
+ assert.strictEqual(body.slice(8).toString(), 'hey\n')
200
+ }
201
+
202
+ {
203
+ const createResponse = await docker.createContainer({
204
+ name: 'test-alpine-2',
205
+ image: 'node:15-alpine',
206
+ cmd: ['node', '-e', 'http.createServer((request, response) => response.end(\'hey0\')).listen(2999)'],
207
+ rm: true,
208
+ })
209
+ assert(createResponse.ok)
210
+ const containerId = (await createResponse.json()).Id
211
+ assert((await docker.startContainer(containerId)).ok)
212
+ const execResponse = await docker.execContainer(containerId, ['node', '-e', 'console.log(\'heyyy\')'])
213
+ const body = await execResponse.buffer()
214
+ assert.equal(body.constructor, Buffer)
215
+ assert.strictEqual(body[0], 1) // stdout
216
+ assert.strictEqual(body[1], 0) // empty
217
+ assert.strictEqual(body[2], 0) // empty
218
+ assert.strictEqual(body[3], 0) // empty
219
+ assert.strictEqual(body[4], 0) // SIZE1
220
+ assert.strictEqual(body[5], 0) // SIZE2
221
+ assert.strictEqual(body[6], 0) // SIZE3
222
+ assert.strictEqual(body[7], 6) // SIZE4
223
+ assert.strictEqual(body.slice(8).toString(), 'heyyy\n')
224
+ await docker.stopContainer(containerId, { time: 1 })
225
+ }
226
+
227
+ {
228
+ const response = await docker.inspectContainer(this.containerId)
229
+ assert.equal(response.status, 200)
230
+ const body = await response.json()
231
+ assert.equal(body.Config.Image, 'node:15-alpine')
232
+ assert.deepEqual(body.Config.Volumes, { '/opt/my-volume': {} })
233
+ assert.equal(body.Config.WorkingDir, '/opt/heyo')
234
+ assert.deepEqual(body.Config.ExposedPorts, { '22/tcp': {}, '8888/tcp': {}, '8889/udp': {} })
235
+ assert.equal(body.HostConfig.Memory, 512e6)
236
+ assert.deepEqual(body.HostConfig.PortBindings, {
237
+ '22/tcp': [{ HostIp: '', HostPort: '23' }],
238
+ '8000/tcp': [{ HostIp: '', HostPort: '8888' }]
239
+ })
240
+ assert.deepEqual(body.HostConfig.LogConfig, {
241
+ Type: 'json-file',
242
+ Config: {
243
+ 'max-file': '10',
244
+ 'max-size': '100m',
245
+ },
246
+ })
247
+ assert.deepEqual(body.Config.Healthcheck, {
248
+ Test: ['CMD', 'echo', 'ok'],
249
+ Interval: 1000000000,
250
+ Timeout: 30000000000,
251
+ StartPeriod: 5000000000,
252
+ Retries: 10,
253
+ })
254
+ assert.deepEqual(body.HostConfig.Mounts, [{
255
+ Type: 'volume',
256
+ Source: 'other-volume',
257
+ Target: '/opt/other-volume',
258
+ ReadOnly: true
259
+ }])
260
+ }
261
+
262
+ {
263
+ const containersResponse = await docker.listContainers()
264
+ assert.equal(containersResponse.status, 200)
265
+ const body = await containersResponse.json()
266
+ assert(!body.map(get('Id')).includes(this.removedContainerId))
267
+ }
268
+ }),
269
269
 
270
270
  Test('Docker - swarm and service', Docker)
271
- .case(async function (docker) {
272
- {
273
- const response = await docker.leaveSwarm({ force: true })
274
- assert([200, 503].includes(response.status))
275
- }
276
- {
277
- const response = await docker.initSwarm('[::1]:2377')
278
- assert.equal(response.status, 200)
279
- }
280
- {
281
- const response = await docker.inspectSwarm()
282
- assert.equal(response.status, 200)
283
- const body = await response.json()
284
- assert.equal(typeof body.JoinTokens.Worker, 'string')
285
- assert.equal(typeof body.JoinTokens.Manager, 'string')
286
- this.workerJoinToken = body.JoinTokens.Worker
287
- }
271
+ .case(async function (docker) {
272
+ { // initial leaveSwarm
273
+ const response = await docker.leaveSwarm({ force: true })
274
+ assert([200, 503].includes(response.status))
275
+ }
288
276
 
289
- {
290
- const response = await docker.createService('hey1', {
291
- image: 'node:15-alpine',
292
- replicas: 2,
293
- cmd: ['node', '-e', 'http.createServer((request, response) => response.end(\'hey1\')).listen(3000)'],
294
- workdir: '/opt/heyo',
295
- env: { HEY: 'hey' },
296
- mounts: [{
297
- source: 'other-volume',
298
- target: '/opt/other-volume',
299
- readonly: true,
300
- }],
301
- memory: 512e6, // bytes
302
- restart: 'on-failure:5',
303
-
304
- healthCmd: ['wget', '--no-verbose', '--tries=1', '--spider', 'localhost:3000'],
305
- healthInterval: 1e9,
306
- healthTimeout: 30e9,
307
- healthRetries: 10,
308
- healthStartPeriod: 5e9,
309
-
310
- publish: {
311
- 23: 22, // hostPort -> containerPort[/protocol]
312
- 8080: 3000,
313
- },
314
-
315
- logDriver: 'json-file',
316
- logDriverOptions: {
317
- 'max-file': '10',
318
- 'max-size': '100m',
319
- },
320
- })
321
- assert.equal(response.status, 201)
322
- const body = await response.json()
323
- this.serviceId = body.ID
324
- }
277
+ { // initSwarm
278
+ const response = await docker.initSwarm('[::1]:2377')
279
+ assert.equal(response.status, 200)
280
+ }
325
281
 
326
- {
327
- const response = await docker.createService('hey2', {
328
- image: 'node:15-alpine',
329
- replicas: 2,
330
- cmd: ['node', '-e', 'http.createServer((request, response) => response.end(\'hey2\')).listen(3001)'],
331
- workdir: '/opt/heyo',
332
- env: { HEY: 'hey' },
333
- mounts: [{
334
- source: 'other-volume',
335
- target: '/opt/other-volume',
336
- readonly: true,
337
- }],
338
- memory: 512e6, // bytes
339
- restart: 'on-failure',
340
- publish: { 8081: 3001 },
341
-
342
- healthCmd: ['wget', '--no-verbose', '--tries=1', '--spider', 'localhost:3001'],
343
- })
344
- assert.equal(response.status, 201)
345
- }
346
- {
347
- const response = await docker.listServices()
348
- assert.equal(response.status, 200)
349
- const body = await response.json()
350
- assert.equal(body.length, 2)
351
- }
352
- {
353
- const response = await docker.inspectService(this.serviceId)
354
- assert.equal(response.status, 200)
355
- }
282
+ { // inspectSwarm
283
+ const response = await docker.inspectSwarm()
284
+ assert.equal(response.status, 200)
285
+ const body = await response.json()
286
+ assert.equal(typeof body.JoinTokens.Worker, 'string')
287
+ assert.equal(typeof body.JoinTokens.Manager, 'string')
288
+ this.workerJoinToken = body.JoinTokens.Worker
289
+ }
356
290
 
357
- {
358
- const response = await docker.leaveSwarm()
359
- assert.equal(response.status, 503)
360
- assert((await response.json()).message.startsWith('You are attempting to leave'))
361
- }
362
- {
363
- const response = await docker.leaveSwarm({ force: true })
364
- assert.equal(response.status, 200)
365
- }
291
+ { // create a service
292
+ const response = await docker.createService('hey1', {
293
+ image: 'node:15-alpine',
294
+ replicas: 2,
295
+ cmd: ['node', '-e', 'http.createServer((request, response) => response.end(\'hey1\')).listen(3000)'],
296
+ workdir: '/opt/heyo',
297
+ env: { HEY: 'hey' },
298
+ mounts: [{
299
+ source: 'other-volume',
300
+ target: '/opt/other-volume',
301
+ readonly: true,
302
+ }],
303
+ memory: 512e6, // bytes
304
+ restart: 'on-failure:5',
366
305
 
367
- await Promise.all([ // TODO figure out a real test for join. Checking for the 503 is ok but is both slow and not a 200
368
- docker.joinSwarm('[::1]:2377', this.workerJoinToken, {
369
- listenAddr: 'hey',
370
- }).then(async response => {
371
- console.log('hey1', await response.text())
372
- // assert.equal(response.status, 503)
373
- assert.equal(response.status, 400)
374
- }),
375
- docker.joinSwarm('[::1]:2377', this.workerJoinToken, {
376
- advertiseAddr: '[::1]:2377',
377
- listenAddr: 'hey',
378
- dataPathAddr: '127.0.0.1',
379
- }).then(async response => {
380
- console.log('hey2', await response.text())
381
- // assert.equal(response.status, 503)
382
- assert.equal(response.status, 400)
383
- }),
384
- ])
385
- }),
386
- ]
306
+ healthCmd: ['wget', '--no-verbose', '--tries=1', '--spider', 'localhost:3000'],
307
+ healthInterval: 1e9,
308
+ healthTimeout: 30e9,
309
+ healthRetries: 10,
310
+ healthStartPeriod: 5e9,
311
+
312
+ publish: {
313
+ // 23: 22, // hostPort -> containerPort[/protocol]
314
+ 8080: 3000,
315
+ },
316
+
317
+ logDriver: 'json-file',
318
+ logDriverOptions: {
319
+ 'max-file': '10',
320
+ 'max-size': '100m',
321
+ },
322
+ })
323
+ assert.equal(response.status, 201)
324
+ const body = await response.json()
325
+ this.serviceId = body.ID
326
+ }
327
+
328
+ { // create another service
329
+ const response = await docker.createService('hey2', {
330
+ image: 'node:15-alpine',
331
+ replicas: 2,
332
+ cmd: ['node', '-e', 'http.createServer((request, response) => response.end(\'hey2\')).listen(3001)'],
333
+ workdir: '/opt/heyo',
334
+ env: { HEY: 'hey' },
335
+ mounts: [{
336
+ source: 'other-volume',
337
+ target: '/opt/other-volume',
338
+ readonly: true,
339
+ }],
340
+ memory: 512e6, // bytes
341
+ restart: 'on-failure',
342
+ publish: { 8081: 3001 },
343
+
344
+ healthCmd: ['wget', '--no-verbose', '--tries=1', '--spider', 'localhost:3001'],
345
+ })
346
+ assert.equal(response.status, 201)
347
+ }
348
+
349
+ { // listServices
350
+ const response = await docker.listServices()
351
+ assert.equal(response.status, 200)
352
+ const body = await response.json()
353
+ assert.equal(body.length, 2)
354
+ }
355
+
356
+ { // listTasks
357
+ const response = await docker.listTasks()
358
+ const body = await response.json()
359
+ assert.equal(body.length, 4) // 2 for hey1, 2 for hey2
360
+ }
361
+
362
+ { // inspectService
363
+ const response = await docker.inspectService(this.serviceId)
364
+ assert.equal(response.status, 200)
365
+ }
366
+
367
+ { // deleteService
368
+ const response = await docker.deleteService(this.serviceId)
369
+ assert.equal(response.status, 200)
370
+ }
371
+
372
+ { // listServices again
373
+ const response = await docker.listServices()
374
+ assert.equal(response.status, 200)
375
+ const body = await response.json()
376
+ assert.equal(body.length, 1)
377
+ }
378
+
379
+ { // leaveSwarm without forcing
380
+ const response = await docker.leaveSwarm()
381
+ assert.equal(response.status, 503)
382
+ assert((await response.json()).message.startsWith('You are attempting to leave'))
383
+ }
384
+
385
+ { // force leaveSwarm
386
+ const response = await docker.leaveSwarm({ force: true })
387
+ assert.equal(response.status, 200)
388
+ }
389
+
390
+ await Promise.all([ // TODO figure out a real test for join. Checking for the 503 is ok but is both slow and not a 200
391
+ docker.joinSwarm('[::1]:2377', this.workerJoinToken, {
392
+ listenAddr: 'hey',
393
+ }).then(async response => {
394
+ console.log('hey1', await response.text())
395
+ // assert.equal(response.status, 503)
396
+ assert.equal(response.status, 400)
397
+ }),
398
+ docker.joinSwarm('[::1]:2377', this.workerJoinToken, {
399
+ advertiseAddr: '[::1]:2377',
400
+ listenAddr: 'hey',
401
+ dataPathAddr: '127.0.0.1',
402
+ }).then(async response => {
403
+ console.log('hey2', await response.text())
404
+ // assert.equal(response.status, 503)
405
+ assert.equal(response.status, 400)
406
+ }),
407
+ ])
408
+ }),
409
+ ])
410
+
411
+ if (process.argv[1] == __filename) {
412
+ test()
413
+ }
414
+
415
+ module.exports = test
package/DockerService.js CHANGED
@@ -47,7 +47,7 @@ const dockerServiceOptions = [
47
47
  * name: string,
48
48
  * image: string,
49
49
  * replicas: 1|number,
50
- * restart: 'no'|'on-failure[:<max-retries>]'|'always'|'unless-stopped',
50
+ * restart: 'no'|'on-failure[:<max-retries>]'|'any',
51
51
  * restartDelay: 10e9|number, // nanoseconds to delay between restarts
52
52
  * logDriver: 'json-file'|'syslog'|'journald'|'gelf'|'fluentd'|'awslogs'|'splunk'|'none',
53
53
  * logDriverOptions: Object<string>,
@@ -155,7 +155,7 @@ DockerService.prototype.synchronize = function dockerServiceSynchronize() {
155
155
  *
156
156
  * image: string,
157
157
  * replicas: 1|number,
158
- * restart: 'no'|'on-failure[:<max-retries>]'|'always'|'unless-stopped',
158
+ * restart: 'no'|'on-failure[:<max-retries>]'|'any',
159
159
  * restartDelay: 10e9|number, // nanoseconds to delay between restarts
160
160
  * logDriver: 'json-file'|'syslog'|'journald'|'gelf'|'fluentd'|'awslogs'|'splunk'|'none',
161
161
  * logDriverOptions: Object<string>,
package/DynamoStream.js CHANGED
@@ -42,6 +42,8 @@ const {
42
42
  * https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDBStreams.html
43
43
  *
44
44
  * DynamoStream -> Stream Headers -> Stream ARNs
45
+ *
46
+ * `eventName` enumeration: `INSERT`, `MODIFY`, `REMOVE`
45
47
  */
46
48
 
47
49
  const DynamoStream = function (options) {
package/DynamoTable.js CHANGED
@@ -146,6 +146,8 @@ DynamoTable.prototype.putItem = async function dynamoTablePutItem(item, options)
146
146
  ...options,
147
147
  }).promise().catch(error => {
148
148
  error.tableName = this.name
149
+ error.method = 'putItem'
150
+ error.item = item
149
151
  throw error
150
152
  })
151
153
  }
@@ -172,6 +174,8 @@ DynamoTable.prototype.getItem = async function dynamoTableGetItem(key) {
172
174
  return result
173
175
  }).catch(error => {
174
176
  error.tableName = this.name
177
+ error.method = 'getItem'
178
+ error.key = key
175
179
  throw error
176
180
  })
177
181
  }
@@ -233,6 +237,9 @@ DynamoTable.prototype.updateItem = async function dynamoTableUpdateItem(
233
237
  ...options,
234
238
  }).promise().catch(error => {
235
239
  error.tableName = this.name
240
+ error.method = 'updateItem'
241
+ error.key = key
242
+ error.updates = updates
236
243
  throw error
237
244
  })
238
245
  }
@@ -276,6 +283,9 @@ DynamoTable.prototype.incrementItem = async function incrementItem(
276
283
  ...options,
277
284
  }).promise().catch(error => {
278
285
  error.tableName = this.name
286
+ error.method = 'incrementItem'
287
+ error.key = key
288
+ error.incrementUpdates = incrementUpdates
279
289
  throw error
280
290
  })
281
291
  }
@@ -303,6 +313,8 @@ DynamoTable.prototype.deleteItem = async function dynamoTableDeleteItem(key, opt
303
313
  ...options,
304
314
  }).promise().catch(error => {
305
315
  error.tableName = this.name
316
+ error.method = 'deleteItem'
317
+ error.key = key
306
318
  throw error
307
319
  })
308
320
  }
@@ -335,6 +347,7 @@ DynamoTable.prototype.scan = async function scan(options = {}) {
335
347
  },
336
348
  }).promise().catch(error => {
337
349
  error.tableName = this.name
350
+ error.method = 'scan'
338
351
  throw error
339
352
  })
340
353
  }
@@ -184,6 +184,7 @@ TranscribeStream.prototype.sendAudioChunk = function (chunk) {
184
184
 
185
185
  TranscribeStream.prototype.close = function () {
186
186
  this.websocket.close()
187
+ this.emit('close')
187
188
  }
188
189
 
189
190
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "presidium",
3
- "version": "0.15.32",
3
+ "version": "0.15.36",
4
4
  "description": "A library for creating web services",
5
5
  "author": "Richard Tong",
6
6
  "license": "MIT",