mirror of
https://github.com/podman-desktop/podman-desktop
synced 2026-05-23 17:58:22 +00:00
chore: add Digest to ImageInfo (#6817)
* chore: add Digest to ImageInfo ### What does this PR do? * Adds ability to get Digest from podman API calls. * Already within PD list images calls, now we can get it via ImageInfo ### Screenshot / video of UI <!-- If this PR is changing UI, please include screenshots or screencasts showing the difference --> N/A ### What issues does this PR fix or reference? <!-- Include any related issues from Podman Desktop repository (or from another issue tracker). --> Closes https://github.com/containers/podman-desktop/issues/6816 ### How to test this PR? <!-- Please explain steps to verify the functionality, do not forget to provide unit/component tests --> - [X] Tests are covering the bug fix or the new feature Signed-off-by: Charlie Drage <charlie@charliedrage.com> * add Digest for all list images calls Signed-off-by: Charlie Drage <charlie@charliedrage.com> * update Signed-off-by: Charlie Drage <charlie@charliedrage.com> * update Signed-off-by: Charlie Drage <charlie@charliedrage.com> --------- Signed-off-by: Charlie Drage <charlie@charliedrage.com>
This commit is contained in:
parent
c1359eea5d
commit
70c19fc31a
7 changed files with 91 additions and 1 deletions
|
|
@ -1868,6 +1868,7 @@ declare module '@podman-desktop/api' {
|
|||
Labels: { [label: string]: string };
|
||||
Containers: number;
|
||||
History?: string[];
|
||||
Digest: string;
|
||||
|
||||
// isManifest will be returned and set to true if the image is identified to be a manifest list
|
||||
isManifest?: boolean;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export interface ImageInfo extends Dockerode.ImageInfo {
|
|||
engineName: string;
|
||||
History?: string[];
|
||||
isManifest?: boolean;
|
||||
Digest: string;
|
||||
}
|
||||
|
||||
export interface BuildImageOptions {
|
||||
|
|
|
|||
|
|
@ -3761,6 +3761,7 @@ describe('listImages', () => {
|
|||
Id: 'dummyImageId',
|
||||
engineId: 'dummyId',
|
||||
engineName: 'dummyName',
|
||||
Digest: 'sha256:dummyImageId',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -3830,6 +3831,74 @@ test('expect images with podmanListImages to also include History as well as eng
|
|||
expect(image.History).toStrictEqual(['history1', 'history2']);
|
||||
});
|
||||
|
||||
test('expect images with podmanListImages to also include Digest as engineId and engineName', async () => {
|
||||
const imagesList = [
|
||||
{
|
||||
Id: 'dummyImageId',
|
||||
Digest: 'dummyDigest',
|
||||
},
|
||||
];
|
||||
|
||||
nock('http://localhost').get('/v4.2.0/libpod/images/json').reply(200, imagesList);
|
||||
|
||||
const api = new Dockerode({ protocol: 'http', host: 'localhost' });
|
||||
|
||||
// set provider
|
||||
containerRegistry.addInternalProvider('podman', {
|
||||
name: 'podman',
|
||||
id: 'podman1',
|
||||
api,
|
||||
libpodApi: api,
|
||||
connection: {
|
||||
type: 'podman',
|
||||
},
|
||||
} as unknown as InternalContainerProvider);
|
||||
|
||||
const images = await containerRegistry.podmanListImages();
|
||||
// ensure the field are correct
|
||||
expect(images).toBeDefined();
|
||||
expect(images).toHaveLength(1);
|
||||
const image = images[0];
|
||||
expect(image.engineId).toBe('podman1');
|
||||
expect(image.engineName).toBe('podman');
|
||||
expect(image.Digest).toBe('dummyDigest');
|
||||
});
|
||||
|
||||
test('If image does not have Digest in list images, expect the Digest to be sha256:ID', async () => {
|
||||
// Purposely be missing Digest, it should return Digest as sha256:ID
|
||||
// this is because the compat API does not provide Digest return.
|
||||
const imagesList = [
|
||||
{
|
||||
Id: 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2',
|
||||
},
|
||||
];
|
||||
|
||||
nock('http://localhost').get('/v4.2.0/libpod/images/json').reply(200, imagesList);
|
||||
|
||||
const api = new Dockerode({ protocol: 'http', host: 'localhost' });
|
||||
|
||||
// set provider
|
||||
containerRegistry.addInternalProvider('podman', {
|
||||
name: 'podman',
|
||||
id: 'podman1',
|
||||
api,
|
||||
libpodApi: api,
|
||||
connection: {
|
||||
type: 'podman',
|
||||
},
|
||||
} as unknown as InternalContainerProvider);
|
||||
|
||||
const images = await containerRegistry.podmanListImages();
|
||||
|
||||
// ensure the field are correct
|
||||
expect(images).toBeDefined();
|
||||
expect(images).toHaveLength(1);
|
||||
const image = images[0];
|
||||
expect(image.engineId).toBe('podman1');
|
||||
expect(image.engineName).toBe('podman');
|
||||
expect(image.Digest).toBe('sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2');
|
||||
});
|
||||
|
||||
test('expect to fall back to compat api images if podman provider does not have libpodApi', async () => {
|
||||
const imagesList = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -582,7 +582,12 @@ export class ContainerProviderRegistry {
|
|||
}
|
||||
const images = await provider.api.listImages({ all: false });
|
||||
return images.map(image => {
|
||||
const imageInfo: ImageInfo = { ...image, engineName: provider.name, engineId: provider.id };
|
||||
const imageInfo: ImageInfo = {
|
||||
...image,
|
||||
engineName: provider.name,
|
||||
engineId: provider.id,
|
||||
Digest: `sha256:${image.Id}`,
|
||||
};
|
||||
return imageInfo;
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
@ -641,6 +646,10 @@ export class ContainerProviderRegistry {
|
|||
// NOTE: This is a workaround until we have a better way to determine if an image is a manifest
|
||||
// and may result in false positives until issue: https://github.com/containers/podman/issues/22184 is resolved
|
||||
isManifest: guessIsManifest(image, provider.connection.type),
|
||||
|
||||
// Compat API provider does not add the Digest field.
|
||||
// if it is missing, add it as 'sha256:image.Id'
|
||||
Digest: image.Digest || `sha256:${image.Id}`,
|
||||
}));
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ suite('image checker module', () => {
|
|||
SharedSize: 1,
|
||||
Labels: {},
|
||||
Containers: 1,
|
||||
Digest: 'sha256:id',
|
||||
};
|
||||
const result = await imageChecker.check(providers[0].id, imageInfo);
|
||||
expect(result).toBeDefined();
|
||||
|
|
@ -168,6 +169,7 @@ suite('image checker module', () => {
|
|||
SharedSize: 1,
|
||||
Labels: {},
|
||||
Containers: 1,
|
||||
Digest: 'sha256:id',
|
||||
};
|
||||
await expect(() => imageChecker.check('unknown-id', imageInfo)).rejects.toThrow(
|
||||
'provider not found with id unknown-id',
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ describe('guessIsManifest function', () => {
|
|||
VirtualSize: 40 * 1024, // 40KB (less than 50KB threshold)
|
||||
SharedSize: 0,
|
||||
Containers: 0,
|
||||
Digest: 'sha256:manifestImage',
|
||||
};
|
||||
|
||||
expect(guessIsManifest(manifestImage, 'podman')).toBe(true);
|
||||
|
|
@ -55,6 +56,7 @@ describe('guessIsManifest function', () => {
|
|||
VirtualSize: 2000000, // 2MB
|
||||
SharedSize: 0,
|
||||
Containers: 0,
|
||||
Digest: 'sha256:largeImage',
|
||||
};
|
||||
|
||||
expect(guessIsManifest(largeImage, 'podman')).toBe(false);
|
||||
|
|
@ -74,6 +76,7 @@ describe('guessIsManifest function', () => {
|
|||
VirtualSize: 500000, // 500KB
|
||||
SharedSize: 0,
|
||||
Containers: 0,
|
||||
Digest: 'sha256:labeledImage',
|
||||
};
|
||||
|
||||
expect(guessIsManifest(labeledImage, 'podman')).toBe(false);
|
||||
|
|
@ -93,6 +96,7 @@ describe('guessIsManifest function', () => {
|
|||
VirtualSize: 500000, // 500KB
|
||||
SharedSize: 0,
|
||||
Containers: 0,
|
||||
Digest: 'sha256:noTagImage',
|
||||
};
|
||||
|
||||
expect(guessIsManifest(noTagImage, 'podman')).toBe(false);
|
||||
|
|
@ -112,6 +116,7 @@ describe('guessIsManifest function', () => {
|
|||
VirtualSize: 500000, // 500KB
|
||||
SharedSize: 0,
|
||||
Containers: 0,
|
||||
Digest: 'sha256:noDigestImage',
|
||||
};
|
||||
|
||||
expect(guessIsManifest(noDigestImage, 'podman')).toBe(false);
|
||||
|
|
@ -135,6 +140,7 @@ describe('guessIsManifest function', () => {
|
|||
SharedSize: 0,
|
||||
Containers: 0,
|
||||
History: ['testdomain.io/library/hello:latest'],
|
||||
Digest: 'sha256:ee301c921b8aadc002973b2e0c3da17d701dcd994b606769a7e6eaa100b81d44',
|
||||
};
|
||||
|
||||
// Should be false
|
||||
|
|
@ -156,6 +162,7 @@ test('expect to fail even if engine name does not equal podman', () => {
|
|||
VirtualSize: 40 * 1024, // 40KB (less than 50KB threshold)
|
||||
SharedSize: 0,
|
||||
Containers: 0,
|
||||
Digest: 'sha256:manifestImage',
|
||||
};
|
||||
|
||||
expect(guessIsManifest(manifestImage, 'foobar')).toBe(false);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ const myImage: ImageInfo = {
|
|||
VirtualSize: 0,
|
||||
SharedSize: 0,
|
||||
Containers: 0,
|
||||
Digest: 'sha256:myImage',
|
||||
};
|
||||
|
||||
const myNoneNameImage: ImageInfo = {
|
||||
|
|
|
|||
Loading…
Reference in a new issue