microsoft/openvmm

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
a488949c3e59c0e4d8c2da58334bda23dfe591bc

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

249lines · modecode

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