-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy patherrors.rs
More file actions
352 lines (301 loc) · 13.1 KB
/
errors.rs
File metadata and controls
352 lines (301 loc) · 13.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
//! Error types for the Configure Subcommand
//!
//! This module defines error types that can occur during CLI configure command execution.
//! All errors follow the project's error handling principles by providing clear,
//! contextual, and actionable error messages with `.help()` methods.
use thiserror::Error;
use crate::application::command_handlers::configure::errors::ConfigureCommandHandlerError;
use crate::domain::environment::name::EnvironmentNameError;
use crate::presentation::cli::views::progress::ProgressReporterError;
use crate::presentation::cli::views::ViewRenderError;
/// Configure command specific errors
///
/// This enum contains all error variants specific to the configure command,
/// including environment validation, repository access, and configuration failures.
/// Each variant includes relevant context and actionable error messages.
#[derive(Debug, Error)]
pub enum ConfigureSubcommandError {
// ===== Environment Validation Errors =====
/// Environment name validation failed
///
/// The provided environment name doesn't meet the validation requirements.
/// Use `.help()` for detailed troubleshooting steps.
#[error("Invalid environment name '{name}': {source}
Tip: Environment names must be 1-63 characters, start with letter/digit, contain only letters/digits/hyphens")]
InvalidEnvironmentName {
name: String,
#[source]
source: EnvironmentNameError,
},
/// Environment not found or inaccessible
///
/// The environment couldn't be loaded from persistent storage.
/// Use `.help()` for detailed troubleshooting steps.
#[error(
"Environment '{name}' not found or inaccessible from data directory '{data_dir}'
Tip: Check if environment exists: ls -la {data_dir}/"
)]
EnvironmentNotAccessible { name: String, data_dir: String },
/// Environment is not in Provisioned state
///
/// The environment is in the wrong state for configuration.
/// Use `.help()` for detailed troubleshooting steps.
#[error(
"Environment '{name}' is in '{current_state}' state, but 'Provisioned' state is required for configuration
Tip: Only environments in 'Provisioned' state can be configured"
)]
InvalidEnvironmentState { name: String, current_state: String },
// ===== Repository Access Errors =====
/// Repository operation failed
///
/// Failed to create or access the environment repository.
/// Use `.help()` for detailed troubleshooting steps.
#[error(
"Failed to access environment repository at '{data_dir}': {reason}
Tip: Check directory permissions and disk space"
)]
RepositoryAccessFailed { data_dir: String, reason: String },
// ===== Configure Operation Errors =====
/// Configure operation failed
///
/// The configuration process encountered an error during execution.
/// Use `.help()` for detailed troubleshooting steps.
#[error(
"Failed to configure environment '{name}': {source}
Tip: Check logs and try running with --log-output file-and-stderr for more details"
)]
ConfigureOperationFailed {
name: String,
#[source]
source: Box<ConfigureCommandHandlerError>,
},
// ===== Internal Errors =====
/// Progress reporting failed
///
/// Failed to report progress to the user due to an internal error.
/// This indicates a critical internal error.
#[error(
"Failed to report progress: {source}
Tip: This is a critical bug - please report it with full logs using --log-output file-and-stderr"
)]
ProgressReportingFailed {
#[source]
source: ProgressReporterError,
},
/// Output formatting failed (JSON serialization error).
/// This indicates an internal error in data serialization.
#[error(
"Failed to format output: {reason}\nTip: This is a critical bug - please report it with full logs using --log-output file-and-stderr"
)]
OutputFormatting { reason: String },
}
// ============================================================================
// ERROR CONVERSIONS
// ============================================================================
impl From<ProgressReporterError> for ConfigureSubcommandError {
fn from(source: ProgressReporterError) -> Self {
Self::ProgressReportingFailed { source }
}
}
impl From<ViewRenderError> for ConfigureSubcommandError {
fn from(e: ViewRenderError) -> Self {
Self::OutputFormatting {
reason: e.to_string(),
}
}
}
impl ConfigureSubcommandError {
/// Get detailed troubleshooting guidance for this error
///
/// This method provides comprehensive troubleshooting steps that can be
/// displayed to users when they need more help resolving the error.
///
/// # Example
///
/// Using with Container and `ExecutionContext` (recommended):
///
/// ```ignore
/// use std::path::Path;
/// use std::sync::Arc;
/// use torrust_tracker_deployer_lib::bootstrap::Container;
/// use torrust_tracker_deployer_lib::presentation::cli::dispatch::ExecutionContext;
/// use torrust_tracker_deployer_lib::presentation::cli::controllers::configure;
/// use torrust_tracker_deployer_lib::presentation::cli::views::VerbosityLevel;
///
/// let container = Container::new(VerbosityLevel::Normal, Path::new("."));
/// let context = ExecutionContext::new(Arc::new(container), global_args);
///
/// if let Err(e) = context
/// .container()
/// .create_configure_controller()
/// .execute("test-env")
/// {
/// eprintln!("Error: {e}");
/// eprintln!("\nTroubleshooting:\n{}", e.help());
/// }
/// ```
///
/// Direct usage (for testing):
///
/// ```ignore
/// use std::path::{Path, PathBuf};
/// use std::sync::Arc;
/// use std::time::Duration;
/// use parking_lot::ReentrantMutex;
/// use std::cell::RefCell;
/// use torrust_tracker_deployer_lib::presentation::cli::controllers::configure::handler::ConfigureCommandController;
/// use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};
/// use torrust_tracker_deployer_lib::infrastructure::persistence::file_repository_factory::FileRepositoryFactory;
/// use torrust_tracker_deployer_lib::shared::clock::SystemClock;
///
/// # #[tokio::main]
/// # async fn main() {
/// let output = Arc::new(ReentrantMutex::new(RefCell::new(UserOutput::new(VerbosityLevel::Normal))));
/// let data_dir = PathBuf::from("./data");
/// let file_repository_factory = FileRepositoryFactory::new(Duration::from_secs(30));
/// let repository = file_repository_factory.create(data_dir);
/// let clock = Arc::new(SystemClock);
/// if let Err(e) = ConfigureCommandController::new(repository, clock, output).execute("test-env") {
/// eprintln!("Error: {e}");
/// eprintln!("\nTroubleshooting:\n{}", e.help());
/// }
/// # }
/// ```
#[must_use]
#[allow(clippy::too_many_lines)] // Help text is comprehensive for user guidance
pub fn help(&self) -> &'static str {
match self {
Self::InvalidEnvironmentName { .. } => {
"Invalid Environment Name - Detailed Troubleshooting:
1. Check environment name format:
- Length: Must be 1-63 characters
- Start: Must begin with a letter or digit
- Characters: Only letters, digits, and hyphens allowed
- No special characters: Avoid spaces, underscores, dots
2. Valid examples:
- 'production'
- 'staging-01'
- 'dev-environment'
3. Invalid examples:
- 'prod_01' (underscore not allowed)
- '-production' (cannot start with hyphen)
- 'prod.env' (dots not allowed)
For more information, see environment naming documentation."
}
Self::EnvironmentNotAccessible { .. } => {
"Environment Not Accessible - Detailed Troubleshooting:
1. Verify environment exists:
- List environments: ls -la data/
- Check for environment.json file in data/<environment-name>/
2. Check file permissions:
- Read permission: chmod +r data/<environment-name>/environment.json
- Directory access: chmod +rx data/<environment-name>/
3. Verify data directory:
- Ensure data/ directory exists
- Check disk space: df -h
- Verify no file locks: lsof data/
4. Common solutions:
- Create environment first: torrust-tracker-deployer create environment -f <config-file>
- Provision environment: torrust-tracker-deployer provision <env-name>
- Check working directory: pwd
- Verify correct environment name
For more information, see the provision command documentation."
}
Self::InvalidEnvironmentState { .. } => {
"Invalid Environment State - Detailed Troubleshooting:
The configure command requires an environment in 'Provisioned' state.
1. Check current state:
- View environment file: cat data/<environment-name>/environment.json
- Look for 'state' field
2. State transitions:
- Provisioned → Configuring → Configured (success path)
- Provisioned → Configuring → ConfigureFailed (error path)
3. If environment is already Configured:
- Environment is ready to use
- No need to configure again
- Proceed to next deployment steps
4. If environment is in ConfigureFailed state:
- Review error logs to understand failure
- Fix underlying issues (network, permissions, etc.)
- Try configuring again
5. If environment is not yet Provisioned:
- Provision environment first: torrust-tracker-deployer provision <env-name>
- Wait for provisioning to complete
- Then run configure command
For more information, see environment lifecycle documentation."
}
Self::RepositoryAccessFailed { .. } => {
"Repository Access Failed - Detailed Troubleshooting:
1. Check directory permissions:
- Read/write access: ls -la data/
- Fix permissions: chmod -R u+rw data/
2. Verify disk space:
- Check available space: df -h
- Free up space if needed
3. Check for file locks:
- List open files: lsof data/
- Kill processes if safe to do so
4. Verify directory exists:
- Create if missing: mkdir -p data/
- Check parent directory permissions
5. Common issues:
- Running multiple instances simultaneously
- File system mounted read-only
- Insufficient permissions
For persistent issues, check system logs and file system health."
}
Self::ConfigureOperationFailed { .. } => {
"Configure Operation Failed - Detailed Troubleshooting:
1. Review detailed error logs:
- Run with verbose output: --log-output file-and-stderr
- Check log files in data/logs/
2. Common failure points:
- Ansible playbook execution failures
- Docker installation issues
- Docker Compose installation problems
- SSH connectivity issues
- System package manager failures
3. Infrastructure-specific troubleshooting:
SSH connectivity:
- Verify SSH keys exist: ls -la ~/.ssh/
- Check VM/server is running using provider tools
- Test SSH manually: ssh -i <key> <user>@<ip>
Docker installation:
- SSH into server and check: docker --version
- Verify package manager: apt-get update (or equivalent)
- Check internet connectivity: ping -c 3 google.com
Ansible issues:
- Check Ansible is installed: ansible --version
- Verify playbook syntax: ansible-playbook --syntax-check <playbook>
- Review Ansible logs in data/logs/
4. Recovery steps:
- Review error messages and logs
- Fix underlying issues (network, permissions, etc.)
- Try configure command again
- If persistent, destroy and recreate environment
For more information, see the configuration troubleshooting guide."
}
Self::ProgressReportingFailed { .. } => {
"Progress Reporting Failed - Critical Internal Error:
This is a critical internal error that should not occur during normal operation.
1. Immediate actions:
- Save full error output
- Copy log files from data/logs/
- Note the exact command that was running
2. Report the issue:
- Create GitHub issue with full details
- Include: command, error output, logs, system info
- Describe steps to reproduce
3. Temporary workarounds:
- Try running command again
- Restart application
- Check for system resource issues (memory, file descriptors)
This error indicates a bug in the progress reporting system.
Please report it so we can fix it."
}
Self::OutputFormatting { .. } => {
"Output Formatting Failed - Critical Internal Error:\n\nThis error should not occur during normal operation. It indicates a bug in the output formatting system.\n\n1. Immediate actions:\n - Save full error output\n - Copy log files from data/logs/\n - Note the exact command and output format being used\n\n2. Report the issue:\n - Create GitHub issue with full details\n - Include: command, output format (--output-format), error output, logs\n - Describe steps to reproduce\n\n3. Temporary workarounds:\n - Try using different output format (text vs json)\n - Try running command again\n\nPlease report it so we can fix it."
}
}
}
}