-
Notifications
You must be signed in to change notification settings - Fork 16
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 launch VM button #865
Conversation
6b1c9b8
to
2a40cc1
Compare
c1e9589
to
9dbe951
Compare
This is an initial implementation and meant for experimenting as parts have not been finalized yet / further discussion needed. Feel free to test it out @deboer-tim @slemeur We can further discuss this during the week! |
00a2992
to
017082e
Compare
7f889c4
to
b38fa33
Compare
Comments from my initial testing:
|
Agreed, let's launch it and maybe just link to docs near the status icon to give more information?
I don't think we should hide, but maybe an empty page saying "must build raw image, no raw image found"?
Intentional! Sorry!
Will fix.
I agree :( I think we should have that in a follow up issue / PR though.
|
Screen.Recording.2024-10-01.at.12.56.43.PM.mov@deboer-tim Ready for another review! I have done the following:
Feel free to test it out and let me know if this works and I can begin adding some unit tests so we can get this initial POC in. |
73cc1d8
to
a570f03
Compare
Ready for review with the exception of unit tests being added later. This is marked as experimental (as per the tab) and only shown for macOS users. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As before, testing worked without any issues.
I don't love auto-launching a 'large' VM, but that's fine for first pass. The main drawback is the VM getting reset when you leave the tab, but again that is expected for this first step.
packages/shared/src/BootcAPI.ts
Outdated
@@ -21,6 +21,7 @@ import type { ImageInfo, ImageInspectInfo, ManifestInspectInfo } from '@podman-d | |||
|
|||
export abstract class BootcApi { | |||
abstract checkPrereqs(): Promise<string | undefined>; | |||
abstract checkVMLaunchPrereqs(folder: string, architecture: string): Promise<string | undefined>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both backend and frontend know about list of BootcBuildInfos (i.e. disk images), but frontend grabs folder and arch from one of these to check if it can be launched, then to actually launchVM(). Seems like we could use the BootBuildInfo or its id directly instead? i.e. can I launch disk image X / run disk image Y.
561f0d5
to
b314111
Compare
@deboer-tim updated with a new commit! Let me know if that works and I can start on tests 👍 |
Thanks for the changes! I was also suggesting instead of: |
Done! I use BuildImageInfo for that section now because who knows what other information we may be passing in the future now. |
464623c
to
89f5a7a
Compare
### What does this PR do? * Using QEMU we add a feature to "Launch VM" in the background * Uses websockets, qemu as well as our xterm.js library to achieve this * Launches in "snapshot" mode so no data is written to .raw file so the file can be easily re-used ### Screenshot / video of UI <!-- If this PR is changing UI, please include screenshots or screencasts showing the difference --> ### What issues does this PR fix or reference? <!-- Include any related issues from Podman Desktop repository (or from another issue tracker). --> Closes podman-desktop#813 ### How to test this PR? <!-- Please explain steps to reproduce --> 1. Be on macOS silicon 2. `brew install qemu` 3. Build a bootc container image 4. Press launch VM button in actions bar Signed-off-by: Charlie Drage <[email protected]>
Signed-off-by: Charlie Drage <[email protected]>
Signed-off-by: Charlie Drage <[email protected]>
Signed-off-by: Charlie Drage <[email protected]>
Signed-off-by: Charlie Drage <[email protected]>
Tests added and ready for review 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all the improvements, @cdrage. One minor url change noted but otherwise let's get this in and get some feedback!
@@ -17,7 +20,20 @@ async function deleteBuild(): Promise<void> { | |||
async function gotoLogs(): Promise<void> { | |||
router.goto(`/disk-image/${btoa(object.id)}/build`); | |||
} | |||
|
|||
async function gotoVM(): Promise<void> { | |||
router.goto(`/details/${btoa(object.id)}/vm`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to be updated to /disk-image/
after the nav change.
Signed-off-by: Charlie Drage <[email protected]>
@deboer-tim Updated and confirm link works now! Agreed, let's get this in even if it's in nightly and get some feedback :) Screen.Recording.2024-10-21.at.9.34.34.AM.mov |
dismissing as changes were made based on review + two other reviews of tim and axel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cdrage cdrage dismissed [benoitf]
please do not dismiss the review of someone without asking him first
} | ||
await this.notify(Messages.MSG_VM_LAUNCH_ERROR, { success: '', error: errorMessage }); | ||
} | ||
return Promise.resolve(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do not need to return anything
it's an async method being void so just remove
|
||
// Stop VM by pid file on the system | ||
async stopCurrentVM(): Promise<void> { | ||
return await new VMManager().stopCurrentVM(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do not return await here, return the promise
private build: BootcBuildInfo; | ||
|
||
// Only values needed is the location of the VM file as well as the architecture of the image that | ||
// will be used. | ||
constructor(build?: BootcBuildInfo) { | ||
this.build = build!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please don't do that
it can't be optional and then you're saying there is a value with !
it will make unexpected runtime failures
if (isMac() && isArm()) { | ||
return this.checkMacPrereqs(); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it doesn't scale well there, the idea was to have multiple instances
like you have an abstract base, then a MacArm, a MacIntel that has a preReqs method to fill
it's not the client that needs to do the if if at each call
} | ||
|
||
private isArchitectureSupported(): boolean { | ||
return this.build.arch === 'amd64' || this.build.arch === 'arm64'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be part of the Mac implementation
// Unsupported: MacOS Intel, Linux, Windows | ||
private generateLaunchCommand(diskImage: string): string[] { | ||
// Future support for Mac Intel, Linux ARM, Linux X86 and Windows ARM, Windows X86 to be added here. | ||
if (isMac() && isArm()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we had proper method in macArm implementation, we would not need the is and is
// logs.terminal.buffer.normal will contain the "ascii cursor" with a value of 1 until there is more logs. | ||
// we wait until buffer.normal.length is more than 1. | ||
while (logsTerminal.buffer.normal.length < 1) { | ||
await new Promise(resolve => setTimeout(resolve, 500)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should have a safe exit (max-retries) to avoid infinite loop
async function resetTerminalTheme(): Promise<void> { | ||
// Wait until we have more than 100 lines in the buffer before resetting the terminal | ||
while (logsTerminal.buffer.normal.length < 100) { | ||
await new Promise(resolve => setTimeout(resolve, 500)); | ||
} | ||
|
||
// Reset the terminal | ||
logsTerminal.reset(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it doesn't reset the theme, it reset the terminal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's intentional as it will clear any ASCII background characters in the log output. Tried many other alternative ways (including "setting the theme again") and nothing works.
It's a bug with websockets mode and using the host hardware for mac support and luckily a very minor edge case.
// Allow copy / paste support with Ctrl+V | ||
logsTerminal.attachCustomKeyEventHandler((arg: KeyboardEvent) => { | ||
// Allow copy and paste from the ctrl key (windows and linux) | ||
// and "meta" key (macOS). Sometimes on macOS the ctrl key is used, so we safely assume that either meta or ctrl is meant | ||
// for paste. | ||
if ((arg.ctrlKey || arg.metaKey) && arg.code === 'KeyV' && arg.type === 'keydown') { | ||
bootcClient.readFromClipboard().then(clipboardText => { | ||
// Send to socket | ||
if (socket !== undefined) { | ||
const encoder = new TextEncoder(); | ||
const binaryData = encoder.encode(clipboardText); | ||
socket.send(binaryData.buffer); | ||
} | ||
}); | ||
} | ||
return true; | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need that, I can copy/paste in Terminal of Podman Desktop without this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason is because we are using the special websockets mode for addon-attach https://www.npmjs.com/package/xterm-addon-attach and unfortunately we have to "disable stdin" since it's more meant for viewing websocket connections rather than interaction.
That's why we have to add a custom event handler for copying and pasting code as well as interpret each keystroke (see key section code).
I apologize and won't dismiss in the future. I had implemented your suggestions. I should of asked. I'll follow up in a new PR with the suggested changes. |
feat: add launch VM button
What does this PR do?
file can be easily re-used
Screenshot / video of UI
Screen.Recording.2024-09-27.at.11.05.00.AM.mov
What issues does this PR fix or reference?
Closes #813
How to test this PR?
brew install qemu
Signed-off-by: Charlie Drage [email protected]