rocketmq_error/unified/tools.rs
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18//! Tools and Admin operation specific errors
19//!
20//! This module contains error types specific to RocketMQ admin tools and CLI operations.
21
22use thiserror::Error;
23
24/// Tools-specific errors for admin operations
25#[derive(Debug, Error)]
26pub enum ToolsError {
27 // ============================================================================
28 // Topic Management Errors
29 // ============================================================================
30 /// Topic not found
31 #[error("Topic '{topic}' not found")]
32 TopicNotFound { topic: String },
33
34 /// Topic already exists
35 #[error("Topic '{topic}' already exists")]
36 TopicAlreadyExists { topic: String },
37
38 /// Invalid topic configuration
39 #[error("Invalid topic configuration: {reason}")]
40 TopicInvalid { reason: String },
41
42 // ============================================================================
43 // Cluster Management Errors
44 // ============================================================================
45 /// Cluster not found
46 #[error("Cluster '{cluster}' not found")]
47 ClusterNotFound { cluster: String },
48
49 /// Invalid cluster configuration
50 #[error("Invalid cluster configuration: {reason}")]
51 ClusterInvalid { reason: String },
52
53 // ============================================================================
54 // Broker Management Errors
55 // ============================================================================
56 /// Broker not found
57 #[error("Broker '{broker}' not found")]
58 BrokerNotFound { broker: String },
59
60 /// Broker offline
61 #[error("Broker '{broker}' is offline")]
62 BrokerOffline { broker: String },
63
64 // ============================================================================
65 // Consumer Management Errors
66 // ============================================================================
67 /// Consumer group not found
68 #[error("Consumer group '{group}' not found")]
69 ConsumerGroupNotFound { group: String },
70
71 /// Consumer offline
72 #[error("Consumer '{consumer}' is offline")]
73 ConsumerOffline { consumer: String },
74
75 // ============================================================================
76 // NameServer Management Errors
77 // ============================================================================
78 /// NameServer unreachable
79 #[error("NameServer '{addr}' is unreachable")]
80 NameServerUnreachable { addr: String },
81
82 /// NameServer configuration invalid
83 #[error("Invalid NameServer configuration: {reason}")]
84 NameServerConfigInvalid { reason: String },
85
86 // ============================================================================
87 // Configuration Errors
88 // ============================================================================
89 /// Invalid configuration field
90 #[error("Invalid configuration for '{field}': {reason}")]
91 InvalidConfiguration { field: String, reason: String },
92
93 /// Missing required field
94 #[error("Missing required field: '{field}'")]
95 MissingRequiredField { field: String },
96
97 // ============================================================================
98 // Validation Errors
99 // ============================================================================
100 /// Input validation failed
101 #[error("Validation failed for '{field}': {reason}")]
102 ValidationError { field: String, reason: String },
103
104 /// Generic validation error
105 #[error("Validation error: {message}")]
106 ValidationFailed { message: String },
107
108 // ============================================================================
109 // Permission Errors
110 // ============================================================================
111 /// Permission denied for operation
112 #[error("Permission denied for operation: {operation}")]
113 PermissionDenied { operation: String },
114
115 /// Invalid permission value
116 #[error("Invalid permission value: {value}, allowed values: {}", .allowed.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))]
117 InvalidPermission { value: i32, allowed: Vec<i32> },
118
119 // ============================================================================
120 // Operation Errors
121 // ============================================================================
122 /// Operation timeout
123 #[error("Operation '{operation}' timed out after {duration_ms}ms")]
124 OperationTimeout { operation: String, duration_ms: u64 },
125
126 /// Generic internal error
127 #[error("Internal error: {message}")]
128 Internal { message: String },
129}
130
131impl ToolsError {
132 // ============================================================================
133 // Convenience Constructors
134 // ============================================================================
135
136 /// Create a topic not found error
137 #[inline]
138 pub fn topic_not_found(topic: impl Into<String>) -> Self {
139 Self::TopicNotFound {
140 topic: topic.into(),
141 }
142 }
143
144 /// Create a topic already exists error
145 #[inline]
146 pub fn topic_already_exists(topic: impl Into<String>) -> Self {
147 Self::TopicAlreadyExists {
148 topic: topic.into(),
149 }
150 }
151
152 /// Create a cluster not found error
153 #[inline]
154 pub fn cluster_not_found(cluster: impl Into<String>) -> Self {
155 Self::ClusterNotFound {
156 cluster: cluster.into(),
157 }
158 }
159
160 /// Create a broker not found error
161 #[inline]
162 pub fn broker_not_found(broker: impl Into<String>) -> Self {
163 Self::BrokerNotFound {
164 broker: broker.into(),
165 }
166 }
167
168 /// Create a validation error
169 #[inline]
170 pub fn validation_error(field: impl Into<String>, reason: impl Into<String>) -> Self {
171 Self::ValidationError {
172 field: field.into(),
173 reason: reason.into(),
174 }
175 }
176
177 /// Create a nameserver unreachable error
178 #[inline]
179 pub fn nameserver_unreachable(addr: impl Into<String>) -> Self {
180 Self::NameServerUnreachable { addr: addr.into() }
181 }
182
183 /// Create a nameserver config invalid error
184 #[inline]
185 pub fn nameserver_config_invalid(reason: impl Into<String>) -> Self {
186 Self::NameServerConfigInvalid {
187 reason: reason.into(),
188 }
189 }
190
191 /// Create an internal error
192 #[inline]
193 pub fn internal(message: impl Into<String>) -> Self {
194 Self::Internal {
195 message: message.into(),
196 }
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn test_topic_not_found() {
206 let err = ToolsError::topic_not_found("TestTopic");
207 assert_eq!(err.to_string(), "Topic 'TestTopic' not found");
208 }
209
210 #[test]
211 fn test_validation_error() {
212 let err = ToolsError::validation_error("topic_name", "name too long");
213 assert_eq!(
214 err.to_string(),
215 "Validation failed for 'topic_name': name too long"
216 );
217 }
218
219 #[test]
220 fn test_broker_offline() {
221 let err = ToolsError::BrokerOffline {
222 broker: "broker-a".to_string(),
223 };
224 assert_eq!(err.to_string(), "Broker 'broker-a' is offline");
225 }
226}