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 {
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 {
75 "latest run failed".to_string()
76 },
77 });
78 }
79 }
80 }
81 Ok(_) => reached = true,
82 Err(e) => {
83 let msg = format!("{e:#}");
84 first_err
85 .get_or_insert_with(|| msg.lines().next().unwrap_or("unreachable").to_string());
86 }
87 }
88 }
89 if !reached {
90 out.push(RemoteProblem {
91 profile: profile.clone(),
92 panel: None,
93 name: profile,
94 status: Status::Failed,
95 note: first_err.unwrap_or_else(|| "workspace unreachable".to_string()),
96 });
97 }
98 out
99}