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: add podman extension api package and use it in podman extension #8891

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

dgolovin
Copy link
Contributor

What does this PR do?

  1. introduces podman extension API package
  2. adds it to workspace
  3. uses it in podman extension

Screenshot / video of UI

What issues does this PR fix or reference?

Related to #5990.

How to test this PR?

  • Tests are covering the bug fix or the new feature

@dgolovin dgolovin requested review from benoitf and a team as code owners September 16, 2024 03:09
@dgolovin dgolovin requested review from cdrage, gastoner and SoniaSandler and removed request for a team September 16, 2024 03:09
Copy link
Collaborator

@benoitf benoitf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing unit tests

Copy link
Collaborator

@benoitf benoitf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might help if we're able to remove the code from other extensions using dedicated podman code

Here it seems we're assuming other extensions are using the CLI when calling 'podman stuff' but for example Ai-Lab is using the API, not the CLI to a lot of code.

https://github.com/containers/podman-desktop-extension-ai-lab/blob/0045a65681889ada6763bf05a12ad93d0bbe14b0/packages/backend/src/managers/podmanConnection.ts

so the API should provide a way to get all the podman connections as well directly

could be interesting that to have PR in other repositories to see if the API will fit, before trying to provide an API that extensions won't consume/solve the problem.

extensions/podman/packages/api/package.json Outdated Show resolved Hide resolved
extensions/podman/packages/api/vite.config.js Outdated Show resolved Hide resolved
extensions/podman/packages/api/tsconfig.json Show resolved Hide resolved
Comment on lines 21 to 27
export interface PodmanExtensionApi {
exec(args: string[], options?: RunOptions): Promise<RunResult>;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here I don't see how consumers will be able to use that API in case of multiple providers (applehv, libkrun)

For example I see an hardcoded 'podman' value in the implementation:

return execPodman(args, 'podman', options);

but if I look at execPodman method

export function execPodman(
  args: string[],
  containersProvider?: string,
  options?: extensionApi.RunOptions,
): Promise<extensionApi.RunResult> {

containersProvider is an option to specify like is it Apple Hypervisor, is it libkrun, etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should pass the object ProviderContainerConnection or ContainerProviderConnection instead of a string

If we pass ProviderContainerConnection podman extension could add a security checking that the providerId corresponds and we are not sending one registered by another extensions.

however;

ContainerProviderConnection would be easier as extension get this object pretty easily through, and is something used in the BuildOptions, VolumeCreateOptions, pullImage, createNetwork etc....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added additional optional parameter connection: ProviderContainerConnection, so clients can get instance using provider.getContainerConnections and use it to call exec.

@dgolovin
Copy link
Contributor Author

so the API should provide a way to get all the podman connections as well directly

You are suggesting to have getConnections() method that would be called when needed, instead of having all of those listeners added to track changes in connections related to podman provider, aren't you?

That should work, but should we add that as different pull request, after merging API with exec and implementing publishing?

I can definitely add that in this PR, but it would be out of the issue scope IMO.

@benoitf
Copy link
Collaborator

benoitf commented Sep 18, 2024

I just want to be sure that @axel7083 and others on AI lab extension will be able to use the extension endpoint.
You're saying it's out of the scope but it seems the scope is to be able to call this extension rather doing some private fork/own code

If there is an exec endpoint that is useless for other extensions then they won't use it and still keep their own code

@benoitf
Copy link
Collaborator

benoitf commented Sep 18, 2024

that said, it needs to be something in the middle where we might not have all the endpoints but we need to be sure that what we're adding is working smoothly for the other extensions

@axel7083
Copy link
Contributor

axel7083 commented Sep 18, 2024

I just want to be sure that @axel7083 and others on AI lab extension will be able to use the extension endpoint.

To make some tests in AI Lab I added the following functions

import type { ExtensionContext, ProviderContainerConnection, RunOptions, RunResult } from '@podman-desktop/api';
import { extensions, provider } from '@podman-desktop/api';

async function podmanExtensionExperiment(): Promise<void> {
  const podman = extensions.getExtension('podman-desktop.podman');
  if(!podman) throw new Error('cannot found podman extension api');

  const podmanApi: {
    exec(args: string[], connection?: extensionApi.ProviderContainerConnection, options?: RunOptions): Promise<RunResult>;
  } = podman.exports;

  const machines = await podmanApi.exec(['machine', 'list', '--format=json']);
  console.log('podman machine list', JSON.parse(machines.stdout));

  const connections: ProviderContainerConnection[] = provider.getContainerConnections();
  for (const connection of connections) {
    await podmanApi.exec(['run','hello-world'], connection);
  }
}

I have two connections: podman-machine-default (qemu machine) and Podman (podman native).

After running the function above in AI Lab, I cannot see the hello-world on the qemu machine.

$: podman container ls -a
d67b196eac60  quay.io/podman/hello:latest                                                                                 /usr/local/bin/po...  3 minutes ago  Exited (0) 3 minutes ago                                                                          elastic_ganguly
1682a7a50ae1  quay.io/podman/hello:latest                                                                                 /usr/local/bin/po...  3 minutes ago  Exited (0) 3 minutes ago                                                                          pensive_saha
$: podman --connection=podman-machine-default container ls -s
# nothing

We seems to have both hello-world container running on the podman default

Throobleshooting

For some weird reason the following command

$: CONTAINERS_MACHINE_PROVIDER=podmanm-machine-default podman container ls -a

return the container list of the podman native connection. The only way to get the podman from the qemu is to use the following

$: podman --connection=podmanm-machine-default container ls

@dgolovin
Copy link
Contributor Author

that said, it needs to be something in the middle where we might not have all the endpoints but we need to be sure that what we're adding is working smoothly for the other extensions

Looking through podmanConnection.ts and it looks like it can be just moved over to podman extension and used as an API prototype. Whatever extension needs to work with podman directly would be able to use it directly from podman extension avoiding dealing with provider API.

@benoitf
Copy link
Collaborator

benoitf commented Sep 19, 2024

we can probably iterate there,

move as suggested all the options to a single option parameter

export interface PodmanRunOptions extends RunOptions {
  connection?: ProviderContainerConnection;
}
export interface PodmanExtensionApi {
  exec(args: string[], options?: PodmanRunOptions): Promise<RunResult>;
}

then we will be able to start publishing the artifact

then we can add the other parts.

connection?: extensionApi.ProviderContainerConnection,
options?: extensionApi.RunOptions,
): Promise<extensionApi.RunResult> {
return execPodman(args, connection?.connection.vmTypeDisplayName, options);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK it's not the display name to use but the vmType

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I have two wsl vmType, I need to use the connection name to be able to determine which one is supposed to be targeted

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both can be used, because if known display name is passed, it would be converted to vmType, otherwise if the passed value cannot be converted, it is used as as vmType (see execPodman).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CONTAINERS_MACHINE_PROVIDER allow us to target a provider (qemu, wsl etc.) but not a specific machine in the provider.

But as Florent said, let's iterate after this PR

Signed-off-by: Denis Golovin <[email protected]>
Copy link
Contributor

@axel7083 axel7083 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Collaborator

@benoitf benoitf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok for step 1

we have a short window until the API goes public with 1.13.0 release
so we can still change the API until that if we see it's not working in the extensions until that time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants