mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-02-22 02:16:43 +00:00
Merge pull request #1156 from balena-io/1072-v2-v3-delta-fixes
fix: ⬇️ Force a regular pull when moving from v2 to v3 deltas
This commit is contained in:
commit
a590fa0bb8
6
package-lock.json
generated
6
package-lock.json
generated
@ -256,9 +256,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/dockerode": {
|
||||
"version": "2.5.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-2.5.20.tgz",
|
||||
"integrity": "sha512-g2eM9q+pur7iZc897K/OSq8sCL7VdVcCPzNkdeTukUokfvgl3TaP+nT7G8BMpnSSojrJFKl7VdTciP7hbVgfKA==",
|
||||
"version": "2.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-2.5.21.tgz",
|
||||
"integrity": "sha512-Y9kVV7Umw0SAOsGVp06VGjlAiZbjALNhDIw69NeWNEqfI++7nQijzjWsepOkUjKHr5CrJWgK4v++6a+Ms0G/6A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
|
@ -42,7 +42,7 @@
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/chai-as-promised": "^7.1.2",
|
||||
"@types/common-tags": "^1.8.0",
|
||||
"@types/dockerode": "^2.5.20",
|
||||
"@types/dockerode": "^2.5.21",
|
||||
"@types/event-stream": "^3.3.34",
|
||||
"@types/express": "^4.11.1",
|
||||
"@types/knex": "^0.14.14",
|
||||
|
@ -89,6 +89,20 @@ export class DockerUtils extends DockerToolbelt {
|
||||
return await this.fetchImageWithProgress(imgDest, deltaOpts, onProgress);
|
||||
}
|
||||
|
||||
// We need to make sure that we're not trying to apply a
|
||||
// v3 delta on top of a v2 delta, as this will cause the
|
||||
// update to fail, and we must fall back to a standard
|
||||
// image pull
|
||||
if (
|
||||
deltaOpts.deltaVersion === 3 &&
|
||||
(await DockerUtils.isV2DeltaImage(this, deltaOpts.deltaSourceId))
|
||||
) {
|
||||
logFn(
|
||||
`Cannot create a delta from V2 to V3, falling back to regular pull`,
|
||||
);
|
||||
return await this.fetchImageWithProgress(imgDest, deltaOpts, onProgress);
|
||||
}
|
||||
|
||||
// Since the supevisor never calls this function with a source anymore,
|
||||
// this should never happen, but w ehandle it anyway
|
||||
if (deltaOpts.deltaSource == null) {
|
||||
@ -317,6 +331,19 @@ export class DockerUtils extends DockerToolbelt {
|
||||
return (await docker.getImage(deltaImg).inspect()).Id;
|
||||
}
|
||||
|
||||
public static async isV2DeltaImage(
|
||||
docker: DockerUtils,
|
||||
imageName: string,
|
||||
): Promise<boolean> {
|
||||
const inspect = await docker.getImage(imageName).inspect();
|
||||
|
||||
// It's extremely unlikely that an image is valid if
|
||||
// it's smaller than 40 bytes, but a v2 delta always is.
|
||||
// For this reason, this is the method that we use to
|
||||
// detect when an image is a v2 delta
|
||||
return inspect.Size < 40 && inspect.VirtualSize < 40;
|
||||
}
|
||||
|
||||
private getAuthToken = memoizee(
|
||||
async (
|
||||
srcInfo: ImageNameParts,
|
||||
|
106
test/25-deltas.spec.ts
Normal file
106
test/25-deltas.spec.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { expect } from 'chai';
|
||||
import { stub } from 'sinon';
|
||||
|
||||
import DockerUtils from '../src/lib/docker-utils';
|
||||
|
||||
const dockerUtils = new DockerUtils({});
|
||||
|
||||
describe('Deltas', () => {
|
||||
it('should correctly detect a V2 delta', async () => {
|
||||
const imageStub = stub(dockerUtils, 'getImage').returns({
|
||||
inspect: () => {
|
||||
return Promise.resolve({
|
||||
Id:
|
||||
'sha256:34ec91fe6e08cb0f867bbc069c5f499d39297eb8e874bb8ce9707537d983bcbc',
|
||||
RepoTags: [],
|
||||
RepoDigests: [],
|
||||
Parent: '',
|
||||
Comment: '',
|
||||
Created: '2019-12-05T10:20:51.516Z',
|
||||
Container: '',
|
||||
ContainerConfig: {
|
||||
Hostname: '',
|
||||
Domainname: '',
|
||||
User: '',
|
||||
AttachStdin: false,
|
||||
AttachStdout: false,
|
||||
AttachStderr: false,
|
||||
Tty: false,
|
||||
OpenStdin: false,
|
||||
StdinOnce: false,
|
||||
Env: null,
|
||||
Cmd: null,
|
||||
Image: '',
|
||||
Volumes: null,
|
||||
WorkingDir: '',
|
||||
Entrypoint: null,
|
||||
OnBuild: null,
|
||||
Labels: null,
|
||||
},
|
||||
DockerVersion: '',
|
||||
Author: '',
|
||||
Config: {
|
||||
Hostname: '7675a23f4fdc',
|
||||
Domainname: '',
|
||||
User: '',
|
||||
AttachStdin: false,
|
||||
AttachStdout: false,
|
||||
AttachStderr: false,
|
||||
Tty: false,
|
||||
OpenStdin: false,
|
||||
StdinOnce: false,
|
||||
Env: [
|
||||
'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
|
||||
'TINI_VERSION=0.14.0',
|
||||
'LC_ALL=C.UTF-8',
|
||||
'DEBIAN_FRONTEND=noninteractive',
|
||||
'UDEV=on',
|
||||
'container=docker',
|
||||
'test=123',
|
||||
],
|
||||
Cmd: [
|
||||
'/bin/sh',
|
||||
'-c',
|
||||
"while true; do echo 'hello'; sleep 10; done;",
|
||||
],
|
||||
ArgsEscaped: true,
|
||||
Image:
|
||||
'sha256:b24946093df7157727b20934d11a7287359d8de42d8a80030f51f46a73d645ec',
|
||||
Volumes: {
|
||||
'/sys/fs/cgroup': {},
|
||||
},
|
||||
WorkingDir: '',
|
||||
Entrypoint: ['/usr/bin/entry.sh'],
|
||||
OnBuild: [],
|
||||
Labels: {
|
||||
'io.resin.architecture': 'amd64',
|
||||
'io.resin.device-type': 'intel-nuc',
|
||||
},
|
||||
StopSignal: '37',
|
||||
},
|
||||
Architecture: '',
|
||||
Os: 'linux',
|
||||
Size: 17,
|
||||
VirtualSize: 17,
|
||||
GraphDriver: {
|
||||
Data: null,
|
||||
Name: 'aufs',
|
||||
},
|
||||
RootFS: {
|
||||
Type: 'layers',
|
||||
Layers: [
|
||||
'sha256:c6e6cd4f95ef00e62f5c9df5798393470c991ca0148cb1e434b28101ed4219d3',
|
||||
],
|
||||
},
|
||||
Metadata: {
|
||||
LastTagTime: '0001-01-01T00:00:00Z',
|
||||
},
|
||||
});
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(await DockerUtils.isV2DeltaImage(dockerUtils, 'test')).to.be.true;
|
||||
expect(imageStub.callCount).to.equal(1);
|
||||
imageStub.restore();
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user