diff --git a/packages/main/src/plugin/docker-extension/docker-desktop-installation.spec.ts b/packages/main/src/plugin/docker-extension/docker-desktop-installation.spec.ts index e4075b58ceb1..c8f7b7df131c 100644 --- a/packages/main/src/plugin/docker-extension/docker-desktop-installation.spec.ts +++ b/packages/main/src/plugin/docker-extension/docker-desktop-installation.spec.ts @@ -36,9 +36,15 @@ let dockerDesktopInstallation: TestDockerDesktopInstallation; const contributionManagerLoadMetadataMock = vi.fn(); const contributionManagerInitMock = vi.fn(); +const contributionManagerFindComposeBinaryMock = vi.fn(); +const contributionManagerEnhanceComposeFileMock = vi.fn(); +const containerProviderStartVMMock = vi.fn(); const contributionManager = { init: contributionManagerInitMock, loadMetadata: contributionManagerLoadMetadataMock, + findComposeBinary: contributionManagerFindComposeBinaryMock, + enhanceComposeFile: contributionManagerEnhanceComposeFileMock, + startVM: containerProviderStartVMMock, } as unknown as ContributionManager; const containerProviderGetFirstRunningConnectionMock = vi.fn(); @@ -318,8 +324,17 @@ test('Check handlePluginInstall', async () => { // mock extractDockerDesktopFiles vi.spyOn(dockerDesktopInstallation, 'extractDockerDesktopFiles').mockResolvedValue(); + // mock findComposeBinary + contributionManagerFindComposeBinaryMock.mockResolvedValue('/my-compose-binary'); + + // mock enhanceComposeFile + contributionManagerEnhanceComposeFileMock.mockResolvedValue('/my-enhanced-compose-file.yaml'); + contributionManagerLoadMetadataMock.mockResolvedValue({ name: 'My Extension', + vm: { + composefile: 'docker-compose.yaml', + }, }); const logCallbackId = 2503; @@ -336,4 +351,6 @@ test('Check handlePluginInstall', async () => { // contribution manager is called expect(contributionManagerInitMock).toBeCalled(); + + expect(containerProviderStartVMMock).toBeCalledWith('My Extension', '/my-enhanced-compose-file.yaml', true); }); diff --git a/packages/main/src/plugin/docker-extension/docker-desktop-installation.ts b/packages/main/src/plugin/docker-extension/docker-desktop-installation.ts index 2ce82c746589..6ad8731651de 100644 --- a/packages/main/src/plugin/docker-extension/docker-desktop-installation.ts +++ b/packages/main/src/plugin/docker-extension/docker-desktop-installation.ts @@ -67,6 +67,10 @@ export class DockerDesktopInstallation { }); } + if (metadata.vm?.composefile) { + files.push(metadata.vm.composefile); + } + // host binaries const hostFiles: string[] = []; if (metadata?.host?.binaries) { @@ -377,6 +381,7 @@ export class DockerDesktopInstallation { await this.extractDockerDesktopFiles(tmpFolderPath, finalFolderPath, reportLog); + event.reply('docker-desktop-plugin:install-log', logCallbackId, 'Loading metadata...'); // check metadata. If name is missing, add the one from the image const metadata = await this.contributionManager.loadMetadata(finalFolderPath); if (!metadata.name) { @@ -385,8 +390,41 @@ export class DockerDesktopInstallation { await this.contributionManager.saveMetadata(finalFolderPath, metadata); } + // if there is a VM, need to generate the updated compose file + let enhancedComposeFile; + if (metadata.vm) { + // check compose presence + event.reply('docker-desktop-plugin:install-log', logCallbackId, 'Check compose being setup...'); + const foundPath = await this.contributionManager.findComposeBinary(); + if (!foundPath) { + event.reply('docker-desktop-plugin:install-error', logCallbackId, 'Compose binary not found.'); + return; + } else { + event.reply('docker-desktop-plugin:install-log', logCallbackId, `Compose binary found at ${foundPath}.`); + } + + event.reply('docker-desktop-plugin:install-log', logCallbackId, 'Enhance compose file...'); + // need to update the compose file + try { + enhancedComposeFile = await this.contributionManager.enhanceComposeFile(finalFolderPath, imageName, metadata); + } catch (error) { + event.reply('docker-desktop-plugin:install-error', logCallbackId, error); + return; + } + + // try to start the VM + event.reply('docker-desktop-plugin:install-log', logCallbackId, 'Starting compose project...'); + await this.contributionManager.startVM(metadata.name, enhancedComposeFile, true); + } + event.reply('docker-desktop-plugin:install-end', logCallbackId, 'Extension Successfully installed.'); + // refresh contributions - await this.contributionManager.init(); + try { + await this.contributionManager.init(); + } catch (error) { + event.reply('docker-desktop-plugin:install-error', logCallbackId, error); + return; + } } } diff --git a/packages/preload-docker-extension/src/index.ts b/packages/preload-docker-extension/src/index.ts index b2a78034d575..5114a1f224ba 100644 --- a/packages/preload-docker-extension/src/index.ts +++ b/packages/preload-docker-extension/src/index.ts @@ -295,40 +295,44 @@ export class DockerExtensionPreload { hostname, }; + const vmServicePort = urlParams.get('vmServicePort') || undefined; + + // do we have a service being exposed ? + const doRequest = async (config: RequestConfig): Promise => { + if (vmServicePort) { + return ipcRenderer.invoke('docker-desktop-adapter:extensionVMServiceRequest', vmServicePort, config); + } else { + throw new Error(`no service port defined for request ${config}`); + } + }; + const extensionVMService: dockerDesktopAPI.HttpService = { get: async (url: string): Promise => { - console.error('extensionVMService.get not implemented', url); - return {} as any; + return doRequest({ url, method: 'GET', headers: {}, data: undefined }); }, post: async (url: string, data: any): Promise => { - console.error('extensionVMService.post not implemented', url, data); - return {} as any; + return doRequest({ url, method: 'POST', headers: {}, data }); }, put: async (url: string, data: any): Promise => { - console.error('extensionVMService.put not implemented', url, data); - return {} as any; + return doRequest({ url, method: 'PUT', headers: {}, data }); }, patch: async (url: string, data: any): Promise => { - console.error('extensionVMService.patch not implemented', url, data); - return {} as any; + return doRequest({ url, method: 'PATCH', headers: {}, data }); }, delete: async (url: string): Promise => { - console.error('extensionVMService.delete not implemented', url); - return {} as any; + return doRequest({ url, method: 'DELETE', headers: {}, data: undefined }); }, head: async (url: string): Promise => { - console.error('extensionVMService.head not implemented', url); - return {} as any; + return doRequest({ url, method: 'HEAD', headers: {}, data: undefined }); }, request: async (config: RequestConfig): Promise => { - console.error('extensionVMService.request not implemented', config); - return {} as any; + return doRequest(config); }, }; const extensionCliVM: dockerDesktopAPI.ExtensionCli = { - //FIXME: - exec: {} as any, + // need to call exec inside a container for the VM service + exec: this.getExec('VM_SERVICE'), }; const extensionVM: dockerDesktopAPI.ExtensionVM = { diff --git a/packages/preload/src/index.ts b/packages/preload/src/index.ts index d9e9429401f1..e8400eaf467c 100644 --- a/packages/preload/src/index.ts +++ b/packages/preload/src/index.ts @@ -1229,7 +1229,7 @@ function initExposure(): void { }); contextBridge.exposeInMainWorld('ddExtensionDelete', async (extensionName: string): Promise => { - return ipcRenderer.invoke('docker-desktop-plugin:delete', extensionName); + return ipcInvoke('docker-desktop-plugin:delete', extensionName); }); contextBridge.exposeInMainWorld('getDDPreloadPath', async (): Promise => { diff --git a/packages/renderer/src/lib/docker-extension/DockerExtension.svelte b/packages/renderer/src/lib/docker-extension/DockerExtension.svelte index 46c0f1f7e4ab..4da196b57792 100644 --- a/packages/renderer/src/lib/docker-extension/DockerExtension.svelte +++ b/packages/renderer/src/lib/docker-extension/DockerExtension.svelte @@ -41,7 +41,7 @@ window.events?.receive('dev-tools:open-extension', extensionId => {