databricks_tui/fetchers/
problems.rs1use crate::cli::DatabricksCli;
6use crate::shape::{Shape, Status};
7
8pub struct RemoteProblem {
10 pub profile: String,
11 pub panel: Option<usize>,
14 pub name: String,
15 pub status: Status,
16 pub note: String,
17}
18
19pub async fn fetch(profiles: Vec<String>, current: String) -> Vec<RemoteProblem> {
23 let handles: Vec<_> = profiles
24 .into_iter()
25 .filter(|name| *name != current)
26 .map(|name| tokio::spawn(scan_one(name)))
27 .collect();
28 let mut out = Vec::new();
29 for h in handles {
30 if let Ok(mut v) = h.await {
31 out.append(&mut v);
32 }
33 }
34 out
35}
36
37async fn scan_one(profile: String) -> Vec<RemoteProblem> {
38 let arg = if profile == "DEFAULT" {
39 None
40 } else {
41 Some(profile.clone())
42 };
43 let cli = DatabricksCli::new(arg);
44 let (clusters, jobs, pipelines, warehouses) = tokio::join!(
45 crate::fetchers::clusters::fetch(&cli),
46 crate::fetchers::jobs::fetch(&cli),
47 crate::fetchers::pipelines::fetch(&cli),
48 crate::fetchers::warehouses::fetch(&cli),
49 );
50
51 let mut out = Vec::new();
52 let mut reached = false;
53 let mut first_err: Option<String> = None;
54 for (panel, fetched) in [(0, clusters), (1, jobs), (2, pipelines), (3, warehouses)] {
57 match fetched {
58 Ok(Shape::List(items)) => {
59 reached = true;
60 for it in items {
61 let failed_now = matches!(it.status, Status::Failed);
62 let failed_last = it
63 .history
64 .last()
65 .is_some_and(|s| matches!(s, Status::Failed));
66 if failed_now || failed_last || it.alert.is_some() {
67 out.push(RemoteProblem {
68 profile: profile.clone(),
69 panel: Some(panel),
70 name: it.name,
71 status: it.status,
72 note: if failed_now {
73 it.detail.unwrap_or_default()
74 } else if let Some(alert) = it.alert {
75 alert
76 } else {
77 "latest run failed".to_string()
78 },
79 });
80 }
81 }
82 }
83 Ok(_) => reached = true,
84 Err(e) => {
85 let msg = format!("{e:#}");
86 first_err
87 .get_or_insert_with(|| msg.lines().next().unwrap_or("unreachable").to_string());
88 }
89 }
90 }
91 if !reached {
92 out.push(RemoteProblem {
93 profile: profile.clone(),
94 panel: None,
95 name: profile,
96 status: Status::Failed,
97 note: first_err.unwrap_or_else(|| "workspace unreachable".to_string()),
98 });
99 }
100 out
101}