microsoft/openvmm

Public

mirrored from https://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
c8f70de480b5afd238530bd9f422db6753a653b2

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

flowey/flowey_cli/src/cli/debug/interrogate.rs

252lines · modecode

1// Copyright (C) Microsoft Corporation. All rights reserved.
2
3use crate::cli::FlowBackendCli;
4use flowey_core::node::steps::rust::RustRuntimeServices;
5use flowey_core::node::user_facing::ClaimedGhParam;
6use flowey_core::node::user_facing::GhPermission;
7use flowey_core::node::user_facing::GhPermissionValue;
8use flowey_core::node::FlowArch;
9use flowey_core::node::FlowBackend;
10use flowey_core::node::FlowPlatform;
11use flowey_core::node::NodeHandle;
12use std::collections::BTreeMap;
13
14/// (debug) get info about a specific node.
15///
16/// Information includes:
17/// - supported backends
18/// - supported requests
19/// - dependencies
20/// - inline steps (with exec-snippet indices)*
21///
22/// *inline-steps will only be listed if they are enabled via the particular
23/// combination of specified {backend x requests}. For a complete picture
24/// possible dependencies and available steps, you must inspect the Node's
25/// code and documentation directly.
26#[derive(clap::Args)]
27pub struct Interrogate {
28 /// Node to interrogate
29 node_handle: String,
30
31 /// Flow backend to interrogate with
32 flow_backend: FlowBackendCli,
33
34 /// Apply a request onto the node (as JSON)
35 #[clap(long)]
36 req: Vec<String>,
37}
38
39impl Interrogate {
40 pub fn run(self) -> anyhow::Result<()> {
41 let Self {
42 node_handle,
43 flow_backend,
44 req,
45 } = self;
46
47 let raw_json_reqs: Vec<Box<[u8]>> = req
48 .into_iter()
49 .map(|v| v.as_bytes().to_vec().into())
50 .collect();
51
52 let Some(node_handle) = NodeHandle::try_from_modpath(&node_handle) else {
53 anyhow::bail!("could not find node with that name");
54 };
55
56 let mut node = node_handle.new_erased_node();
57
58 let mut dep_registration_backend = InterrogateDepRegistrationBackend;
59 let mut dep_registration = flowey_core::node::new_import_ctx(&mut dep_registration_backend);
60
61 let mut ctx_backend = InterrogateCtx::new(flow_backend.into(), node_handle);
62
63 println!(
64 "# interrogating with {}",
65 match flow_backend {
66 FlowBackendCli::Ado => "ado",
67 FlowBackendCli::Local => "local",
68 FlowBackendCli::Github => "github",
69 }
70 );
71
72 node.imports(&mut dep_registration);
73
74 let mut ctx = flowey_core::node::new_node_ctx(&mut ctx_backend);
75 node.emit(raw_json_reqs.clone(), &mut ctx)?;
76
77 Ok(())
78 }
79}
80
81struct InterrogateDepRegistrationBackend;
82
83impl flowey_core::node::ImportCtxBackend for InterrogateDepRegistrationBackend {
84 fn on_possible_dep(&mut self, node_handle: NodeHandle) {
85 println!("[dep?] {}", node_handle.modpath())
86 }
87}
88
89struct InterrogateCtx {
90 flow_backend: FlowBackend,
91 current_node: NodeHandle,
92 idx_tracker: usize,
93 var_tracker: usize,
94}
95
96impl InterrogateCtx {
97 fn new(flow_backend: FlowBackend, current_node: NodeHandle) -> Self {
98 Self {
99 flow_backend,
100 current_node,
101 idx_tracker: 0,
102 var_tracker: 0,
103 }
104 }
105}
106
107impl flowey_core::node::NodeCtxBackend for InterrogateCtx {
108 fn on_emit_rust_step(
109 &mut self,
110 label: &str,
111 _code: Box<
112 dyn for<'a> FnOnce(&'a mut RustRuntimeServices<'_>) -> anyhow::Result<()> + 'static,
113 >,
114 ) {
115 println!("[step][rust][{}] # {}", self.idx_tracker, label);
116 self.idx_tracker += 1;
117 }
118
119 fn on_emit_ado_step(
120 &mut self,
121 label: &str,
122 yaml_snippet: Box<
123 dyn for<'a> FnOnce(
124 &'a mut flowey_core::node::user_facing::AdoStepServices<'_>,
125 ) -> String,
126 >,
127 code: Option<
128 Box<
129 dyn for<'a> FnOnce(&'a mut RustRuntimeServices<'_>) -> anyhow::Result<()> + 'static,
130 >,
131 >,
132 _condvar: Option<String>,
133 ) {
134 println!(
135 "[step][yaml] # {}{}",
136 if code.is_some() {
137 "(+inline script) "
138 } else {
139 ""
140 },
141 label
142 );
143 let mut fresh_ado_var = || "<dummy>".into();
144 let mut access = flowey_core::node::steps::ado::new_ado_step_services(&mut fresh_ado_var);
145 let raw_snippet = yaml_snippet(&mut access);
146
147 let snippet: Result<serde_yaml::Value, _> = serde_yaml::from_str(&raw_snippet);
148 match snippet {
149 Ok(snippet) => print!("{}", serde_yaml::to_string(&snippet).unwrap()),
150 Err(e) => {
151 log::error!("invalid snippet: {}", e);
152 println!(">>>");
153 println!("{}", raw_snippet);
154 println!("<<<");
155 }
156 };
157
158 self.idx_tracker += 1;
159 }
160
161 fn on_emit_gh_step(
162 &mut self,
163
164 label: &str,
165 _uses: &str,
166 _with: BTreeMap<String, ClaimedGhParam>,
167 _condvar: Option<String>,
168 _outputs: BTreeMap<String, Vec<(String, bool)>>,
169 _permissions: BTreeMap<GhPermission, GhPermissionValue>,
170 _gh_to_rust: Vec<(String, String, bool)>,
171 _rust_to_gh: Vec<(String, String, bool)>,
172 ) {
173 println!("[step][yaml] # {}", label);
174 self.idx_tracker += 1;
175 }
176
177 fn on_emit_side_effect_step(&mut self) {
178 println!("[step][anchor]");
179 }
180
181 fn backend(&mut self) -> FlowBackend {
182 self.flow_backend
183 }
184
185 fn platform(&mut self) -> FlowPlatform {
186 if cfg!(windows) {
187 FlowPlatform::Windows
188 } else if cfg!(target_os = "linux") {
189 FlowPlatform::Linux
190 } else {
191 unreachable!("flowey only runs on windows/linux at the moment")
192 }
193 }
194
195 fn arch(&mut self) -> FlowArch {
196 // xtask-fmt allow-target-arch oneoff-flowey
197 if cfg!(target_arch = "x86_64") {
198 FlowArch::X86_64
199 // xtask-fmt allow-target-arch oneoff-flowey
200 } else if cfg!(target_arch = "aarch64") {
201 FlowArch::Aarch64
202 } else {
203 unreachable!("flowey only runs on X86_64 or Aarch64 at the moment")
204 }
205 }
206
207 fn on_request(&mut self, node_handle: NodeHandle, req: anyhow::Result<Box<[u8]>>) {
208 match req {
209 Ok(data) => {
210 let data = match String::from_utf8(data.into()) {
211 Ok(data) => data,
212 Err(e) => e
213 .into_bytes()
214 .iter()
215 .map(|b| format!("(raw) {:02x}", b))
216 .collect::<Vec<_>>()
217 .join(""),
218 };
219 println!("[req] {} <-- {}", node_handle.modpath(), data)
220 }
221 Err(e) => {
222 log::error!("error serializing inter-node request: {:#}", e)
223 }
224 }
225 }
226
227 fn on_new_var(&mut self) -> String {
228 let v = self.var_tracker;
229 self.var_tracker += 1;
230 format!("<dummy>:{}", v)
231 }
232
233 fn on_claimed_runtime_var(&mut self, var: &str, is_read: bool) {
234 println!(
235 "[var][claim] {} {}",
236 var,
237 if is_read { "(read)" } else { "(write)" },
238 )
239 }
240
241 fn current_node(&self) -> NodeHandle {
242 self.current_node
243 }
244
245 fn persistent_dir_path_var(&mut self) -> Option<String> {
246 Some("<dummy>".into())
247 }
248
249 fn on_unused_read_var(&mut self, _var: &str) {
250 // not relevant
251 }
252}
253