Skip to content

Commit cffa34a

Browse files
committed
Fix several morloc-manager bugs
- unfreeze hangs forever during validation because the serve image ENTRYPOINT causes --help to run as router args instead of a direct command. Fixed by adding --entrypoint "" override. - stop <env> silently kills a different running container when the named one isn't serving. Removed the fallback; now returns error. - freeze produces base_image "unknown" when active env comes from system config fallback. Now checks system config like resolve_active_env_name does. - daemon logs spurious "read error" on first /call/ because the router's readiness probe connects then closes without sending data. Added MSG_PEEK to silently ignore EOF probe connections. - start hint leaked raw docker/podman command instead of morloc-manager logs. - ls output now shows "Local environments:" header with indentation, matching the system environments section.
1 parent c6166d1 commit cffa34a

4 files changed

Lines changed: 46 additions & 21 deletions

File tree

data/rust/morloc-manager/src/freeze.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,26 @@ pub fn freeze_from_dir(
6767
eprintln!("Created {tar_path}");
6868
let now = Utc::now();
6969

70-
// Get base image from the active environment config
71-
let m_cfg = config::read_active_config();
72-
let active_env_name = m_cfg.as_ref().and_then(|c| c.active_env.as_deref());
73-
74-
let (base_img, env_layer) = if let Some(env_name) = active_env_name {
75-
match config::read_env_config(scope, env_name) {
70+
// Get base image from the active environment config.
71+
// Check local config first, then system config for the active env name
72+
// (mirrors resolve_active_env_name in environment.rs).
73+
let active_env_name: Option<String> = config::read_active_config()
74+
.and_then(|c| c.active_env)
75+
.or_else(|| {
76+
let sys_path = config::config_path(Scope::System);
77+
config::read_config::<Config>(&sys_path)
78+
.ok()
79+
.and_then(|c| c.active_env)
80+
});
81+
82+
let (base_img, env_layer) = if let Some(ref env_name) = active_env_name {
83+
let env_scope = config::find_env_scope(env_name).unwrap_or(scope);
84+
match config::read_env_config(env_scope, env_name) {
7685
Ok(ec) => {
7786
let base = ec.base_image.clone();
7887
// Capture env layer info if there's a Dockerfile
7988
let layer = if ec.dockerfile.is_some() {
80-
let df_path = config::env_dockerfile_path(scope, env_name);
89+
let df_path = config::env_dockerfile_path(env_scope, env_name);
8190
if df_path.exists() {
8291
let df_contents = fs::read_to_string(&df_path).unwrap_or_default();
8392
let content_hash = ec.content_hash.unwrap_or_default();

data/rust/morloc-manager/src/main.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,12 +1055,15 @@ fn dispatch(verbose: bool, cmd: Cmd) -> Result<()> {
10551055
let local_active = if active_in_local { active_str } else { None };
10561056
let envs = environment::list_environments(Scope::Local, local_active);
10571057
total += envs.len();
1058-
for e in envs {
1059-
let active_mark = if e.active { " (active)" } else { "" };
1060-
let ver_mark = e.morloc_version
1061-
.map(|v| format!(" [{}]", v.show()))
1062-
.unwrap_or_default();
1063-
println!("{}{}{}", e.name, ver_mark, active_mark);
1058+
if !envs.is_empty() {
1059+
println!("Local environments:");
1060+
for e in envs {
1061+
let active_mark = if e.active { " (active)" } else { "" };
1062+
let ver_mark = e.morloc_version
1063+
.map(|v| format!(" [{}]", v.show()))
1064+
.unwrap_or_default();
1065+
println!(" {}{}{}", e.name, ver_mark, active_mark);
1066+
}
10641067
}
10651068
}
10661069
if show_system {
@@ -1071,7 +1074,7 @@ fn dispatch(verbose: bool, cmd: Cmd) -> Result<()> {
10711074
if show_local {
10721075
println!();
10731076
}
1074-
println!("System:");
1077+
println!("System environments:");
10751078
for e in envs {
10761079
let active_mark = if e.active { " (active)" } else { "" };
10771080
let ver_mark = e.morloc_version
@@ -1472,10 +1475,9 @@ fn dispatch(verbose: bool, cmd: Cmd) -> Result<()> {
14721475
serve::stop_serve_container(ec.engine, verbose, &container_name)?;
14731476
eprintln!("Stopped serving environment: {env_name}");
14741477
} else {
1475-
// Fallback: scan for running serve containers
1476-
let (found_name, found_engine) = find_running_serve_container()?;
1477-
serve::stop_serve_container(found_engine, verbose, &found_name)?;
1478-
eprintln!("Stopped {found_name} (active env '{env_name}' was not serving)");
1478+
return Err(ManagerError::EnvError(
1479+
format!("No serve container running for environment '{env_name}'")
1480+
));
14791481
}
14801482
Ok(())
14811483
}

data/rust/morloc-manager/src/serve.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ pub fn run_serve_container(
247247
if state == "running" {
248248
eprintln!("Container {name} started");
249249
eprintln!(" Stop: morloc-manager stop {name}");
250-
eprintln!(" Logs: {exe} logs -f {name}");
250+
eprintln!(" Logs: morloc-manager logs");
251251
eprintln!(" Status: morloc-manager status");
252252
Ok(())
253253
} else {
@@ -357,7 +357,7 @@ pub fn serve_environment(
357357
if state == "running" {
358358
eprintln!("Container {container_name} started");
359359
eprintln!(" Stop: morloc-manager stop");
360-
eprintln!(" Logs: {exe} logs -f {container_name}");
360+
eprintln!(" Logs: morloc-manager logs");
361361
eprintln!(" Status: morloc-manager status");
362362
Ok(())
363363
} else {
@@ -489,14 +489,17 @@ pub fn validate_programs(
489489
let exe_path = format!("{}/bin/{}", CONTAINER_MORLOC_HOME, prog.name);
490490
if verbose {
491491
let exe = engine_executable(engine);
492-
eprintln!("[morloc-manager] {exe} run --rm {image} {exe_path} --help");
492+
eprintln!("[morloc-manager] {exe} run --rm --entrypoint '' {image} {exe_path} --help");
493493
}
494494
let cfg = RunConfig {
495495
bind_mounts: bind_mounts.clone(),
496496
command: Some(vec![exe_path, "--help".to_string()]),
497497
env: vec![
498498
("MORLOC_HOME".to_string(), CONTAINER_MORLOC_HOME.to_string()),
499499
],
500+
// Override the image ENTRYPOINT so the command runs directly
501+
// instead of being appended to the router entrypoint.
502+
extra_flags: vec!["--entrypoint".to_string(), "".to_string()],
500503
..RunConfig::new(image)
501504
};
502505
let (status, _stdout, stderr) = container_run_quiet(engine, &cfg);

data/rust/morloc-runtime/src/daemon_ffi.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,17 @@ unsafe fn handle_lp_connection(
13331333
let mut errmsg: *mut c_char = ptr::null_mut();
13341334
let mut msg_len: usize = 0;
13351335

1336+
// Peek to distinguish a probe connection (immediate EOF) from a real
1337+
// client. The router's readiness check connects then closes without
1338+
// sending data; silently ignore those.
1339+
let mut peek_buf = [0u8; 1];
1340+
let peek_n = libc::recv(client_fd, peek_buf.as_mut_ptr() as *mut c_void, 1, libc::MSG_PEEK);
1341+
if peek_n == 0 {
1342+
// Clean EOF — probe connection, silently close.
1343+
libc::close(client_fd);
1344+
return;
1345+
}
1346+
13361347
let msg = read_lp_message(client_fd, &mut msg_len, &mut errmsg);
13371348
if !errmsg.is_null() {
13381349
let err_str = CStr::from_ptr(errmsg).to_string_lossy();

0 commit comments

Comments
 (0)