From 86c7ee8b7dd09225a0b59dcfcf535021664bc48f Mon Sep 17 00:00:00 2001 From: Charlie Drage Date: Thu, 18 Jul 2024 14:16:57 -0400 Subject: [PATCH] feat: add removeManifest API (#8127) --- packages/extension-api/src/extension-api.d.ts | 1 + .../src/plugin/container-registry.spec.ts | 24 +++++++++++++++++ .../main/src/plugin/container-registry.ts | 16 +++++++++++ .../plugin/dockerode/libpod-dockerode.spec.ts | 13 +++++++++ .../src/plugin/dockerode/libpod-dockerode.ts | 27 +++++++++++++++++++ packages/main/src/plugin/extension-loader.ts | 3 +++ packages/main/src/plugin/index.ts | 7 +++++ packages/preload/src/index.ts | 3 +++ 8 files changed, 94 insertions(+) diff --git a/packages/extension-api/src/extension-api.d.ts b/packages/extension-api/src/extension-api.d.ts index a43fe2c18fa..98353974443 100644 --- a/packages/extension-api/src/extension-api.d.ts +++ b/packages/extension-api/src/extension-api.d.ts @@ -3670,6 +3670,7 @@ declare module '@podman-desktop/api' { // Manifest related methods export function createManifest(options: ManifestCreateOptions): Promise<{ engineId: string; Id: string }>; export function inspectManifest(engineId: string, id: string): Promise; + export function removeManifest(engineId: string, id: string): Promise; } /** diff --git a/packages/main/src/plugin/container-registry.spec.ts b/packages/main/src/plugin/container-registry.spec.ts index 24b5a3061b8..d9e665c8a03 100644 --- a/packages/main/src/plugin/container-registry.spec.ts +++ b/packages/main/src/plugin/container-registry.spec.ts @@ -4720,3 +4720,27 @@ test('inspectManifest should fail if libpod is missing from the provider', async 'LibPod is not supported by this engine', ); }); + +test('test removeManifest', async () => { + const api = new Dockerode({ protocol: 'http', host: 'localhost' }); + + const removeManifestMock = vi.fn(); + + const fakeLibPod = { + podmanRemoveManifest: removeManifestMock, + } as unknown as LibPod; + + containerRegistry.addInternalProvider('podman1', { + name: 'podman', + id: 'podman1', + api, + libpodApi: fakeLibPod, + connection: { + type: 'podman', + }, + } as unknown as InternalContainerProvider); + + const result = await containerRegistry.removeManifest('podman1', 'manifestId'); + expect(removeManifestMock).toBeCalledWith('manifestId'); + expect(result).toBeUndefined(); +}); diff --git a/packages/main/src/plugin/container-registry.ts b/packages/main/src/plugin/container-registry.ts index 070991d0b71..3b598354b0a 100644 --- a/packages/main/src/plugin/container-registry.ts +++ b/packages/main/src/plugin/container-registry.ts @@ -1353,6 +1353,22 @@ export class ContainerProviderRegistry { } } + async removeManifest(engineId: string, manifestName: string): Promise { + let telemetryOptions = {}; + try { + const libPod = this.getMatchingPodmanEngineLibPod(engineId); + if (!libPod) { + throw new Error('No podman provider with a running engine'); + } + return libPod.podmanRemoveManifest(manifestName); + } catch (error) { + telemetryOptions = { error: error }; + throw error; + } finally { + this.telemetryService.track('removeManifest', telemetryOptions); + } + } + async replicatePodmanContainer( source: { engineId: string; id: string }, target: { engineId: string }, diff --git a/packages/main/src/plugin/dockerode/libpod-dockerode.spec.ts b/packages/main/src/plugin/dockerode/libpod-dockerode.spec.ts index 4d966bb785c..024d79edce7 100644 --- a/packages/main/src/plugin/dockerode/libpod-dockerode.spec.ts +++ b/packages/main/src/plugin/dockerode/libpod-dockerode.spec.ts @@ -273,3 +273,16 @@ test('Check create volume', async () => { expect(response.Name).toBe('foo'); expect(response.Scope).toBe('local'); }); + +test('Test remove manifest', async () => { + nock('http://localhost').delete('/v4.2.0/libpod/manifests/name1').reply(200); + const api = new Dockerode({ protocol: 'http', host: 'localhost' }); + + const response = await (api as unknown as LibPod).podmanRemoveManifest('name1'); + + // Check that the request was made + expect(nock.isDone()).toBe(true); + + // Check that the response is correct + expect(response).toBeDefined(); +}); diff --git a/packages/main/src/plugin/dockerode/libpod-dockerode.ts b/packages/main/src/plugin/dockerode/libpod-dockerode.ts index 7f5a08b7258..4cbdeb84ccc 100644 --- a/packages/main/src/plugin/dockerode/libpod-dockerode.ts +++ b/packages/main/src/plugin/dockerode/libpod-dockerode.ts @@ -364,6 +364,7 @@ export interface LibPod { podmanListImages(options?: PodmanListImagesOptions): Promise; podmanCreateManifest(manifestOptions: ManifestCreateOptions): Promise<{ engineId: string; Id: string }>; podmanInspectManifest(manifestName: string): Promise; + podmanRemoveManifest(manifestName: string): Promise; } // tweak Dockerode by adding the support of libpod API @@ -895,5 +896,31 @@ export class LibpodDockerode { }); }); }; + + // remove manifest + prototypeOfDockerode.podmanRemoveManifest = function (manifestName: string): Promise { + // make sure encodeURI component for the name ex. domain.com/foo/bar:latest + const encodedManifestName = encodeURIComponent(manifestName); + + const optsf = { + path: `/v4.2.0/libpod/manifests/${encodedManifestName}`, + method: 'DELETE', + statusCodes: { + 200: true, + 404: 'no such manifest', + 500: 'server error', + }, + options: {}, + }; + + return new Promise((resolve, reject) => { + this.modem.dial(optsf, (err: unknown, data: unknown) => { + if (err) { + return reject(err); + } + resolve(data); + }); + }); + }; } } diff --git a/packages/main/src/plugin/extension-loader.ts b/packages/main/src/plugin/extension-loader.ts index 205d2bdb415..290eaf962f1 100644 --- a/packages/main/src/plugin/extension-loader.ts +++ b/packages/main/src/plugin/extension-loader.ts @@ -1175,6 +1175,9 @@ export class ExtensionLoader { inspectManifest(engineId: string, id: string): Promise { return containerProviderRegistry.inspectManifest(engineId, id); }, + removeManifest(engineId: string, id: string): Promise { + return containerProviderRegistry.removeManifest(engineId, id); + }, replicatePodmanContainer( source: { engineId: string; id: string }, target: { engineId: string }, diff --git a/packages/main/src/plugin/index.ts b/packages/main/src/plugin/index.ts index c7dc20520a7..f617b75fc59 100644 --- a/packages/main/src/plugin/index.ts +++ b/packages/main/src/plugin/index.ts @@ -806,6 +806,13 @@ export class PluginSystem { }, ); + this.ipcHandle( + 'container-provider-registry:removeManifest', + async (_listener, engine: string, manifestId: string): Promise => { + return containerProviderRegistry.removeManifest(engine, manifestId); + }, + ); + this.ipcHandle( 'container-provider-registry:generatePodmanKube', async (_listener, engine: string, names: string[]): Promise => { diff --git a/packages/preload/src/index.ts b/packages/preload/src/index.ts index c64821ca2ef..3e2542f044d 100644 --- a/packages/preload/src/index.ts +++ b/packages/preload/src/index.ts @@ -303,6 +303,9 @@ export function initExposure(): void { return ipcInvoke('container-provider-registry:inspectManifest', engine, manifestId); }, ); + contextBridge.exposeInMainWorld('removeManifest', async (engine: string, manifestId: string): Promise => { + return ipcInvoke('container-provider-registry:removeManifest', engine, manifestId); + }); /** * @deprecated This method is deprecated and will be removed in a future release.