flowey_lib_hvlite/
stop_test_igvm_agent_rpc_server.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Stop the test_igvm_agent_rpc_server after VMM tests complete.
5//!
6//! This node terminates any running test_igvm_agent_rpc_server.exe processes
7//! using taskkill. It should be run after VMM tests complete to clean up
8//! the background server process started by run_test_igvm_agent_rpc_server.
9//!
10//! **Note:** This node only supports Windows. Callers should check the platform
11//! before requesting this node.
12
13use flowey::node::prelude::*;
14
15flowey_request! {
16    pub struct Request {
17        /// Dependency to ensure this runs after tests complete
18        pub after_tests: ReadVar<SideEffect>,
19        /// Completion indicator - signals that the server has been stopped
20        pub done: WriteVar<SideEffect>,
21    }
22}
23
24new_simple_flow_node!(struct Node);
25
26impl SimpleFlowNode for Node {
27    type Request = Request;
28
29    fn imports(_ctx: &mut ImportCtx<'_>) {}
30
31    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
32        let Request { after_tests, done } = request;
33
34        // This node only supports Windows - fail at flow-graph construction time
35        // if someone mistakenly tries to use it on another platform.
36        if !matches!(ctx.platform(), FlowPlatform::Windows) {
37            anyhow::bail!(
38                "stop_test_igvm_agent_rpc_server only supports Windows. \
39                Callers should check the platform before requesting this node."
40            );
41        }
42
43        ctx.emit_rust_step("stopping test_igvm_agent_rpc_server", |ctx| {
44            after_tests.claim(ctx);
45            done.claim(ctx);
46            move |_rt| stop_rpc_server()
47        });
48
49        Ok(())
50    }
51}
52
53#[cfg(windows)]
54fn stop_rpc_server() -> anyhow::Result<()> {
55    log::info!("stopping test_igvm_agent_rpc_server processes");
56
57    // Use taskkill to terminate any running instances
58    let output = std::process::Command::new("taskkill")
59        .args(["/F", "/IM", "test_igvm_agent_rpc_server.exe"])
60        .output();
61
62    match output {
63        Ok(output) => {
64            let stdout = String::from_utf8_lossy(&output.stdout);
65            let stderr = String::from_utf8_lossy(&output.stderr);
66
67            if output.status.success() {
68                log::info!("test_igvm_agent_rpc_server terminated: {}", stdout.trim());
69            } else if stderr.contains("not found") || stdout.contains("not found") {
70                // Process wasn't running - that's fine
71                log::info!("test_igvm_agent_rpc_server was not running");
72            } else {
73                log::warn!(
74                    "taskkill returned non-zero: stdout={}, stderr={}",
75                    stdout.trim(),
76                    stderr.trim()
77                );
78            }
79        }
80        Err(e) => {
81            log::warn!("failed to run taskkill: {}", e);
82        }
83    }
84
85    Ok(())
86}
87
88#[cfg(not(windows))]
89fn stop_rpc_server() -> anyhow::Result<()> {
90    // This should never be called - the node rejects non-Windows at construction time.
91    // But we need this for compilation on non-Windows hosts.
92    anyhow::bail!("stop_test_igvm_agent_rpc_server is only supported on Windows")
93}