1use crate::prelude::*;
2
3use crate::migration_data;
4use kanidm_proto::internal::{
5 DomainUpgradeCheckReport as ProtoDomainUpgradeCheckReport,
7 };
9
10use super::ServerPhase;
11
12impl QueryServer {
13 #[instrument(level = "info", name = "system_initialisation", skip_all)]
14 pub async fn initialise_helper(
15 &self,
16 ts: Duration,
17 domain_target_level: DomainVersion,
18 ) -> Result<(), OperationError> {
19 let mut write_txn = self.write(ts).await?;
22
23 write_txn.upgrade_reindex(SYSTEM_INDEX_VERSION)?;
27
28 if domain_target_level < DOMAIN_LEVEL_1_11 {
38 write_txn
40 .initialise_schema_core()
41 .and_then(|_| write_txn.reload())?;
42 }
43
44 let db_domain_version = match write_txn.internal_search_uuid(UUID_DOMAIN_INFO) {
47 Ok(e) => Ok(e.get_ava_single_uint32(Attribute::Version).unwrap_or(0)),
48 Err(OperationError::NoMatchingEntries) => Ok(0),
49 Err(r) => Err(r),
50 }?;
51
52 debug!(?db_domain_version, "Before setting internal domain info");
53
54 if db_domain_version == DOMAIN_LEVEL_0 {
55 debug_assert!(domain_target_level <= DOMAIN_MAX_LEVEL);
59
60 const { assert!(DOMAIN_MIN_CREATION_LEVEL == DOMAIN_LEVEL_11) };
62
63 match domain_target_level {
67 DOMAIN_LEVEL_11 => write_txn.migrate_domain_10_to_11()?,
68 DOMAIN_LEVEL_12 => write_txn.migrate_domain_11_to_12()?,
69 DOMAIN_LEVEL_13 => write_txn.migrate_domain_12_to_13()?,
70 DOMAIN_LEVEL_14 => write_txn.migrate_domain_13_to_14()?,
71 DOMAIN_LEVEL_1_11 => write_txn.migrate_domain_1_10_to_1_11()?,
72 DOMAIN_LEVEL_1_12 => write_txn.migrate_domain_1_11_to_1_12()?,
73 DOMAIN_LEVEL_1_13 => write_txn.migrate_domain_1_12_to_1_13()?,
74 _ => {
75 error!("Invalid requested domain target level for server bootstrap");
76 debug_assert!(false);
77 return Err(OperationError::MG0009InvalidTargetLevelForBootstrap);
78 }
79 }
80
81 write_txn
82 .internal_apply_domain_migration(domain_target_level)
83 .map(|()| {
84 warn!(
85 "Domain level has been bootstrapped to {}",
86 domain_target_level
87 );
88 })?;
89 }
90
91 write_txn.force_domain_reload();
103
104 write_txn.reload()?;
105
106 assert!(write_txn.get_domain_version() > DOMAIN_LEVEL_0);
107
108 write_txn.set_phase(ServerPhase::SchemaReady);
111
112 write_txn.force_schema_reload();
121
122 write_txn.reload()?;
124
125 write_txn.set_phase(ServerPhase::DomainInfoReady);
127
128 let domain_info_version = write_txn.get_domain_version();
135 let domain_patch_level = write_txn.get_domain_patch_level();
136 let domain_development_taint = write_txn.get_domain_development_taint();
137 debug!(
138 ?db_domain_version,
139 ?domain_patch_level,
140 ?domain_development_taint,
141 "After setting internal domain info"
142 );
143
144 let mut reload_required = false;
145
146 if domain_info_version < domain_target_level {
148 if domain_info_version < DOMAIN_MIGRATION_FROM_MIN {
150 error!(
151 "UNABLE TO PROCEED. You are attempting a skip update which is NOT SUPPORTED."
152 );
153 error!(
154 "For more see: https://kanidm.github.io/kanidm/stable/support.html#upgrade-policy and https://kanidm.github.io/kanidm/stable/server_updates.html"
155 );
156 error!(domain_previous_version = ?domain_info_version, domain_target_version = ?domain_target_level, domain_migration_minimum_limit = ?DOMAIN_MIGRATION_FROM_MIN);
157 return Err(OperationError::MG0008SkipUpgradeAttempted);
158 }
159
160 for domain_target_level_step in domain_info_version..domain_target_level {
162 let domain_target_level_step = domain_target_level_step + 1;
166
167 write_txn
170 .internal_apply_domain_migration(domain_target_level_step)
171 .map(|()| {
172 warn!(
173 "Domain level has been raised to {}",
174 domain_target_level_step
175 );
176 })?;
177 }
178 } else if domain_info_version > domain_target_level {
179 error!("UNABLE TO PROCEED. You are attempting a downgrade which is NOT SUPPORTED.");
181 error!(
182 "For more see: https://kanidm.github.io/kanidm/stable/support.html#upgrade-policy and https://kanidm.github.io/kanidm/stable/server_updates.html"
183 );
184 error!(domain_previous_version = ?domain_info_version, domain_target_version = ?domain_target_level);
185 return Err(OperationError::MG0010DowngradeNotAllowed);
186 } else if domain_development_taint {
187 write_txn.domain_remigrate(DOMAIN_PREVIOUS_TGT_LEVEL)?;
198
199 reload_required = true;
200 }
201
202 if domain_patch_level < DOMAIN_TGT_PATCH_LEVEL {
205 write_txn
206 .internal_modify_uuid(
207 UUID_DOMAIN_INFO,
208 &ModifyList::new_purge_and_set(
209 Attribute::PatchLevel,
210 Value::new_uint32(DOMAIN_TGT_PATCH_LEVEL),
211 ),
212 )
213 .map(|()| {
214 warn!(
215 "Domain patch level has been raised to {}",
216 domain_patch_level
217 );
218 })?;
219
220 reload_required = true;
221 };
222
223 if reload_required {
227 write_txn.reload()?;
228 }
229
230 let current_devel_flag = option_env!("KANIDM_PRE_RELEASE").is_some();
233 if current_devel_flag {
234 warn!("Domain Development Taint mode is enabled");
235 }
236 if domain_development_taint != current_devel_flag {
237 write_txn.internal_modify_uuid(
238 UUID_DOMAIN_INFO,
239 &ModifyList::new_purge_and_set(
240 Attribute::DomainDevelopmentTaint,
241 Value::Bool(current_devel_flag),
242 ),
243 )?;
244 }
245
246 write_txn.set_phase(ServerPhase::Running);
248
249 write_txn.commit()?;
252
253 debug!("Database version check and migrations success! ☀️ ");
254 Ok(())
255 }
256}
257
258impl QueryServerWriteTransaction<'_> {
259 #[instrument(level = "debug", skip(self))]
262 pub(crate) fn internal_apply_domain_migration(
263 &mut self,
264 to_level: u32,
265 ) -> Result<(), OperationError> {
266 self.internal_modify_uuid(
267 UUID_DOMAIN_INFO,
268 &ModifyList::new_purge_and_set(Attribute::Version, Value::new_uint32(to_level)),
269 )
270 .and_then(|()| self.reload())
271 }
272
273 fn internal_migrate_or_create_batch(
274 &mut self,
275 msg: &str,
276 entries: Vec<EntryInitNew>,
277 ) -> Result<(), OperationError> {
278 let r: Result<(), _> = entries
279 .into_iter()
280 .try_for_each(|entry| self.internal_migrate_or_create(entry));
281
282 if let Err(err) = r {
283 error!(?err, msg);
284 debug_assert!(false);
285 }
286
287 Ok(())
288 }
289
290 #[instrument(level = "debug", skip_all)]
291 fn internal_migrate_or_create(
301 &mut self,
302 e: Entry<EntryInit, EntryNew>,
303 ) -> Result<(), OperationError> {
304 self.internal_migrate_or_create_ignore_attrs(
306 e,
307 &[
308 Attribute::CredentialTypeMinimum,
310 ],
311 )
312 }
313
314 #[instrument(level = "debug", skip_all)]
315 fn internal_delete_batch(
316 &mut self,
317 msg: &str,
318 entries: Vec<Uuid>,
319 ) -> Result<(), OperationError> {
320 let filter = entries
321 .into_iter()
322 .map(|uuid| f_eq(Attribute::Uuid, PartialValue::Uuid(uuid)))
323 .collect();
324
325 let filter = filter!(f_or(filter));
327
328 let result = self.internal_delete(&filter);
329
330 match result {
331 Ok(_) | Err(OperationError::NoMatchingEntries) => Ok(()),
332 Err(err) => {
333 error!(?err, msg);
334 Err(err)
335 }
336 }
337 }
338
339 #[instrument(level = "trace", skip_all)]
343 fn internal_migrate_or_create_ignore_attrs(
344 &mut self,
345 mut e: Entry<EntryInit, EntryNew>,
346 attrs: &[Attribute],
347 ) -> Result<(), OperationError> {
348 trace!("operating on {:?}", e.get_uuid());
349
350 let Some(filt) = e.filter_from_attrs(&[Attribute::Uuid]) else {
351 return Err(OperationError::FilterGeneration);
352 };
353
354 trace!("search {:?}", filt);
355
356 let results = self.internal_search(filt.clone())?;
357
358 if results.is_empty() {
359 if let Some(members_create_once) = e.pop_ava(Attribute::MemberCreateOnce) {
363 if let Some(members) = e.get_ava_mut(Attribute::Member) {
364 members.merge(&members_create_once).inspect_err(|err| {
366 error!(?err, "Unable to merge member sets, mismatched types?");
367 })?;
368 } else {
369 e.set_ava_set(&Attribute::Member, members_create_once);
371 }
372 };
373
374 self.internal_create(vec![e])
375 } else if results.len() == 1 {
376 e.remove_ava(&Attribute::MemberCreateOnce);
378
379 for attr in attrs.iter() {
381 e.remove_ava(attr);
382 }
383
384 match e.gen_modlist_assert(&self.schema) {
386 Ok(modlist) => {
387 trace!(?modlist);
389 self.internal_modify(&filt, &modlist)
390 }
391 Err(e) => Err(OperationError::SchemaViolation(e)),
392 }
393 } else {
394 admin_error!(
395 "Invalid Result Set - Expected One Entry for {:?} - {:?}",
396 filt,
397 results
398 );
399 Err(OperationError::InvalidDbState)
400 }
401 }
402
403 #[instrument(level = "info", skip_all)]
432 pub(crate) fn migrate_domain_10_to_11(&mut self) -> Result<(), OperationError> {
433 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_10 {
434 error!("Unable to raise domain level from 10 to 11.");
435 return Err(OperationError::MG0004DomainLevelInDevelopment);
436 }
437
438 self.internal_migrate_or_create_batch(
440 "phase 1 - schema attrs",
441 migration_data::dl11::phase_1_schema_attrs(),
442 )?;
443
444 self.internal_migrate_or_create_batch(
445 "phase 2 - schema classes",
446 migration_data::dl11::phase_2_schema_classes(),
447 )?;
448
449 self.reload()?;
451
452 self.reindex(false)?;
455
456 self.set_phase(ServerPhase::SchemaReady);
460
461 self.internal_migrate_or_create_batch(
462 "phase 3 - key provider",
463 migration_data::dl11::phase_3_key_provider(),
464 )?;
465
466 self.reload()?;
468
469 self.internal_migrate_or_create_batch(
470 "phase 4 - system entries",
471 migration_data::dl11::phase_4_system_entries(),
472 )?;
473
474 self.reload()?;
476
477 self.set_phase(ServerPhase::DomainInfoReady);
479
480 self.internal_migrate_or_create_batch(
482 "phase 5 - builtin admin entries",
483 migration_data::dl11::phase_5_builtin_admin_entries()?,
484 )?;
485
486 self.internal_migrate_or_create_batch(
487 "phase 6 - builtin not admin entries",
488 migration_data::dl11::phase_6_builtin_non_admin_entries()?,
489 )?;
490
491 self.internal_migrate_or_create_batch(
492 "phase 7 - builtin access control profiles",
493 migration_data::dl11::phase_7_builtin_access_control_profiles(),
494 )?;
495
496 self.reload()?;
497
498 Ok(())
499 }
500
501 #[instrument(level = "info", skip_all)]
503 pub(crate) fn migrate_domain_11_to_12(&mut self) -> Result<(), OperationError> {
504 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_11 {
505 error!("Unable to raise domain level from 11 to 12.");
506 return Err(OperationError::MG0004DomainLevelInDevelopment);
507 }
508
509 self.internal_migrate_or_create_batch(
511 "phase 1 - schema attrs",
512 migration_data::dl12::phase_1_schema_attrs(),
513 )?;
514
515 self.internal_migrate_or_create_batch(
516 "phase 2 - schema classes",
517 migration_data::dl12::phase_2_schema_classes(),
518 )?;
519
520 self.reload()?;
522
523 self.reindex(false)?;
526
527 self.set_phase(ServerPhase::SchemaReady);
531
532 self.internal_migrate_or_create_batch(
533 "phase 3 - key provider",
534 migration_data::dl12::phase_3_key_provider(),
535 )?;
536
537 self.reload()?;
539
540 self.internal_migrate_or_create_batch(
541 "phase 4 - system entries",
542 migration_data::dl12::phase_4_system_entries(),
543 )?;
544
545 self.reload()?;
547
548 self.set_phase(ServerPhase::DomainInfoReady);
550
551 self.internal_migrate_or_create_batch(
553 "phase 5 - builtin admin entries",
554 migration_data::dl12::phase_5_builtin_admin_entries()?,
555 )?;
556
557 self.internal_migrate_or_create_batch(
558 "phase 6 - builtin not admin entries",
559 migration_data::dl12::phase_6_builtin_non_admin_entries()?,
560 )?;
561
562 self.internal_migrate_or_create_batch(
563 "phase 7 - builtin access control profiles",
564 migration_data::dl12::phase_7_builtin_access_control_profiles(),
565 )?;
566
567 self.reload()?;
568
569 let modlist = ModifyList::new_purge(Attribute::IdVerificationEcKey);
571 let filter = filter_all!(f_pres(Attribute::IdVerificationEcKey));
572
573 self.internal_modify(&filter, &modlist)?;
574
575 Ok(())
576 }
577
578 #[instrument(level = "info", skip_all)]
580 pub(crate) fn migrate_domain_12_to_13(&mut self) -> Result<(), OperationError> {
581 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_12 {
582 error!("Unable to raise domain level from 12 to 13.");
583 return Err(OperationError::MG0004DomainLevelInDevelopment);
584 }
585
586 self.internal_migrate_or_create_batch(
588 "phase 1 - schema attrs",
589 migration_data::dl13::phase_1_schema_attrs(),
590 )?;
591
592 self.internal_migrate_or_create_batch(
593 "phase 2 - schema classes",
594 migration_data::dl13::phase_2_schema_classes(),
595 )?;
596
597 self.reload()?;
599
600 self.reindex(false)?;
603
604 self.set_phase(ServerPhase::SchemaReady);
608
609 self.internal_migrate_or_create_batch(
610 "phase 3 - key provider",
611 migration_data::dl13::phase_3_key_provider(),
612 )?;
613
614 self.reload()?;
616
617 self.internal_migrate_or_create_batch(
618 "phase 4 - system entries",
619 migration_data::dl13::phase_4_system_entries(),
620 )?;
621
622 self.reload()?;
624
625 self.set_phase(ServerPhase::DomainInfoReady);
627
628 self.internal_migrate_or_create_batch(
630 "phase 5 - builtin admin entries",
631 migration_data::dl13::phase_5_builtin_admin_entries()?,
632 )?;
633
634 self.internal_migrate_or_create_batch(
635 "phase 6 - builtin not admin entries",
636 migration_data::dl13::phase_6_builtin_non_admin_entries()?,
637 )?;
638
639 self.internal_migrate_or_create_batch(
640 "phase 7 - builtin access control profiles",
641 migration_data::dl13::phase_7_builtin_access_control_profiles(),
642 )?;
643
644 self.internal_delete_batch(
645 "phase 8 - delete UUIDS",
646 migration_data::dl13::phase_8_delete_uuids(),
647 )?;
648
649 self.reload()?;
650
651 Ok(())
652 }
653
654 #[instrument(level = "info", skip_all)]
656 pub(crate) fn migrate_domain_13_to_14(&mut self) -> Result<(), OperationError> {
657 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_13 {
658 error!("Unable to raise domain level from 13 to 14.");
659 return Err(OperationError::MG0004DomainLevelInDevelopment);
660 }
661
662 self.internal_migrate_or_create_batch(
664 &format!("phase 1 - schema attrs target {}", DOMAIN_TGT_LEVEL),
665 migration_data::dl14::phase_1_schema_attrs(),
666 )?;
667
668 self.internal_migrate_or_create_batch(
669 "phase 2 - schema classes",
670 migration_data::dl14::phase_2_schema_classes(),
671 )?;
672
673 self.reload()?;
675
676 self.reindex(false)?;
679
680 self.set_phase(ServerPhase::SchemaReady);
684
685 self.internal_migrate_or_create_batch(
686 "phase 3 - key provider",
687 migration_data::dl14::phase_3_key_provider(),
688 )?;
689
690 self.reload()?;
692
693 self.internal_migrate_or_create_batch(
694 "phase 4 - dl14 system entries",
695 migration_data::dl14::phase_4_system_entries(),
696 )?;
697
698 self.reload()?;
700
701 self.set_phase(ServerPhase::DomainInfoReady);
703
704 self.internal_migrate_or_create_batch(
706 "phase 5 - builtin admin entries",
707 migration_data::dl14::phase_5_builtin_admin_entries()?,
708 )?;
709
710 self.internal_migrate_or_create_batch(
711 "phase 6 - builtin not admin entries",
712 migration_data::dl14::phase_6_builtin_non_admin_entries()?,
713 )?;
714
715 self.internal_migrate_or_create_batch(
716 "phase 7 - builtin access control profiles",
717 migration_data::dl14::phase_7_builtin_access_control_profiles(),
718 )?;
719
720 self.internal_delete_batch(
721 "phase 8 - delete UUIDS",
722 migration_data::dl14::phase_8_delete_uuids(),
723 )?;
724
725 self.reload()?;
726
727 let filter = filter_all!(f_and!([
729 f_eq(Attribute::Class, EntryClass::Person.into()),
730 f_andnot(f_pres(Attribute::PasswordChangedTime)),
731 ]));
732 let modlist = ModifyList::new_purge_and_set(
733 Attribute::PasswordChangedTime,
734 Value::DateTime(time::OffsetDateTime::UNIX_EPOCH),
735 );
736 self.internal_modify(&filter, &modlist)?;
737
738 Ok(())
739 }
740
741 pub(crate) fn migrate_schema_1_11(&mut self) -> Result<(), OperationError> {
742 self.schema.extend_in_memory(
743 migration_data::dl15::phase_1_schema_attrs(),
744 migration_data::dl15::phase_2_schema_classes(),
745 )
746 }
747
748 #[instrument(level = "info", skip_all)]
750 pub(crate) fn migrate_domain_1_10_to_1_11(&mut self) -> Result<(), OperationError> {
751 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_14 {
752 error!(
753 "Unable to raise domain level from {} to {}.",
754 DOMAIN_LEVEL_14, DOMAIN_LEVEL_1_11
755 );
756 return Err(OperationError::MG0004DomainLevelInDevelopment);
757 }
758
759 self.migrate_schema_1_11()?;
761
762 self.reload()?;
764
765 self.reindex(false)?;
768
769 let filter = filter!(f_and(vec![
772 f_eq(Attribute::Class, EntryClass::ClassType.into()),
773 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
774 ]));
775
776 self.internal_delete_if_exists(&filter)?;
777
778 self.set_phase(ServerPhase::SchemaReady);
782
783 self.internal_migrate_or_create_batch(
784 "phase 3 - key provider",
785 migration_data::dl15::phase_3_key_provider(),
786 )?;
787
788 self.reload()?;
790
791 self.internal_migrate_or_create_batch(
792 "phase 4 - dl15 system entries",
793 migration_data::dl15::phase_4_system_entries(),
794 )?;
795
796 self.reload()?;
798
799 self.set_phase(ServerPhase::DomainInfoReady);
801
802 self.internal_migrate_or_create_batch(
804 "phase 5 - builtin admin entries",
805 migration_data::dl15::phase_5_builtin_admin_entries()?,
806 )?;
807
808 self.internal_migrate_or_create_batch(
809 "phase 6 - builtin not admin entries",
810 migration_data::dl15::phase_6_builtin_non_admin_entries()?,
811 )?;
812
813 self.internal_migrate_or_create_batch(
814 "phase 7 - builtin access control profiles",
815 migration_data::dl15::phase_7_builtin_access_control_profiles(),
816 )?;
817
818 self.internal_delete_batch(
819 "phase 8 - delete UUIDS",
820 migration_data::dl15::phase_8_delete_uuids(),
821 )?;
822
823 self.reload()?;
824
825 let filter = filter_all!(f_and!([
827 f_eq(Attribute::Class, EntryClass::Person.into()),
828 f_andnot(f_pres(Attribute::PasswordChangedTime)),
829 ]));
830 let modlist = ModifyList::new_purge_and_set(
831 Attribute::PasswordChangedTime,
832 Value::DateTime(time::OffsetDateTime::UNIX_EPOCH),
833 );
834 self.internal_modify(&filter, &modlist)?;
835
836 Ok(())
837 }
838
839 pub(crate) fn migrate_schema_1_12(&mut self) -> Result<(), OperationError> {
840 self.schema.extend_in_memory(
841 migration_data::dl_1_12::phase_1_schema_attrs(),
842 migration_data::dl_1_12::phase_2_schema_classes(),
843 )
844 }
845
846 #[instrument(level = "info", skip_all)]
848 pub(crate) fn migrate_domain_1_11_to_1_12(&mut self) -> Result<(), OperationError> {
849 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_1_12 {
850 error!("Unable to raise domain level from 1_11 to 1_12.");
851 return Err(OperationError::MG0004DomainLevelInDevelopment);
852 }
853
854 use migration_data::dl_1_12 as dl_target;
855
856 self.migrate_schema_1_12()?;
858
859 self.reload()?;
861
862 self.reindex(false)?;
865
866 let filter = filter!(f_and(vec![
869 f_eq(Attribute::Class, EntryClass::ClassType.into()),
870 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
871 ]));
872
873 self.internal_delete_if_exists(&filter)?;
874
875 self.set_phase(ServerPhase::SchemaReady);
879
880 self.internal_migrate_or_create_batch(
881 "phase 3 - key provider",
882 dl_target::phase_3_key_provider(),
883 )?;
884
885 self.reload()?;
887
888 self.internal_migrate_or_create_batch(
889 "phase 4 - system entries",
890 dl_target::phase_4_system_entries(),
891 )?;
892
893 self.reload()?;
895
896 self.set_phase(ServerPhase::DomainInfoReady);
898
899 self.internal_migrate_or_create_batch(
901 "phase 5 - builtin admin entries",
902 dl_target::phase_5_builtin_admin_entries()?,
903 )?;
904
905 self.internal_migrate_or_create_batch(
906 "phase 6 - builtin not admin entries",
907 dl_target::phase_6_builtin_non_admin_entries()?,
908 )?;
909
910 self.internal_migrate_or_create_batch(
911 "phase 7 - builtin access control profiles",
912 dl_target::phase_7_builtin_access_control_profiles(),
913 )?;
914
915 self.internal_delete_batch("phase 8 - delete UUIDS", dl_target::phase_8_delete_uuids())?;
916
917 self.reload()?;
918
919 Ok(())
920 }
921
922 #[instrument(level = "info", skip_all)]
924 pub(crate) fn migrate_domain_1_12_to_1_13(&mut self) -> Result<(), OperationError> {
925 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_1_13 {
926 error!("Unable to raise domain level from 1_12 to 1_13.");
927 return Err(OperationError::MG0004DomainLevelInDevelopment);
928 }
929
930 Ok(())
931 }
932
933 #[instrument(level = "info", skip_all)]
934 pub(crate) fn initialise_schema_core(&mut self) -> Result<(), OperationError> {
935 debug!("initialise_schema_core -> start ...");
936 let entries = self.schema.to_entries();
938
939 let r: Result<_, _> = entries.into_iter().try_for_each(|e| {
943 trace!(?e, "init schema entry");
944 self.internal_migrate_or_create(e)
945 });
946 if r.is_ok() {
947 debug!("initialise_schema_core -> Ok!");
948 } else {
949 error!(?r, "initialise_schema_core -> Error");
950 }
951 debug_assert!(r.is_ok());
953 r
954 }
955}
956
957impl QueryServerReadTransaction<'_> {
958 pub fn domain_upgrade_check(
960 &mut self,
961 ) -> Result<ProtoDomainUpgradeCheckReport, OperationError> {
962 let d_info = &self.d_info;
963
964 let name = d_info.d_name.clone();
965 let uuid = d_info.d_uuid;
966 let current_level = d_info.d_vers;
967 let upgrade_level = DOMAIN_TGT_NEXT_LEVEL;
968
969 let report_items = Vec::with_capacity(1);
970
971 Ok(ProtoDomainUpgradeCheckReport {
988 name,
989 uuid,
990 current_level,
991 upgrade_level,
992 report_items,
993 })
994 }
995
996 }
1028
1029#[cfg(test)]
1030mod tests {
1031 use crate::prelude::*;
1033 use crate::value::CredentialType;
1034 use crate::valueset::ValueSetCredentialType;
1035
1036 #[qs_test]
1037 async fn test_init_idempotent_schema_core(server: &QueryServer) {
1038 {
1039 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1041 assert!(server_txn.initialise_schema_core().is_ok());
1042 }
1043 {
1044 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1045 assert!(server_txn.initialise_schema_core().is_ok());
1046 assert!(server_txn.initialise_schema_core().is_ok());
1047 assert!(server_txn.commit().is_ok());
1048 }
1049 {
1050 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1052 assert!(server_txn.initialise_schema_core().is_ok());
1053 }
1054 {
1055 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1057 assert!(server_txn.initialise_schema_core().is_ok());
1058 assert!(server_txn.commit().is_ok());
1059 }
1060 }
1061
1062 #[qs_test(domain_level=DOMAIN_PREVIOUS_TGT_LEVEL)]
1066 async fn test_migrations_dl_previous_to_dl_target(server: &QueryServer) {
1067 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1068
1069 let db_domain_version = write_txn
1070 .internal_search_uuid(UUID_DOMAIN_INFO)
1071 .expect("unable to access domain entry")
1072 .get_ava_single_uint32(Attribute::Version)
1073 .expect("Attribute Version not present");
1074
1075 assert_eq!(db_domain_version, DOMAIN_PREVIOUS_TGT_LEVEL);
1076
1077 let modlist = ModifyList::new_set(
1082 Attribute::Member,
1083 ValueSetRefer::new(UUID_ANONYMOUS),
1086 );
1087 write_txn
1088 .internal_modify_uuid(UUID_IDM_ADMINS, &modlist)
1089 .expect("Unable to modify CredentialTypeMinimum");
1090
1091 let modlist = ModifyList::new_purge(Attribute::Member);
1094 write_txn
1095 .internal_modify_uuid(UUID_IDM_PEOPLE_SELF_NAME_WRITE, &modlist)
1096 .expect("Unable to remove idm_all_persons from self-write");
1097
1098 let modlist = ModifyList::new_set(
1100 Attribute::CredentialTypeMinimum,
1101 ValueSetCredentialType::new(CredentialType::Any),
1102 );
1103 write_txn
1104 .internal_modify_uuid(UUID_IDM_ALL_PERSONS, &modlist)
1105 .expect("Unable to modify CredentialTypeMinimum");
1106
1107 write_txn.commit().expect("Unable to commit");
1108
1109 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1110
1111 write_txn
1113 .internal_apply_domain_migration(DOMAIN_TGT_LEVEL)
1114 .expect("Unable to set domain level");
1115
1116 let idm_admins_entry = write_txn
1119 .internal_search_uuid(UUID_IDM_ADMINS)
1120 .expect("Unable to retrieve all persons");
1121
1122 let members = idm_admins_entry
1123 .get_ava_refer(Attribute::Member)
1124 .expect("No members present");
1125
1126 assert!(members.contains(&UUID_ANONYMOUS));
1128 assert!(members.contains(&UUID_IDM_ADMIN));
1130
1131 let idm_people_self_name_write_entry = write_txn
1133 .internal_search_uuid(UUID_IDM_PEOPLE_SELF_NAME_WRITE)
1134 .expect("Unable to retrieve all persons");
1135
1136 let members = idm_people_self_name_write_entry.get_ava_refer(Attribute::Member);
1137
1138 assert!(members.is_none());
1140
1141 let all_persons_entry = write_txn
1143 .internal_search_uuid(UUID_IDM_ALL_PERSONS)
1144 .expect("Unable to retrieve all persons");
1145
1146 assert_eq!(
1147 all_persons_entry.get_ava_single_credential_type(Attribute::CredentialTypeMinimum),
1148 Some(CredentialType::Any)
1149 );
1150
1151 write_txn.commit().expect("Unable to commit");
1152 }
1153
1154 #[qs_test(domain_level=DOMAIN_TGT_LEVEL)]
1155 async fn test_migrations_prevent_downgrades(server: &QueryServer) {
1156 let curtime = duration_from_epoch_now();
1157
1158 let mut write_txn = server.write(curtime).await.unwrap();
1159
1160 let db_domain_version = write_txn
1161 .internal_search_uuid(UUID_DOMAIN_INFO)
1162 .expect("unable to access domain entry")
1163 .get_ava_single_uint32(Attribute::Version)
1164 .expect("Attribute Version not present");
1165
1166 assert_eq!(db_domain_version, DOMAIN_TGT_LEVEL);
1167
1168 drop(write_txn);
1169
1170 let err = server
1172 .initialise_helper(curtime, DOMAIN_PREVIOUS_TGT_LEVEL)
1173 .await
1174 .expect_err("Domain level was lowered!!!!");
1175
1176 assert_eq!(err, OperationError::MG0010DowngradeNotAllowed);
1177 }
1178
1179 #[qs_test(domain_level=DOMAIN_MIGRATION_FROM_INVALID)]
1180 async fn test_migrations_prevent_skips(server: &QueryServer) {
1181 let curtime = duration_from_epoch_now();
1182
1183 let mut write_txn = server.write(curtime).await.unwrap();
1184
1185 let db_domain_version = write_txn
1186 .internal_search_uuid(UUID_DOMAIN_INFO)
1187 .expect("unable to access domain entry")
1188 .get_ava_single_uint32(Attribute::Version)
1189 .expect("Attribute Version not present");
1190
1191 assert_eq!(db_domain_version, DOMAIN_MIGRATION_FROM_INVALID);
1192
1193 drop(write_txn);
1194
1195 let err = server
1197 .initialise_helper(curtime, DOMAIN_TGT_LEVEL)
1198 .await
1199 .expect_err("Migration went ahead!!!!");
1200
1201 assert_eq!(err, OperationError::MG0008SkipUpgradeAttempted);
1202 }
1203
1204 #[qs_test(domain_level=DOMAIN_MIGRATION_FROM_MIN)]
1205 async fn test_migrations_skip_valid(server: &QueryServer) {
1206 let curtime = duration_from_epoch_now();
1207 let mut write_txn = server.write(curtime).await.unwrap();
1210
1211 let db_domain_version = write_txn
1212 .internal_search_uuid(UUID_DOMAIN_INFO)
1213 .expect("unable to access domain entry")
1214 .get_ava_single_uint32(Attribute::Version)
1215 .expect("Attribute Version not present");
1216
1217 assert_eq!(db_domain_version, DOMAIN_MIGRATION_FROM_MIN);
1218
1219 drop(write_txn);
1220
1221 server
1223 .initialise_helper(curtime, DOMAIN_TGT_LEVEL)
1224 .await
1225 .expect("Migration failed!!!!")
1226 }
1227
1228 #[qs_test(domain_level=DOMAIN_LEVEL_11)]
1229 async fn test_migrations_dl11_dl12(server: &QueryServer) {
1230 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1231
1232 let db_domain_version = write_txn
1233 .internal_search_uuid(UUID_DOMAIN_INFO)
1234 .expect("unable to access domain entry")
1235 .get_ava_single_uint32(Attribute::Version)
1236 .expect("Attribute Version not present");
1237
1238 assert_eq!(db_domain_version, DOMAIN_LEVEL_11);
1239
1240 let tuuid = Uuid::new_v4();
1242 let e1 = entry_init!(
1243 (Attribute::Class, EntryClass::Object.to_value()),
1244 (Attribute::Class, EntryClass::Person.to_value()),
1245 (Attribute::Class, EntryClass::Account.to_value()),
1246 (Attribute::Name, Value::new_iname("testperson1")),
1247 (Attribute::Uuid, Value::Uuid(tuuid)),
1248 (Attribute::Description, Value::new_utf8s("testperson1")),
1249 (Attribute::DisplayName, Value::new_utf8s("testperson1"))
1250 );
1251
1252 write_txn
1253 .internal_create(vec![e1])
1254 .expect("Unable to create user");
1255
1256 let user = write_txn
1257 .internal_search_uuid(tuuid)
1258 .expect("Unable to load user");
1259
1260 assert!(user.get_ava_set(Attribute::IdVerificationEcKey).is_some());
1262
1263 write_txn.commit().expect("Unable to commit");
1264
1265 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1272
1273 write_txn
1277 .internal_apply_domain_migration(DOMAIN_LEVEL_12)
1278 .expect("Unable to set domain level to version 12");
1279
1280 let user = write_txn
1282 .internal_search_uuid(tuuid)
1283 .expect("Unable to load user");
1284
1285 assert!(user.get_ava_set(Attribute::IdVerificationEcKey).is_none());
1287
1288 let t2uuid = Uuid::new_v4();
1290 let e2 = entry_init!(
1291 (Attribute::Class, EntryClass::Object.to_value()),
1292 (Attribute::Class, EntryClass::Person.to_value()),
1293 (Attribute::Class, EntryClass::Account.to_value()),
1294 (Attribute::Name, Value::new_iname("testperson2")),
1295 (Attribute::Uuid, Value::Uuid(t2uuid)),
1296 (Attribute::Description, Value::new_utf8s("testperson2")),
1297 (Attribute::DisplayName, Value::new_utf8s("testperson2"))
1298 );
1299
1300 write_txn
1301 .internal_create(vec![e2])
1302 .expect("Unable to create user");
1303
1304 let user = write_txn
1305 .internal_search_uuid(t2uuid)
1306 .expect("Unable to load user");
1307
1308 assert!(user.get_ava_set(Attribute::IdVerificationEcKey).is_none());
1310
1311 write_txn.commit().expect("Unable to commit");
1312 }
1313
1314 #[qs_test(domain_level=DOMAIN_LEVEL_12)]
1315 async fn test_migrations_dl12_dl13(server: &QueryServer) {
1316 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1317
1318 let db_domain_version = write_txn
1319 .internal_search_uuid(UUID_DOMAIN_INFO)
1320 .expect("unable to access domain entry")
1321 .get_ava_single_uint32(Attribute::Version)
1322 .expect("Attribute Version not present");
1323
1324 assert_eq!(db_domain_version, DOMAIN_LEVEL_12);
1325
1326 write_txn.commit().expect("Unable to commit");
1327
1328 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1335
1336 write_txn
1340 .internal_apply_domain_migration(DOMAIN_LEVEL_13)
1341 .expect("Unable to set domain level to version 13");
1342
1343 write_txn.commit().expect("Unable to commit");
1346 }
1347
1348 #[qs_test(domain_level=DOMAIN_LEVEL_13)]
1349 async fn test_migrations_dl13_dl14(server: &QueryServer) {
1350 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1351
1352 let db_domain_version = write_txn
1353 .internal_search_uuid(UUID_DOMAIN_INFO)
1354 .expect("unable to access domain entry")
1355 .get_ava_single_uint32(Attribute::Version)
1356 .expect("Attribute Version not present");
1357
1358 assert_eq!(db_domain_version, DOMAIN_LEVEL_13);
1359
1360 let tuuid = Uuid::new_v4();
1362 let e1 = entry_init!(
1363 (Attribute::Class, EntryClass::Object.to_value()),
1364 (Attribute::Class, EntryClass::Person.to_value()),
1365 (Attribute::Class, EntryClass::Account.to_value()),
1366 (Attribute::Name, Value::new_iname("testperson1")),
1367 (Attribute::Uuid, Value::Uuid(tuuid)),
1368 (Attribute::Description, Value::new_utf8s("testperson1")),
1369 (Attribute::DisplayName, Value::new_utf8s("testperson1"))
1370 );
1371
1372 write_txn
1373 .internal_create(vec![e1])
1374 .expect("Unable to create test person");
1375
1376 let user = write_txn
1377 .internal_search_uuid(tuuid)
1378 .expect("Unable to load test person");
1379
1380 assert!(user
1382 .get_ava_single_datetime(Attribute::PasswordChangedTime)
1383 .is_none());
1384
1385 write_txn.commit().expect("Unable to commit");
1386
1387 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1394
1395 write_txn
1399 .internal_apply_domain_migration(DOMAIN_LEVEL_14)
1400 .expect("Unable to set domain level to version 14");
1401
1402 let user = write_txn
1405 .internal_search_uuid(tuuid)
1406 .expect("Unable to load test person after migration");
1407
1408 let pwd_changed = user
1409 .get_ava_single_datetime(Attribute::PasswordChangedTime)
1410 .expect("PasswordChangedTime should be set after DL13->DL14 migration");
1411
1412 assert_eq!(pwd_changed, time::OffsetDateTime::UNIX_EPOCH);
1413
1414 write_txn.commit().expect("Unable to commit");
1415 }
1416
1417 #[qs_test(domain_level=DOMAIN_LEVEL_14)]
1418 async fn test_migrations_dl14_dl1_11(server: &QueryServer) {
1419 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1420
1421 let db_domain_version = write_txn
1422 .internal_search_uuid(UUID_DOMAIN_INFO)
1423 .expect("unable to access domain entry")
1424 .get_ava_single_uint32(Attribute::Version)
1425 .expect("Attribute Version not present");
1426
1427 assert_eq!(db_domain_version, DOMAIN_LEVEL_14);
1428
1429 write_txn.commit().expect("Unable to commit");
1430
1431 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1438
1439 write_txn
1443 .internal_apply_domain_migration(DOMAIN_LEVEL_1_11)
1444 .expect("Unable to set domain level to version 1_11");
1445
1446 let filter = filter!(f_and(vec![
1451 f_eq(Attribute::Class, EntryClass::ClassType.into()),
1452 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
1453 ]));
1454
1455 let entries_remain = write_txn.internal_exists(&filter).unwrap();
1456 assert!(!entries_remain);
1457
1458 write_txn.commit().expect("Unable to commit");
1459 }
1460
1461 #[qs_test(domain_level=DOMAIN_LEVEL_1_11)]
1462 async fn test_migrations_dl1_11_to_dl_1_12(server: &QueryServer) {
1463 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1464
1465 let db_domain_version = write_txn
1466 .internal_search_uuid(UUID_DOMAIN_INFO)
1467 .expect("unable to access domain entry")
1468 .get_ava_single_uint32(Attribute::Version)
1469 .expect("Attribute Version not present");
1470
1471 assert_eq!(db_domain_version, DOMAIN_LEVEL_1_11);
1472
1473 write_txn.commit().expect("Unable to commit");
1474
1475 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1482
1483 write_txn
1487 .internal_apply_domain_migration(DOMAIN_LEVEL_1_12)
1488 .expect("Unable to set domain level to version 1_12");
1489
1490 write_txn.commit().expect("Unable to commit");
1493 }
1494}