Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dd): add support for backend extensions of Docker Desktop #3435

Merged
merged 1 commit into from Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand All @@ -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);
});
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
}
}
36 changes: 20 additions & 16 deletions packages/preload-docker-extension/src/index.ts
Expand Up @@ -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<unknown> => {
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<unknown> => {
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<unknown> => {
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<unknown> => {
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<unknown> => {
console.error('extensionVMService.patch not implemented', url, data);
return {} as any;
return doRequest({ url, method: 'PATCH', headers: {}, data });
},
delete: async (url: string): Promise<unknown> => {
console.error('extensionVMService.delete not implemented', url);
return {} as any;
return doRequest({ url, method: 'DELETE', headers: {}, data: undefined });
},
head: async (url: string): Promise<unknown> => {
console.error('extensionVMService.head not implemented', url);
return {} as any;
return doRequest({ url, method: 'HEAD', headers: {}, data: undefined });
},
request: async (config: RequestConfig): Promise<unknown> => {
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 = {
Expand Down
2 changes: 1 addition & 1 deletion packages/preload/src/index.ts
Expand Up @@ -1229,7 +1229,7 @@ function initExposure(): void {
});

contextBridge.exposeInMainWorld('ddExtensionDelete', async (extensionName: string): Promise<void> => {
return ipcRenderer.invoke('docker-desktop-plugin:delete', extensionName);
return ipcInvoke('docker-desktop-plugin:delete', extensionName);
});

contextBridge.exposeInMainWorld('getDDPreloadPath', async (): Promise<string> => {
Expand Down
Expand Up @@ -41,7 +41,7 @@ window.events?.receive('dev-tools:open-extension', extensionId => {
<Route path="/*" breadcrumb="{name}">
<webview
id="dd-webview-{webviewId}"
src="{source}?extensionName={currentContrib.extensionId}&arch={arch}&hostname={hostname}&platform={platform}"
src="{source}?extensionName={currentContrib.extensionId}&arch={arch}&hostname={hostname}&platform={platform}&vmServicePort={currentContrib.vmServicePort}"
preload="{preloadPath}"
style="height: 100%; width: 100%"></webview>
</Route>
Expand Down