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.
- package/.github/workflows/nodejs.yml +52 -13
- package/Docker.js +30 -0
- package/Docker.test.js +380 -351
- package/DockerService.js +2 -2
- package/DynamoStream.js +2 -0
- package/DynamoTable.js +13 -0
- package/TranscribeStream.js +1 -0
- package/package.json +1 -1
|
@@ -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
|
-
|
|
18
|
+
const test = Test.all([
|
|
19
19
|
Test('Docker - prune', Docker)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
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
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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>]'|'
|
|
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>]'|'
|
|
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
|
}
|
package/TranscribeStream.js
CHANGED