lean_ctx/core/patterns/
linkerd.rs1use crate::core::compressor::strip_ansi;
9
10pub fn compress(command: &str, output: &str) -> Option<String> {
11 let sub = command
12 .trim()
13 .strip_prefix("linkerd")
14 .map_or("", str::trim_start)
15 .split_whitespace()
16 .next()
17 .unwrap_or("");
18 if sub != "check" {
19 return None;
20 }
21 Some(compress_check(output))
22}
23
24fn compress_check(output: &str) -> String {
25 let mut kept: Vec<String> = Vec::new();
26 let mut passed = 0usize;
27 let mut failed = 0usize;
28 let mut in_failure = false;
29
30 for raw in output.lines() {
31 let line = strip_ansi(raw);
32 let t = line.trim_end();
33 let probe = t.trim();
34 if probe.is_empty() {
35 in_failure = false;
36 continue;
37 }
38 if probe.chars().all(|c| c == '-') {
40 continue;
41 }
42 if probe.starts_with('√') || probe.starts_with('✓') {
43 passed += 1;
44 in_failure = false;
45 continue;
46 }
47 if probe.starts_with('×') || probe.starts_with('✗') {
48 failed += 1;
49 in_failure = true;
50 kept.push(probe.to_string());
51 continue;
52 }
53 if in_failure && (t.starts_with(' ') || t.starts_with('\t')) {
55 kept.push(probe.to_string());
56 continue;
57 }
58 let pl = probe.to_ascii_lowercase();
59 if pl.starts_with("status check results") {
60 kept.push(probe.to_string());
61 in_failure = false;
62 }
63 }
64
65 let tally = format!("linkerd check: {passed} passed, {failed} failed");
66 if kept.is_empty() {
67 return tally;
68 }
69 format!("{tally}\n{}", kept.join("\n"))
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 const CHECK: &str = "kubernetes-api\n--------------\n√ can initialize the client\n√ can query the Kubernetes API\n\nlinkerd-existence\n-----------------\n√ 'linkerd-config' config map exists\n× control plane pods are ready\n some pods are not ready: linkerd-destination-abc\n see https://linkerd.io/2/checks/#l5d-api-control-ready for hints\n\nStatus check results are ×\n";
77
78 #[test]
79 fn keeps_failures_and_verdict_drops_passing() {
80 let r = compress("linkerd check", CHECK).unwrap();
81 assert!(r.contains("× control plane pods are ready"), "{r}");
82 assert!(r.contains("some pods are not ready"), "keeps hint: {r}");
83 assert!(r.contains("Status check results are ×"), "{r}");
84 assert!(r.contains("3 passed, 1 failed"), "tally: {r}");
85 assert!(
86 !r.contains("can initialize the client"),
87 "drops passing: {r}"
88 );
89 }
90
91 #[test]
92 fn non_check_subcommand_passes_through() {
93 assert!(compress("linkerd viz stat deploy", "some table").is_none());
94 }
95}