Skip to main content

k8s_netinspect/
errors.rs

1use std::fmt;
2use colored::*;
3
4/// Custom error types for k8s-netinspect with specific error codes
5#[derive(Debug)]
6pub enum NetInspectError {
7    /// Kubernetes API connection errors (exit code 3)
8    KubernetesConnection(String),
9    /// RBAC/Permission errors (exit code 5)
10    PermissionDenied(String),
11    /// Configuration errors (exit code 2)
12    Configuration(String),
13    /// Network connectivity issues (exit code 4)
14    NetworkConnectivity(String),
15    /// Invalid input/arguments (exit code 2)
16    InvalidInput(String),
17    /// Resource not found (exit code 4)
18    ResourceNotFound(String),
19    /// Timeout errors
20    Timeout(String),
21    /// General runtime errors (exit code 1)
22    Runtime(String),
23}
24
25impl fmt::Display for NetInspectError {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        match self {
28            NetInspectError::KubernetesConnection(msg) => {
29                write!(f, "{} {}", "Kubernetes Connection Error:".red().bold(), msg)
30            }
31            NetInspectError::PermissionDenied(msg) => {
32                write!(f, "{} {}", "Permission Denied:".yellow().bold(), msg)
33            }
34            NetInspectError::Configuration(msg) => {
35                write!(f, "{} {}", "Configuration Error:".purple().bold(), msg)
36            }
37            NetInspectError::NetworkConnectivity(msg) => {
38                write!(f, "{} {}", "Network Error:".red().bold(), msg)
39            }
40            NetInspectError::InvalidInput(msg) => {
41                write!(f, "{} {}", "Invalid Input:".yellow().bold(), msg)
42            }
43            NetInspectError::ResourceNotFound(msg) => {
44                write!(f, "{} {}", "Resource Not Found:".blue().bold(), msg)
45            }
46            NetInspectError::Timeout(msg) => {
47                write!(f, "{} {}", "Timeout:".red().bold(), msg)
48            }
49            NetInspectError::Runtime(msg) => {
50                write!(f, "{} {}", "Runtime Error:".red().bold(), msg)
51            }
52        }
53    }
54}
55
56impl std::error::Error for NetInspectError {}
57
58impl NetInspectError {
59    /// Get the exit code for this error type
60    pub fn exit_code(&self) -> i32 {
61        match self {
62            NetInspectError::KubernetesConnection(_) => 3,
63            NetInspectError::PermissionDenied(_) => 5,
64            NetInspectError::Configuration(_) => 2,
65            NetInspectError::NetworkConnectivity(_) => 4,
66            NetInspectError::InvalidInput(_) => 2,
67            NetInspectError::ResourceNotFound(_) => 4,
68            NetInspectError::Timeout(_) => 4,
69            NetInspectError::Runtime(_) => 1,
70        }
71    }
72
73    /// Create a user-friendly error message with troubleshooting hints
74    pub fn detailed_message(&self) -> String {
75        match self {
76            NetInspectError::KubernetesConnection(msg) => {
77                format!(
78                    "{}\n{} Ensure kubeconfig is valid and cluster is accessible\n{} Check: kubectl cluster-info",
79                    msg,
80                    "💡 Troubleshooting:".cyan().bold(),
81                    "  •".blue()
82                )
83            }
84            NetInspectError::PermissionDenied(msg) => {
85                format!(
86                    "{}\n{} Check RBAC permissions for your service account\n{} Required: pods/get, nodes/list",
87                    msg,
88                    "💡 Troubleshooting:".cyan().bold(),
89                    "  •".blue()
90                )
91            }
92            NetInspectError::Configuration(msg) => {
93                format!(
94                    "{}\n{} Verify kubeconfig file and context\n{} Check: kubectl config current-context",
95                    msg,
96                    "💡 Troubleshooting:".cyan().bold(),
97                    "  •".blue()
98                )
99            }
100            NetInspectError::NetworkConnectivity(msg) => {
101                format!(
102                    "{}\n{} Network connectivity issue detected\n{} Pod may not be running or port may be closed",
103                    msg,
104                    "💡 Troubleshooting:".cyan().bold(),
105                    "  •".blue()
106                )
107            }
108            NetInspectError::InvalidInput(msg) => {
109                format!(
110                    "{}\n{} Check command syntax and arguments\n{} Use --help for usage information",
111                    msg,
112                    "💡 Troubleshooting:".cyan().bold(),
113                    "  •".blue()
114                )
115            }
116            NetInspectError::ResourceNotFound(msg) => {
117                format!(
118                    "{}\n{} Verify resource exists in the specified namespace\n{} Check: kubectl get pods -n <namespace>",
119                    msg,
120                    "💡 Troubleshooting:".cyan().bold(),
121                    "  •".blue()
122                )
123            }
124            NetInspectError::Timeout(msg) => {
125                format!(
126                    "{}\n{} Operation timed out - cluster may be slow or unreachable\n{} Try again or use kubectl directly to test connectivity",
127                    msg,
128                    "💡 Troubleshooting:".cyan().bold(),
129                    "  •".blue()
130                )
131            }
132            NetInspectError::Runtime(msg) => {
133                format!(
134                    "{}\n{} Unexpected error occurred\n{} Please check logs and try again",
135                    msg,
136                    "💡 Troubleshooting:".cyan().bold(),
137                    "  •".blue()
138                )
139            }
140        }
141    }
142}
143
144/// Convert from kube::Error to NetInspectError
145impl From<kube::Error> for NetInspectError {
146    fn from(err: kube::Error) -> Self {
147        match err {
148            kube::Error::Api(api_err) => {
149                match api_err.code {
150                    401 | 403 => NetInspectError::PermissionDenied(
151                        format!("Kubernetes API access denied: {}", api_err.message)
152                    ),
153                    404 => NetInspectError::ResourceNotFound(
154                        format!("Resource not found: {}", api_err.message)
155                    ),
156                    _ => NetInspectError::KubernetesConnection(
157                        format!("Kubernetes API error: {}", api_err.message)
158                    ),
159                }
160            }
161            kube::Error::HttpError(http_err) => {
162                NetInspectError::KubernetesConnection(
163                    format!("HTTP error connecting to Kubernetes: {}", http_err)
164                )
165            }
166            kube::Error::Auth(auth_err) => {
167                NetInspectError::PermissionDenied(
168                    format!("Authentication failed: {}", auth_err)
169                )
170            }
171            kube::Error::Discovery(discovery_err) => {
172                NetInspectError::KubernetesConnection(
173                    format!("Service discovery failed: {}", discovery_err)
174                )
175            }
176            _ => NetInspectError::KubernetesConnection(
177                format!("Kubernetes client error: {}", err)
178            ),
179        }
180    }
181}
182
183/// Convert from reqwest::Error to NetInspectError
184impl From<reqwest::Error> for NetInspectError {
185    fn from(err: reqwest::Error) -> Self {
186        if err.is_timeout() {
187            NetInspectError::Timeout(
188                "HTTP request timed out - pod may be unreachable".to_string()
189            )
190        } else if err.is_connect() {
191            NetInspectError::NetworkConnectivity(
192                format!("Failed to connect to pod: {}", err)
193            )
194        } else {
195            NetInspectError::NetworkConnectivity(
196                format!("HTTP request failed: {}", err)
197            )
198        }
199    }
200}
201
202/// Convert from anyhow::Error to NetInspectError
203impl From<anyhow::Error> for NetInspectError {
204    fn from(err: anyhow::Error) -> Self {
205        NetInspectError::Runtime(err.to_string())
206    }
207}
208
209/// Result type alias for convenience
210pub type NetInspectResult<T> = Result<T, NetInspectError>;