1use super::Version;
7use crate::error::CoreError;
8use std::collections::{HashMap, VecDeque};
9
10#[cfg(feature = "serialization")]
11use serde::{Deserialize, Serialize};
12
13#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
15#[derive(Debug, Clone)]
16pub struct MigrationPlan {
17 pub from_version: Version,
19 pub toversion: Version,
21 pub steps: Vec<MigrationStep>,
23 pub estimated_effort: u32,
25 pub risk_level: RiskLevel,
27 pub rollback_plan: Option<RollbackPlan>,
29 pub prerequisites: Vec<String>,
31 pub validation_steps: Vec<String>,
33}
34
35#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
37#[derive(Debug, Clone)]
38pub struct MigrationStep {
39 pub id: String,
41 pub name: String,
43 pub description: String,
45 pub step_type: StepType,
47 pub estimated_effort: u32,
49 pub priority: StepPriority,
51 pub dependencies: Vec<String>,
53 pub automation_script: Option<String>,
55 pub manual_instructions: Option<String>,
57 pub validation_criteria: Vec<String>,
59 pub rollback_instructions: Option<String>,
61}
62
63#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum StepType {
67 CodeChange,
69 ConfigurationUpdate,
71 DatabaseMigration,
73 DependencyUpdate,
75 FeatureRemoval,
77 ApiChange,
79 DataFormatChange,
81 Testing,
83 Documentation,
85}
86
87#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
89#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
90pub enum StepPriority {
91 Optional,
93 Low,
95 Medium,
97 High,
99 Critical,
101}
102
103#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
105#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
106pub enum RiskLevel {
107 Low,
109 Medium,
111 High,
113 Critical,
115}
116
117#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
119#[derive(Debug, Clone)]
120pub struct RollbackPlan {
121 pub steps: Vec<RollbackStep>,
123 pub estimated_time: u32,
125 pub backup_requirements: Vec<String>,
127 pub recovery_validation: Vec<String>,
129}
130
131#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
133#[derive(Debug, Clone)]
134pub struct RollbackStep {
135 pub id: String,
137 pub description: String,
139 pub instructions: String,
141 pub validation: Option<String>,
143}
144
145#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
147#[derive(Debug, Clone)]
148pub struct MigrationExecution {
149 pub plan: MigrationPlan,
151 pub current_step: Option<String>,
153 pub completed_steps: Vec<String>,
155 pub failed_steps: Vec<String>,
157 pub status: ExecutionStatus,
159 pub start_time: chrono::DateTime<chrono::Utc>,
161 pub end_time: Option<chrono::DateTime<chrono::Utc>>,
163 pub executionlog: Vec<LogEntry>,
165}
166
167#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
169#[derive(Debug, Clone, Copy, PartialEq, Eq)]
170pub enum ExecutionStatus {
171 NotStarted,
173 InProgress,
175 Completed,
177 Failed,
179 Paused,
181 RolledBack,
183}
184
185#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
187#[derive(Debug, Clone)]
188pub struct LogEntry {
189 pub timestamp: chrono::DateTime<chrono::Utc>,
191 pub level: LogLevel,
193 pub step_id: Option<String>,
195 pub message: String,
197 pub data: Option<String>,
199}
200
201#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
203#[derive(Debug, Clone, Copy, PartialEq, Eq)]
204pub enum LogLevel {
205 Debug,
207 Info,
209 Warning,
211 Error,
213}
214
215pub struct MigrationManager {
217 migration_templates: HashMap<(Version, Version), MigrationTemplate>,
219 active_migrations: HashMap<String, MigrationExecution>,
221 migration_history: Vec<MigrationExecution>,
223}
224
225impl MigrationManager {
226 pub fn new() -> Self {
228 Self {
229 migration_templates: HashMap::new(),
230 active_migrations: HashMap::new(),
231 migration_history: Vec::new(),
232 }
233 }
234
235 pub fn register_version(&mut self, _apiversion: &super::ApiVersion) -> Result<(), CoreError> {
237 Ok(())
239 }
240
241 pub fn create_migration_plan(
243 &self,
244 from_version: &Version,
245 toversion: &Version,
246 ) -> Result<MigrationPlan, CoreError> {
247 if let Some(template) = self
249 .migration_templates
250 .get(&(from_version.clone(), toversion.clone()))
251 {
252 return Ok(template.create_plan(from_version.clone(), toversion.clone()));
253 }
254
255 if let Some(path) = self.find_migration_path(from_version, toversion)? {
257 self.create_multi_step_plan(&path)
258 } else {
259 self.create_default_migration_plan(from_version, toversion)
260 }
261 }
262
263 pub fn has_migration_path(&self, from_version: &Version, toversion: &Version) -> bool {
265 if self
267 .migration_templates
268 .contains_key(&(from_version.clone(), toversion.clone()))
269 {
270 return true;
271 }
272
273 self.find_migration_path(from_version, toversion)
275 .unwrap_or(None)
276 .is_some()
277 }
278
279 fn find_migration_path(
281 &self,
282 from_version: &Version,
283 toversion: &Version,
284 ) -> Result<Option<Vec<Version>>, CoreError> {
285 let mut queue = VecDeque::new();
287 let mut visited = std::collections::HashSet::new();
288 let mut parent: HashMap<Version, Version> = HashMap::new();
289
290 queue.push_back(from_version.clone());
291 visited.insert(from_version.clone());
292
293 while let Some(current) = queue.pop_front() {
294 if current == *toversion {
295 let mut path = Vec::new();
297 let mut node = current;
298
299 while let Some(p) = parent.get(&node) {
300 path.push(node);
301 node = p.clone();
302 }
303 path.push(from_version.clone());
304 path.reverse();
305
306 return Ok(Some(path));
307 }
308
309 for (from, to) in self.migration_templates.keys() {
311 if *from == current && !visited.contains(to) {
312 visited.insert(to.clone());
313 parent.insert(to.clone(), current.clone());
314 queue.push_back(to.clone());
315 }
316 }
317 }
318
319 Ok(None)
320 }
321
322 fn create_multi_step_plan(&self, path: &[Version]) -> Result<MigrationPlan, CoreError> {
324 let mut all_steps = Vec::new();
325 let mut total_effort = 0;
326 let mut max_risk = RiskLevel::Low;
327
328 for window in path.windows(2) {
329 if let Some(template) = self
330 .migration_templates
331 .get(&(window[0].clone(), window[1].clone()))
332 {
333 let plan = template.create_plan(window[0].clone(), window[1].clone());
334 all_steps.extend(plan.steps);
335 total_effort += plan.estimated_effort;
336 max_risk = max_risk.max(plan.risk_level);
337 }
338 }
339
340 Ok(MigrationPlan {
341 from_version: path.first().unwrap().clone(),
342 toversion: path.last().unwrap().clone(),
343 steps: all_steps,
344 estimated_effort: total_effort,
345 risk_level: max_risk,
346 rollback_plan: None, prerequisites: Vec::new(),
348 validation_steps: Vec::new(),
349 })
350 }
351
352 fn create_default_migration_plan(
354 &self,
355 from_version: &Version,
356 toversion: &Version,
357 ) -> Result<MigrationPlan, CoreError> {
358 let mut steps = Vec::new();
359 let risk_level = if toversion.major() > from_version.major() {
360 RiskLevel::High
361 } else if toversion.minor() > from_version.minor() {
362 RiskLevel::Medium
363 } else {
364 RiskLevel::Low
365 };
366
367 if toversion.major() > from_version.major() {
369 steps.push(MigrationStep {
370 id: "major_version_review".to_string(),
371 name: "Major Version Review".to_string(),
372 description: "Review all breaking changes in major version upgrade".to_string(),
373 step_type: StepType::CodeChange,
374 estimated_effort: 40,
375 priority: StepPriority::Critical,
376 dependencies: Vec::new(),
377 automation_script: None,
378 manual_instructions: Some(
379 "Review changelog and identify all breaking changes".to_string(),
380 ),
381 validation_criteria: vec![
382 "All breaking changes identified".to_string(),
383 "Migration strategy defined".to_string(),
384 ],
385 rollback_instructions: Some("Revert to previous _version".to_string()),
386 });
387 }
388
389 if toversion.minor() > from_version.minor() {
390 steps.push(MigrationStep {
391 id: "minor_version_update".to_string(),
392 name: "Minor Version Update".to_string(),
393 description: "Update to new minor version with backward compatibility".to_string(),
394 step_type: StepType::DependencyUpdate,
395 estimated_effort: 8,
396 priority: StepPriority::Medium,
397 dependencies: Vec::new(),
398 automation_script: Some("update_dependencies.sh".to_string()),
399 manual_instructions: None,
400 validation_criteria: vec!["All tests pass".to_string()],
401 rollback_instructions: Some("Revert dependency versions".to_string()),
402 });
403 }
404
405 steps.push(MigrationStep {
407 id: "comprehensive_testing".to_string(),
408 name: "Comprehensive Testing".to_string(),
409 description: "Run full test suite and integration tests".to_string(),
410 step_type: StepType::Testing,
411 estimated_effort: 16,
412 priority: StepPriority::Critical,
413 dependencies: steps.iter().map(|s| s.id.clone()).collect(),
414 automation_script: Some("run_tests.sh".to_string()),
415 manual_instructions: Some("Verify all functionality works as expected".to_string()),
416 validation_criteria: vec![
417 "All unit tests pass".to_string(),
418 "All integration tests pass".to_string(),
419 "Performance benchmarks met".to_string(),
420 ],
421 rollback_instructions: None,
422 });
423
424 let estimated_effort = steps.iter().map(|s| s.estimated_effort).sum();
425
426 Ok(MigrationPlan {
427 from_version: from_version.clone(),
428 toversion: toversion.clone(),
429 steps,
430 estimated_effort,
431 risk_level,
432 rollback_plan: Some(self.create_default_rollback_plan()),
433 prerequisites: vec![
434 "Create backup of current system".to_string(),
435 "Ensure rollback plan is tested".to_string(),
436 ],
437 validation_steps: vec![
438 "Verify system functionality".to_string(),
439 "Check performance metrics".to_string(),
440 "Validate data integrity".to_string(),
441 ],
442 })
443 }
444
445 fn create_default_rollback_plan(&self) -> RollbackPlan {
447 RollbackPlan {
448 steps: vec![RollbackStep {
449 id: "restore_backup".to_string(),
450 description: "Restore from backup".to_string(),
451 instructions: "Restore system from pre-migration backup".to_string(),
452 validation: Some("Verify system is functioning".to_string()),
453 }],
454 estimated_time: 30, backup_requirements: vec![
456 "Full system backup".to_string(),
457 "Database backup".to_string(),
458 "Configuration backup".to_string(),
459 ],
460 recovery_validation: vec![
461 "System startup successful".to_string(),
462 "All services running".to_string(),
463 "Data integrity verified".to_string(),
464 ],
465 }
466 }
467
468 pub fn start_migration(
470 &mut self,
471 plan: MigrationPlan,
472 executionid: String,
473 ) -> Result<(), CoreError> {
474 let execution = MigrationExecution {
475 plan,
476 current_step: None,
477 completed_steps: Vec::new(),
478 failed_steps: Vec::new(),
479 status: ExecutionStatus::NotStarted,
480 start_time: chrono::Utc::now(),
481 end_time: None,
482 executionlog: Vec::new(),
483 };
484
485 self.active_migrations.insert(executionid, execution);
486 Ok(())
487 }
488
489 pub fn id_2(&self, executionid: &str) -> Option<&MigrationExecution> {
491 self.active_migrations.get(executionid)
492 }
493
494 pub fn cleanup_old_plans(&mut self) -> Result<usize, CoreError> {
496 let cutoff = chrono::Utc::now() - chrono::Duration::days(30);
497 let initial_count = self.migration_history.len();
498
499 self.migration_history
500 .retain(|execution| execution.start_time > cutoff);
501
502 Ok(initial_count - self.migration_history.len())
503 }
504}
505
506impl Default for MigrationManager {
507 fn default() -> Self {
508 Self::new()
509 }
510}
511
512struct MigrationTemplate {
514 steps: Vec<MigrationStepTemplate>,
516 base_effort: u32,
518 risk_level: RiskLevel,
520}
521
522impl MigrationTemplate {
523 fn create_plan(&self, from_version: Version, toversion: Version) -> MigrationPlan {
524 let steps = self
525 .steps
526 .iter()
527 .map(|template| template.create_step())
528 .collect();
529
530 MigrationPlan {
531 from_version,
532 toversion,
533 steps,
534 estimated_effort: self.base_effort,
535 risk_level: self.risk_level,
536 rollback_plan: None,
537 prerequisites: Vec::new(),
538 validation_steps: Vec::new(),
539 }
540 }
541}
542
543struct MigrationStepTemplate {
545 id: String,
546 name: String,
547 description: String,
548 step_type: StepType,
549 estimated_effort: u32,
550 priority: StepPriority,
551}
552
553impl MigrationStepTemplate {
554 fn create_step(&self) -> MigrationStep {
555 MigrationStep {
556 id: self.id.clone(),
557 name: self.name.clone(),
558 description: self.description.clone(),
559 step_type: self.step_type,
560 estimated_effort: self.estimated_effort,
561 priority: self.priority,
562 dependencies: Vec::new(),
563 automation_script: None,
564 manual_instructions: None,
565 validation_criteria: Vec::new(),
566 rollback_instructions: None,
567 }
568 }
569}
570
571#[cfg(test)]
572mod tests {
573 use super::*;
574
575 #[test]
576 fn test_migration_manager_creation() {
577 let manager = MigrationManager::new();
578 assert!(manager.migration_templates.is_empty());
579 assert!(manager.active_migrations.is_empty());
580 }
581
582 #[test]
583 fn test_default_migration_plan() {
584 let manager = MigrationManager::new();
585 let from_version = Version::new(1, 0, 0);
586 let toversion = Version::new(2, 0, 0);
587
588 let plan = manager
589 .create_migration_plan(&from_version, &toversion)
590 .unwrap();
591 assert_eq!(plan.from_version, from_version);
592 assert_eq!(plan.toversion, toversion);
593 assert!(!plan.steps.is_empty());
594 assert_eq!(plan.risk_level, RiskLevel::High); }
596
597 #[test]
598 fn test_minor_version_migration() {
599 let manager = MigrationManager::new();
600 let from_version = Version::new(1, 0, 0);
601 let toversion = Version::new(1, 1, 0);
602
603 let plan = manager
604 .create_migration_plan(&from_version, &toversion)
605 .unwrap();
606 assert_eq!(plan.risk_level, RiskLevel::Medium); }
608
609 #[test]
610 fn test_patch_version_migration() {
611 let manager = MigrationManager::new();
612 let from_version = Version::new(1, 0, 0);
613 let toversion = Version::new(1, 0, 1);
614
615 let plan = manager
616 .create_migration_plan(&from_version, &toversion)
617 .unwrap();
618 assert_eq!(plan.risk_level, RiskLevel::Low); }
620
621 #[test]
622 fn test_migration_execution() {
623 let mut manager = MigrationManager::new();
624 let plan = MigrationPlan {
625 from_version: Version::new(1, 0, 0),
626 toversion: Version::new(1, 1, 0),
627 steps: Vec::new(),
628 estimated_effort: 8,
629 risk_level: RiskLevel::Medium,
630 rollback_plan: None,
631 prerequisites: Vec::new(),
632 validation_steps: Vec::new(),
633 };
634
635 let executionid = "test_migration_123".to_string();
636 manager.start_migration(plan, executionid.clone()).unwrap();
637
638 }
642
643 #[test]
644 fn test_step_priority_ordering() {
645 assert!(StepPriority::Critical > StepPriority::High);
646 assert!(StepPriority::High > StepPriority::Medium);
647 assert!(StepPriority::Medium > StepPriority::Low);
648 assert!(StepPriority::Low > StepPriority::Optional);
649 }
650
651 #[test]
652 fn test_risk_level_ordering() {
653 assert!(RiskLevel::Critical > RiskLevel::High);
654 assert!(RiskLevel::High > RiskLevel::Medium);
655 assert!(RiskLevel::Medium > RiskLevel::Low);
656 }
657}