Skip to content

Commit 997f04a

Browse files
committed
desktop: run local Intelligence on OpenBot's engine, on a rootful Podman machine
Which engine OpenBot uses is main's (#831): Docker if it answers, Docker Desktop if it has run before, otherwise Podman, saved with the installation. This commit no longer changes that choice. Local Intelligence's k3d needs rootful Podman (CopilotKit/Intelligence#2147), so the machine OpenBot creates is `--rootful`, and OpenBot addresses it through its `<name>-root` connection, the rootful engine, both for its own machine and for a running machine it adopts. On a rootful Windows machine the host-gateway setting goes to the system configuration. An existing rootless machine is never switched; local Intelligence setup and start decline there instead, with a `rootless-podman` failure whose row names `podman machine set --rootful`. Every Intelligence CLI process gets COPILOTKIT_LOCAL_ENGINE for the engine OpenBot runs on, recorded when the engine is ready (also where Docker answers right after the install step) and when Start pins it; before either, the installation's saved engine. For a Podman machine it also gets CONTAINER_HOST and DOCKER_HOST naming the machine's forwarded API, drops an inherited DOCKER_CONTEXT, and has Podman's directory on PATH. While Podman installs, the step row names the password prompt macOS or Linux raises. The window's runtime row no longer says Docker Desktop.
1 parent 0c42d56 commit 997f04a

8 files changed

Lines changed: 834 additions & 61 deletions

File tree

‎desktop/src-tauri/src/acquire.rs‎

Lines changed: 381 additions & 15 deletions
Large diffs are not rendered by default.

‎desktop/src-tauri/src/engine.rs‎

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
//! documentation, and the three differ more than they look:
55
//!
66
//! - **macOS.** `podman machine` puts a Linux VM behind a socket. Inside that VM
7-
//! `/var/run/docker.sock` is already a symlink to the rootless socket, so Compose's mount needs no
8-
//! help and `ENGINE_SOCKET` stays unset. `applehv` is the default on Apple silicon as of Podman
7+
//! `/var/run/docker.sock` is already a symlink to the socket of the mode the machine runs in
8+
//! (rootful for the machine OpenBot creates, see `acquire`), so Compose's mount needs no help and
9+
//! `ENGINE_SOCKET` stays unset. `applehv` is the default on Apple silicon as of Podman
910
//! 6.1, so no `--provider` is passed.
1011
//! - **Linux.** Podman is native and rootless and there is no VM. `/var/run/docker.sock` is either
1112
//! absent or, with `podman-docker` installed, a symlink to the *rootful* socket, which is not the
@@ -279,6 +280,9 @@ pub struct EngineStatus {
279280
/// Somebody who already has a machine up is handed it rather than made to wait while a duplicate
280281
/// boots beside it. Ours is preferred among running machines only so that repeat launches settle on
281282
/// the same one.
283+
///
284+
/// Answers with the connection for the machine's own mode (see `acquire::connection_for`): a rootful
285+
/// machine is reached through `<name>-root`, where its rootful engine is.
282286
fn running_machine(preferred: &str) -> Option<String> {
283287
let output = tool(Engine::Podman)
284288
.args(["machine", "list", "--format", "json"])
@@ -292,7 +296,7 @@ fn running_machine(preferred: &str) -> Option<String> {
292296
running()
293297
.find(|machine| machine.name == preferred)
294298
.or_else(|| running().next())
295-
.map(|machine| machine.name.clone())
299+
.map(|machine| crate::acquire::connection_of_machine(&machine.name))
296300
}
297301

298302
#[derive(Deserialize)]
@@ -381,17 +385,33 @@ does not reach Docker Desktop's `/usr/local/bin`. Appended, so a `docker` the pe
381385
their PATH stays first; both the link and the directory it resolves to, as `command_at` does.
382386
*/
383387
pub fn path_with_docker() -> Option<OsString> {
384-
let binary = program(Engine::Docker)?;
388+
path_with_engines(&[Engine::Docker])
389+
}
390+
391+
/// `path_with_docker`, for each of `engines` that is here, or None when none is.
392+
///
393+
/// The Intelligence CLI runs `podman` by name as it runs `docker`, and a Podman OpenBot installed
394+
/// in this session is not on this process's PATH (see the PATH rule above).
395+
pub fn path_with_engines(engines: &[Engine]) -> Option<OsString> {
396+
let binaries: Vec<PathBuf> = engines
397+
.iter()
398+
.filter_map(|engine| program(*engine))
399+
.collect();
400+
if binaries.is_empty() {
401+
return None;
402+
}
385403
let mut entries: Vec<PathBuf> = std::env::var_os("PATH")
386404
.map(|path| std::env::split_paths(&path).collect())
387405
.unwrap_or_default();
388-
let resolved = std::fs::canonicalize(&binary).ok();
389-
for directory in [binary.parent(), resolved.as_deref().and_then(Path::parent)]
390-
.into_iter()
391-
.flatten()
392-
{
393-
if !entries.iter().any(|entry| entry == directory) {
394-
entries.push(directory.to_path_buf());
406+
for binary in &binaries {
407+
let resolved = std::fs::canonicalize(binary).ok();
408+
for directory in [binary.parent(), resolved.as_deref().and_then(Path::parent)]
409+
.into_iter()
410+
.flatten()
411+
{
412+
if !entries.iter().any(|entry| entry == directory) {
413+
entries.push(directory.to_path_buf());
414+
}
395415
}
396416
}
397417
std::env::join_paths(entries).ok()
@@ -529,7 +549,8 @@ pub fn rootless_socket() -> Option<PathBuf> {
529549
#[cfg(not(target_os = "linux"))]
530550
pub fn rootless_socket() -> Option<PathBuf> {
531551
// macOS and Windows run the engine in a virtual machine, and inside it `/var/run/docker.sock`
532-
// is already the rootless socket. Compose mounts that path, so there is nothing to override.
552+
// is already the socket of the machine's own mode. Compose mounts that path, so there is
553+
// nothing to override.
533554
None
534555
}
535556

‎desktop/src-tauri/src/install.rs‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,17 +397,34 @@ pub fn install_engine_observed(
397397
installed: impl FnMut(Engine, bool),
398398
progress: &mut dyn FnMut(String),
399399
) -> Result<EngineChosen, Problem> {
400+
// Only one of the two runs, so they share the step row's lines one at a time.
401+
let progress = std::cell::RefCell::new(progress);
400402
install_engine_with(
401403
cache,
402404
Found::here(saved),
403405
saved,
404406
installed,
405-
|| crate::docker_desktop::start(progress),
406-
install_podman,
407+
|| crate::docker_desktop::start(&mut **progress.borrow_mut()),
408+
|into| {
409+
(progress.borrow_mut())(podman_install_said(std::env::consts::OS).into());
410+
install_podman(into)
411+
},
407412
place_compose,
408413
)
409414
}
410415

416+
/// The step row's line while Podman installs, naming the prompt the platform raises for it.
417+
///
418+
/// macOS asks for the person's password, because the package writes to `/opt/podman`. Windows
419+
/// asks for nothing here: the MSI installs for this account alone. Linux asks through `pkexec`.
420+
fn podman_install_said(os: &str) -> &'static str {
421+
match os {
422+
"macos" => "Installing Podman. Enter your Mac password when macOS asks for it.",
423+
"linux" => "Installing Podman. Enter your password when your system asks for it.",
424+
_ => "Installing Podman.",
425+
}
426+
}
427+
411428
/// What engines this machine has, read once so the choice below can be tested on any machine.
412429
///
413430
/// Nothing here asks what product is behind a `docker` command. A Docker that answers is used, a
@@ -1719,4 +1736,12 @@ esac
17191736
assert!(quoted.contains("Application Support"), "{quoted}");
17201737
assert!(!quoted.contains("\\\""), "{quoted}");
17211738
}
1739+
1740+
/// The prompt is named where there is one, and none is promised where there is not.
1741+
#[test]
1742+
fn the_podman_install_line_names_the_prompt_each_platform_raises() {
1743+
assert!(podman_install_said("macos").contains("password"));
1744+
assert!(podman_install_said("linux").contains("password"));
1745+
assert_eq!(podman_install_said("windows"), "Installing Podman.");
1746+
}
17221747
}

0 commit comments

Comments
 (0)