• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NVIDIA / nvrc / 29083537597

10 Jul 2026 09:35AM UTC coverage: 96.808%. First build
29083537597

Pull #167

github

web-flow
Merge 3cc4b0b66 into 97c22f98b
Pull Request #167: nvrc: support Kata composable VM images

559 of 603 new or added lines in 8 files covered. (92.7%)

2608 of 2694 relevant lines covered (96.81%)

22.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.53
/src/execute.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// Copyright (c) NVIDIA CORPORATION
3

4
use std::process::{Child, Command, Stdio};
5

6
use crate::gpu;
7
use crate::kmsg::kmsg;
8
use crate::macros::ResultExt;
9

10
/// Scope the GPU loader path to NVRC-spawned processes so kata-agent, exec'd
11
/// elsewhere, never inherits it.
12
fn gpu_scoped_command(command: &str, args: &[&str]) -> Command {
203✔
13
    let mut cmd = Command::new(command);
203✔
14
    cmd.args(args);
203✔
15
    if let Some(path) = gpu::ld_library_path() {
203✔
NEW
16
        cmd.env("LD_LIBRARY_PATH", path);
×
17
    }
203✔
18
    cmd
203✔
19
}
203✔
20

21
/// Run a command and block until completion. Output goes to kmsg so it appears
22
/// in dmesg/kernel log - the only reliable log destination in minimal VMs.
23
/// Used for setup commands that must succeed before continuing (nvidia-smi, modprobe).
24
pub fn foreground(command: &str, args: &[&str]) {
71✔
25
    debug!("{} {}", command, args.join(" "));
71✔
26

27
    let kmsg_file = kmsg();
71✔
28
    let status = gpu_scoped_command(command, args)
71✔
29
        .stdout(Stdio::from(kmsg_file.try_clone().unwrap()))
71✔
30
        .stderr(Stdio::from(kmsg_file))
71✔
31
        .status()
71✔
32
        .or_panic(format_args!("execute {command}"));
71✔
33

34
    if !status.success() {
71✔
35
        panic!("{command} failed with status: {status}");
47✔
36
    }
24✔
37
}
24✔
38

39
/// Spawn a daemon without waiting. Returns Child so caller can track it later.
40
/// Used for long-running services (nvidia-persistenced, fabricmanager) that run
41
/// alongside kata-agent. Output to kmsg for visibility in kernel log.
42
pub fn background(command: &str, args: &[&str]) -> Child {
132✔
43
    debug!("{} {}", command, args.join(" "));
132✔
44
    let kmsg_file = kmsg();
132✔
45
    gpu_scoped_command(command, args)
132✔
46
        .stdout(Stdio::from(kmsg_file.try_clone().unwrap()))
132✔
47
        .stderr(Stdio::from(kmsg_file))
132✔
48
        .spawn()
132✔
49
        .or_panic(format_args!("start {command}"))
132✔
50
}
132✔
51

52
#[cfg(test)]
53
mod tests {
54
    use super::*;
55
    use std::panic;
56

57
    // ==================== foreground tests ====================
58

59
    #[test]
60
    #[cfg_attr(miri, ignore = "miri cannot emulate process spawn")]
61
    fn test_foreground_success() {
11✔
62
        foreground("/bin/true", &[]);
11✔
63
    }
11✔
64

65
    #[test]
66
    #[cfg_attr(miri, ignore = "miri cannot emulate process spawn")]
67
    fn test_foreground_failure_exit_code() {
11✔
68
        // Command runs but exits non-zero - should panic
69
        let result = panic::catch_unwind(|| {
11✔
70
            foreground("/bin/false", &[]);
11✔
71
        });
11✔
72
        assert!(result.is_err());
11✔
73
    }
11✔
74

75
    #[test]
76
    #[cfg_attr(miri, ignore = "miri cannot emulate process spawn")]
77
    fn test_foreground_not_found() {
11✔
78
        // Command doesn't exist - should panic
79
        let result = panic::catch_unwind(|| {
11✔
80
            foreground("/nonexistent/command", &[]);
11✔
81
        });
11✔
82
        assert!(result.is_err());
11✔
83
    }
11✔
84

85
    #[test]
86
    #[cfg_attr(miri, ignore = "miri cannot emulate process spawn")]
87
    fn test_foreground_with_args() {
11✔
88
        foreground("/bin/sh", &["-c", "exit 0"]);
11✔
89

90
        let result = panic::catch_unwind(|| {
11✔
91
            foreground("/bin/sh", &["-c", "exit 42"]);
11✔
92
        });
11✔
93
        assert!(result.is_err());
11✔
94
    }
11✔
95

96
    // ==================== background tests ====================
97

98
    #[test]
99
    #[cfg_attr(miri, ignore = "miri cannot emulate process spawn")]
100
    fn test_background_spawns() {
11✔
101
        let mut child = background("/bin/sleep", &["0.01"]);
11✔
102
        let status = child.wait().unwrap();
11✔
103
        assert!(status.success());
11✔
104
    }
11✔
105

106
    #[test]
107
    #[cfg_attr(miri, ignore = "miri cannot emulate process spawn")]
108
    // spawn fails and or_panic diverges, so no child is ever returned to wait on.
109
    #[allow(clippy::zombie_processes)]
110
    fn test_background_not_found() {
11✔
111
        // Command doesn't exist - should panic
112
        let result = panic::catch_unwind(|| {
11✔
113
            background("/nonexistent/command", &[]);
11✔
114
        });
11✔
115
        assert!(result.is_err());
11✔
116
    }
11✔
117

118
    #[test]
119
    #[cfg_attr(miri, ignore = "miri cannot emulate process spawn")]
120
    fn test_background_check_later() {
11✔
121
        let mut child = background("/bin/sh", &["-c", "exit 7"]);
11✔
122
        let status = child.wait().unwrap();
11✔
123
        assert!(!status.success());
11✔
124
        assert_eq!(status.code(), Some(7));
11✔
125
    }
11✔
126
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc