docker-storage-gc 4.0.0 → 4.0.1
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/.versionbot/CHANGELOG.yml +19 -1
- package/CHANGELOG.md +6 -0
- package/build/docker-event-stream.d.ts +1 -2
- package/build/docker-event-stream.js +9 -5
- package/build/docker-event-stream.js.map +1 -1
- package/build/docker-image-tree.d.ts +1 -2
- package/build/docker-image-tree.js +6 -6
- package/build/docker-image-tree.js.map +1 -1
- package/build/docker.d.ts +1 -1
- package/build/docker.js +5 -6
- package/build/docker.js.map +1 -1
- package/build/index.js +67 -74
- package/build/index.js.map +1 -1
- package/lib/docker-event-stream.ts +30 -32
- package/lib/docker-image-tree.ts +7 -6
- package/lib/docker.ts +5 -6
- package/lib/index.ts +87 -95
- package/package.json +2 -2
- package/test/docker-event-stream.ts +26 -30
- package/test/docker-image-tree.ts +102 -105
- package/test/index.ts +127 -142
package/test/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type Docker from 'dockerode';
|
|
2
|
-
import Bluebird from 'bluebird';
|
|
3
2
|
import { expect } from 'chai';
|
|
4
3
|
import DockerGC from '../build/index';
|
|
5
4
|
import { getDocker } from '../build/docker';
|
|
@@ -14,19 +13,23 @@ const NONE_TAG_IMAGES = [
|
|
|
14
13
|
'balenaplayground/hello-world@sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042',
|
|
15
14
|
];
|
|
16
15
|
|
|
17
|
-
const promiseToBool = (p: Promise<unknown>): Promise<boolean> =>
|
|
18
|
-
|
|
16
|
+
const promiseToBool = async (p: Promise<unknown>): Promise<boolean> => {
|
|
17
|
+
try {
|
|
18
|
+
await p;
|
|
19
|
+
return true;
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
19
24
|
|
|
20
|
-
const pullAsync = function (docker: Docker, tag: string) {
|
|
25
|
+
const pullAsync = async function (docker: Docker, tag: string) {
|
|
21
26
|
console.log(`[TEST] Pulling ${tag}`);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}),
|
|
29
|
-
);
|
|
27
|
+
const stream = await docker.pull(tag);
|
|
28
|
+
return await new Promise(function (resolve, reject) {
|
|
29
|
+
stream.resume();
|
|
30
|
+
stream.once('error', reject);
|
|
31
|
+
stream.once('end', resolve);
|
|
32
|
+
});
|
|
30
33
|
};
|
|
31
34
|
|
|
32
35
|
// This test case is a little weird, it requires that no other images are present on
|
|
@@ -35,194 +38,176 @@ const pullAsync = function (docker: Docker, tag: string) {
|
|
|
35
38
|
describe('Garbage collection', function () {
|
|
36
39
|
let dockerStorage: DockerGC;
|
|
37
40
|
let docker: Docker;
|
|
38
|
-
beforeEach(function () {
|
|
41
|
+
beforeEach(async function () {
|
|
39
42
|
dockerStorage = new DockerGC();
|
|
40
43
|
// Use either local or CI docker
|
|
41
|
-
|
|
44
|
+
const [$docker] = await Promise.all([
|
|
42
45
|
getDocker({
|
|
43
46
|
socketPath: '/tmp/dind/docker.sock',
|
|
44
47
|
}),
|
|
45
48
|
dockerStorage.setDocker({
|
|
46
49
|
socketPath: '/tmp/dind/docker.sock',
|
|
47
50
|
}),
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
},
|
|
52
|
-
);
|
|
51
|
+
]);
|
|
52
|
+
docker = $docker;
|
|
53
|
+
return await dockerStorage.setupMtimeStream();
|
|
53
54
|
});
|
|
54
55
|
|
|
55
56
|
afterEach(function () {
|
|
56
57
|
console.log('[afterEach] Cleaning up...');
|
|
57
|
-
return IMAGES.concat(NONE_TAG_IMAGES).map((image) =>
|
|
58
|
-
|
|
59
|
-
.getImage(image)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
);
|
|
58
|
+
return IMAGES.concat(NONE_TAG_IMAGES).map(async (image) => {
|
|
59
|
+
try {
|
|
60
|
+
return await docker.getImage(image).remove();
|
|
61
|
+
} catch {
|
|
62
|
+
// ignore
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
it('should remove a image by tag', function () {
|
|
67
|
+
it('should remove a image by tag', async function () {
|
|
68
68
|
this.timeout(600000);
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
.
|
|
70
|
+
await pullAsync(docker, IMAGES[0]);
|
|
71
|
+
await docker.getImage(IMAGES[0]).inspect();
|
|
72
|
+
await dockerStorage.garbageCollect(1);
|
|
73
|
+
const imageFound = await promiseToBool(
|
|
74
|
+
docker.getImage(IMAGES[0]).inspect(),
|
|
75
|
+
);
|
|
76
|
+
expect(imageFound).to.be.false;
|
|
75
77
|
});
|
|
76
78
|
|
|
77
|
-
it('should remove a image by digest if its tag == none', function () {
|
|
79
|
+
it('should remove a image by digest if its tag == none', async function () {
|
|
78
80
|
this.timeout(600000);
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
.
|
|
82
|
+
await pullAsync(docker, NONE_TAG_IMAGES[0]);
|
|
83
|
+
await docker.getImage(NONE_TAG_IMAGES[0]).inspect();
|
|
84
|
+
await dockerStorage.garbageCollect(1);
|
|
85
|
+
const imageFound = await promiseToBool(
|
|
86
|
+
docker.getImage(NONE_TAG_IMAGES[0]).inspect(),
|
|
87
|
+
);
|
|
88
|
+
expect(imageFound).to.be.false;
|
|
85
89
|
});
|
|
86
90
|
|
|
87
|
-
it('should remove a image with tag == none even if it is in several repos', function () {
|
|
91
|
+
it('should remove a image with tag == none even if it is in several repos', async function () {
|
|
88
92
|
this.timeout(600000);
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
for (const image of NONE_TAG_IMAGES) {
|
|
95
|
+
await pullAsync(docker, image);
|
|
96
|
+
}
|
|
97
|
+
await docker.getImage(NONE_TAG_IMAGES[0]).inspect();
|
|
98
|
+
await dockerStorage.garbageCollect(1);
|
|
99
|
+
const imagesFound = await Promise.all(
|
|
100
|
+
NONE_TAG_IMAGES.map((image) =>
|
|
101
|
+
promiseToBool(docker.getImage(image).inspect()),
|
|
102
|
+
),
|
|
103
|
+
);
|
|
104
|
+
expect(imagesFound).to.deep.equal([false, false]);
|
|
99
105
|
});
|
|
100
106
|
|
|
101
|
-
it('should remove all tags of an image', function () {
|
|
107
|
+
it('should remove all tags of an image', async function () {
|
|
102
108
|
this.timeout(600000);
|
|
103
109
|
if (SKIP_GC_TEST) {
|
|
104
|
-
return
|
|
110
|
+
return;
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
// first pull some images, so we know in which order they are referenced
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
await pullAsync(docker, IMAGES[0]);
|
|
115
|
+
await docker
|
|
116
|
+
.getImage(IMAGES[0])
|
|
117
|
+
.tag({ repo: 'some-repo', tag: 'some-tag' });
|
|
118
|
+
await dockerStorage.garbageCollect(1);
|
|
119
|
+
const imagesFound = await promiseToBool(
|
|
120
|
+
docker.getImage(IMAGES[0]).inspect(),
|
|
121
|
+
);
|
|
122
|
+
expect(imagesFound).to.be.false;
|
|
117
123
|
});
|
|
118
124
|
|
|
119
|
-
it('should remove the LRU image', function () {
|
|
125
|
+
it('should remove the LRU image', async function () {
|
|
120
126
|
this.timeout(600000);
|
|
121
127
|
if (SKIP_GC_TEST) {
|
|
122
|
-
return
|
|
128
|
+
return;
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
// first pull some images, so we know in which order they are referenced
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
.then(() =>
|
|
139
|
-
Bluebird.map(IMAGES, (image) =>
|
|
140
|
-
promiseToBool(docker.getImage(image).inspect()),
|
|
141
|
-
),
|
|
142
|
-
)
|
|
143
|
-
.then((imagesFound) =>
|
|
144
|
-
expect(imagesFound).to.deep.equal([false, true, true]),
|
|
145
|
-
);
|
|
132
|
+
await pullAsync(docker, IMAGES[0]);
|
|
133
|
+
await docker
|
|
134
|
+
.getImage(IMAGES[0])
|
|
135
|
+
.tag({ repo: 'some-repo', tag: 'some-tag' });
|
|
136
|
+
for (const image of IMAGES.slice(1)) {
|
|
137
|
+
await pullAsync(docker, image);
|
|
138
|
+
}
|
|
139
|
+
await dockerStorage.garbageCollect(1);
|
|
140
|
+
const imagesFound = await Promise.all(
|
|
141
|
+
IMAGES.map((image) => promiseToBool(docker.getImage(image).inspect())),
|
|
142
|
+
);
|
|
143
|
+
expect(imagesFound).to.deep.equal([false, true, true]);
|
|
146
144
|
});
|
|
147
145
|
|
|
148
|
-
it('should remove more than one image if necessary', function () {
|
|
146
|
+
it('should remove more than one image if necessary', async function () {
|
|
149
147
|
this.timeout(600000);
|
|
150
148
|
if (SKIP_GC_TEST) {
|
|
151
|
-
return
|
|
149
|
+
return;
|
|
152
150
|
}
|
|
153
151
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
})
|
|
166
|
-
.then(() =>
|
|
167
|
-
Bluebird.map(IMAGES, (image) =>
|
|
168
|
-
promiseToBool(docker.getImage(image).inspect()),
|
|
169
|
-
),
|
|
170
|
-
)
|
|
171
|
-
.then((imagesFound) =>
|
|
172
|
-
expect(imagesFound).to.deep.equal([false, false, true]),
|
|
173
|
-
);
|
|
152
|
+
for (const image of IMAGES) {
|
|
153
|
+
await pullAsync(docker, image);
|
|
154
|
+
}
|
|
155
|
+
// Get the size of the first image, so we can add one to it to remove
|
|
156
|
+
// the next one in addition
|
|
157
|
+
const { Size: size } = await docker.getImage(IMAGES[0]).inspect();
|
|
158
|
+
await dockerStorage.garbageCollect(size + 1);
|
|
159
|
+
const imagesFound = await Promise.all(
|
|
160
|
+
IMAGES.map((image) => promiseToBool(docker.getImage(image).inspect())),
|
|
161
|
+
);
|
|
162
|
+
expect(imagesFound).to.deep.equal([false, false, true]);
|
|
174
163
|
});
|
|
175
164
|
|
|
176
|
-
it('should not consider images in use', function () {
|
|
165
|
+
it('should not consider images in use', async function () {
|
|
177
166
|
this.timeout(600000);
|
|
178
167
|
const containerName = 'dont-consider-images-in-use-test';
|
|
179
168
|
if (SKIP_GC_TEST) {
|
|
180
|
-
return
|
|
169
|
+
return;
|
|
181
170
|
}
|
|
182
171
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
172
|
+
try {
|
|
173
|
+
await pullAsync(docker, IMAGES[0]);
|
|
174
|
+
const container = await docker.createContainer({
|
|
175
|
+
Image: IMAGES[0],
|
|
176
|
+
Tty: true,
|
|
177
|
+
Cmd: ['sh', '-c', 'while true; do echo test; sleep 1; done'],
|
|
178
|
+
name: containerName,
|
|
179
|
+
HostConfig: { AutoRemove: true },
|
|
180
|
+
});
|
|
181
|
+
await container.start();
|
|
182
|
+
await dockerStorage.garbageCollect(1);
|
|
183
|
+
const imageInspect = await promiseToBool(
|
|
184
|
+
docker.getImage(IMAGES[0]).inspect(),
|
|
185
|
+
);
|
|
186
|
+
expect(imageInspect).to.be.true;
|
|
187
|
+
} finally {
|
|
188
|
+
await docker.getContainer(containerName).stop();
|
|
189
|
+
}
|
|
200
190
|
});
|
|
201
191
|
|
|
202
|
-
it('should get daemon host disk usage', function () {
|
|
192
|
+
it('should get daemon host disk usage', async function () {
|
|
203
193
|
this.timeout(600000);
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
});
|
|
194
|
+
const du = await dockerStorage.getDaemonFreeSpace();
|
|
195
|
+
expect(du).to.be.an('object');
|
|
196
|
+
expect(du).to.have.property('free').that.is.a('number');
|
|
197
|
+
expect(du).to.have.property('used').that.is.a('number');
|
|
198
|
+
expect(du).to.have.property('total').that.is.a('number');
|
|
210
199
|
});
|
|
211
200
|
|
|
212
|
-
it('should get the correct architecture for a remote host', function () {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
.getDaemonArchitecture() as Promise<string>
|
|
218
|
-
).then((arch) => expect(arch).to.be.a('string'))
|
|
219
|
-
);
|
|
201
|
+
it('should get the correct architecture for a remote host', async function () {
|
|
202
|
+
const arch = (await dockerStorage
|
|
203
|
+
// @ts-expect-error getDaemonArchitecture is private
|
|
204
|
+
.getDaemonArchitecture()) as Promise<string>;
|
|
205
|
+
expect(arch).to.be.a('string');
|
|
220
206
|
});
|
|
221
207
|
|
|
222
|
-
it('should set a base image to be used', function () {
|
|
208
|
+
it('should set a base image to be used', async function () {
|
|
223
209
|
// @ts-expect-error baseImagePromise is private
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
);
|
|
210
|
+
const img = await (dockerStorage.baseImagePromise as Promise<string>);
|
|
211
|
+
expect(img).to.be.a('string');
|
|
227
212
|
});
|
|
228
213
|
});
|