microsoft/openvmm

Public

mirrored fromhttps://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1ce32569373cda4d4b485f6e6f09f15e1e4dd569

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

251lines · modecode

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