1use thiserror::Error;
4
5#[derive(Error, Debug)]
7pub enum OperatorError {
8 #[error("Kubernetes API error: {0}")]
10 KubeError(#[from] kube::Error),
11
12 #[error("Resource not found: {kind}/{name} in namespace {namespace}")]
14 NotFound {
15 kind: String,
16 name: String,
17 namespace: String,
18 },
19
20 #[error("Invalid configuration: {0}")]
22 InvalidConfig(String),
23
24 #[error("Reconciliation failed: {0}")]
26 ReconcileFailed(String),
27
28 #[error("Serialization error: {0}")]
30 SerializationError(#[from] serde_json::Error),
31
32 #[error("YAML serialization error: {0}")]
34 YamlError(#[from] serde_yaml::Error),
35
36 #[error("Validation error: {0}")]
38 ValidationError(String),
39
40 #[error("Finalizer error: {0}")]
42 FinalizerError(String),
43
44 #[error("Operation timed out: {0}")]
46 Timeout(String),
47
48 #[error("Internal error: {0}")]
50 Internal(String),
51
52 #[error("RivvenCluster not found: {0}")]
54 ClusterNotFound(String),
55
56 #[error("Connection to cluster failed: {0}")]
58 ConnectionFailed(String),
59
60 #[error("Cluster operation error: {0}")]
62 ClusterError(String),
63
64 #[error("Topic operation failed: {0}")]
66 TopicError(String),
67
68 #[error("Connect operation failed: {0}")]
70 ConnectError(String),
71}
72
73pub type Result<T> = std::result::Result<T, OperatorError>;
75
76impl OperatorError {
77 pub fn is_retryable(&self) -> bool {
79 matches!(
80 self,
81 OperatorError::KubeError(_)
82 | OperatorError::Timeout(_)
83 | OperatorError::ReconcileFailed(_)
84 )
85 }
86
87 pub fn requeue_delay(&self) -> Option<std::time::Duration> {
89 if self.is_retryable() {
90 Some(std::time::Duration::from_secs(30))
91 } else {
92 None
93 }
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn test_error_display() {
103 let err = OperatorError::NotFound {
104 kind: "StatefulSet".to_string(),
105 name: "rivven-cluster".to_string(),
106 namespace: "default".to_string(),
107 };
108 assert!(err.to_string().contains("StatefulSet"));
109 assert!(err.to_string().contains("rivven-cluster"));
110 }
111
112 #[test]
113 fn test_retryable_errors() {
114 let timeout_err = OperatorError::Timeout("test".to_string());
115 assert!(timeout_err.is_retryable());
116
117 let validation_err = OperatorError::ValidationError("test".to_string());
118 assert!(!validation_err.is_retryable());
119 }
120
121 #[test]
122 fn test_requeue_delay() {
123 let retryable = OperatorError::Timeout("test".to_string());
124 assert!(retryable.requeue_delay().is_some());
125
126 let not_retryable = OperatorError::InvalidConfig("test".to_string());
127 assert!(not_retryable.requeue_delay().is_none());
128 }
129}