From 737abdce09e6691b9ce69c082a867180e76cab60 Mon Sep 17 00:00:00 2001 From: "David R. Morrison" Date: Thu, 19 Dec 2024 11:04:16 -0800 Subject: [PATCH] feat: InsertAt patch location + secondary patch for service_account_missing --- Cargo.lock | 4 +- Cargo.toml | 2 +- sk-cli/src/validation/annotated_trace.rs | 95 +++++++++++++++---- .../rules/service_account_missing.rs | 79 +++++++++++---- sk-cli/src/validation/rules/tests/mod.rs | 2 +- .../tests/service_account_missing_test.rs | 16 ++-- .../validation/tests/annotated_trace_test.rs | 55 +++++++++++ sk-cli/src/validation/tests/mod.rs | 2 +- ..._view_test__itest_render_event_list@0.snap | 4 +- ..._view_test__itest_render_event_list@3.snap | 4 +- ...st_render_event_list_event_selected@0.snap | 4 +- ...st_render_event_list_event_selected@2.snap | 2 +- ...st_render_event_list_event_selected@3.snap | 4 +- sk-core/Cargo.toml | 4 +- sk-core/src/constants.rs | 17 +++- sk-core/src/k8s/testutils/objs.rs | 2 +- sk-store/src/lib.rs | 4 +- 17 files changed, 237 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 517cbb70..256a93e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,9 +139,9 @@ dependencies = [ [[package]] name = "assertables" -version = "8.18.0" +version = "9.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "857057651cdf1fe4bc1e8308493c752db559df0330f23b45f532f6b24c2b443d" +checksum = "0082388b8564898f945b04215e800e800a164af15307d8dfe714b02cc69356e9" [[package]] name = "async-broadcast" diff --git a/Cargo.toml b/Cargo.toml index 2bf0b398..05a81586 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } url = "2.5.3" # test dependencies -assertables = "8.18.0" +assertables = "9.5.0" http = "1.1.0" httpmock = "0.6.8" hyper = "1.5.0" diff --git a/sk-cli/src/validation/annotated_trace.rs b/sk-cli/src/validation/annotated_trace.rs index e071427e..1f8c4bac 100644 --- a/sk-cli/src/validation/annotated_trace.rs +++ b/sk-cli/src/validation/annotated_trace.rs @@ -1,13 +1,16 @@ use std::collections::BTreeMap; // BTreeMap sorts by key, HashMap doesn't +use std::iter::once; use std::slice; use json_patch_ext::prelude::*; +use serde_json::json; use sk_core::external_storage::{ ObjectStoreWrapper, SkObjectStore, }; use sk_core::prelude::*; use sk_store::{ + TraceAction, TraceEvent, TraceStorable, TraceStore, @@ -18,11 +21,12 @@ use super::validator::{ ValidatorCode, }; + #[derive(Clone, Debug)] pub enum PatchLocations { Everywhere, - #[allow(dead_code)] ObjectReference(TypeMeta, String), + InsertAt(i64, TraceAction, TypeMeta, metav1::ObjectMeta), } #[derive(Clone, Debug)] @@ -70,7 +74,7 @@ pub struct AnnotatedTrace { base: TraceStore, patches: Vec, - events: Vec, + pub(super) events: Vec, } impl AnnotatedTrace { @@ -89,21 +93,10 @@ impl AnnotatedTrace { pub fn apply_patch(&mut self, patch: AnnotatedTracePatch) -> anyhow::Result { let mut count = 0; - for event in self.events.iter_mut() { - for obj in event.data.applied_objs.iter_mut().chain(event.data.deleted_objs.iter_mut()) { - let should_apply_here = match patch.locations { - PatchLocations::Everywhere => true, - PatchLocations::ObjectReference(ref type_, ref ns_name) => { - obj.types.as_ref().is_some_and(|t| t == type_) && &obj.namespaced_name() == ns_name - }, - }; - - if should_apply_here { - count += 1; - for op in &patch.ops { - patch_ext(&mut obj.data, op.clone())?; - } - } + for obj in self.matched_objects(&patch.locations) { + count += 1; + for op in &patch.ops { + patch_ext(&mut obj.data, op.clone())?; } } self.patches.push(patch); @@ -186,6 +179,74 @@ impl AnnotatedTrace { pub fn start_ts(&self) -> Option { self.events.first().map(|evt| evt.data.ts) } + + fn object_iter_mut(&mut self) -> impl Iterator { + self.events + .iter_mut() + .flat_map(|e| e.data.applied_objs.iter_mut().chain(e.data.deleted_objs.iter_mut())) + } +} + +impl<'a> AnnotatedTrace { + fn matched_objects( + &'a mut self, + locations: &'a PatchLocations, + ) -> Box + 'a> { + match locations { + PatchLocations::Everywhere => Box::new(self.object_iter_mut()), + PatchLocations::ObjectReference(ref type_, ref ns_name) => { + Box::new(self.object_iter_mut().filter(move |obj| { + obj.types.as_ref().is_some_and(|t| t == type_) && &obj.namespaced_name() == ns_name + })) + }, + PatchLocations::InsertAt(relative_ts, action, type_meta, object_meta) => { + let insert_ts = self.start_ts().unwrap_or_default() + relative_ts; + let insert_idx = find_or_create_event_at_ts(&mut self.events, insert_ts); + + let new_obj = DynamicObject { + types: Some(type_meta.clone()), + metadata: object_meta.clone(), + data: json!({}), + }; + let obj = match action { + TraceAction::ObjectApplied => { + self.events[insert_idx].data.applied_objs.push(new_obj); + self.events[insert_idx].data.applied_objs.iter_mut().last().unwrap() + }, + TraceAction::ObjectDeleted => { + self.events[insert_idx].data.deleted_objs.push(new_obj); + self.events[insert_idx].data.deleted_objs.iter_mut().last().unwrap() + }, + }; + Box::new(once(obj)) + }, + } + } +} + +pub(super) fn find_or_create_event_at_ts(events: &mut Vec, ts: i64) -> usize { + let new_event = AnnotatedTraceEvent { + data: TraceEvent { ts, ..Default::default() }, + ..Default::default() + }; + // Walk through the events list backwards until we find the first one less than the given ts + match events.iter().rposition(|e| e.data.ts <= ts) { + Some(i) => { + // If we found one, and the ts isn't equal, create an event with the specified + // timestamp; this goes at index i+1 since it needs to go after the lower (found) ts + if events[i].data.ts < ts { + events.insert(i + 1, new_event); + i + 1 + } else { + i // otherwise the timestamp is equal so return this index + } + }, + None => { + // In this case there are no events in the trace, so we add one at the beginning + events.push(new_event); + 0 + }, + } } #[cfg(test)] diff --git a/sk-cli/src/validation/rules/service_account_missing.rs b/sk-cli/src/validation/rules/service_account_missing.rs index 6970e820..9e380b3f 100644 --- a/sk-cli/src/validation/rules/service_account_missing.rs +++ b/sk-cli/src/validation/rules/service_account_missing.rs @@ -10,7 +10,10 @@ use std::sync::{ use json_patch_ext::prelude::*; use sk_core::k8s::GVK; use sk_core::prelude::*; -use sk_store::TracerConfig; +use sk_store::{ + TraceAction, + TracerConfig, +}; use crate::validation::validator::{ CheckResult, @@ -33,42 +36,63 @@ pub struct ServiceAccountMissing { pub(crate) seen_service_accounts: HashSet, } -impl Diagnostic for ServiceAccountMissing { - fn check_next_event(&mut self, event: &mut AnnotatedTraceEvent, config: &TracerConfig) -> CheckResult { +impl ServiceAccountMissing { + fn record_service_accounts(&mut self, event: &mut AnnotatedTraceEvent) { for obj in &event.data.applied_objs { if let Some(ref type_meta) = obj.types { - if &type_meta.kind == "ServiceAccount" { + if type_meta.kind == SVC_ACCOUNT_KIND { self.seen_service_accounts.insert(obj.namespaced_name()); } } } for obj in &event.data.deleted_objs { if let Some(ref type_meta) = obj.types { - if &type_meta.kind == "ServiceAccount" { + if type_meta.kind == SVC_ACCOUNT_KIND { self.seen_service_accounts.remove(&obj.namespaced_name()); } } } + } +} + +impl Diagnostic for ServiceAccountMissing { + fn check_next_event(&mut self, event: &mut AnnotatedTraceEvent, config: &TracerConfig) -> CheckResult { + // First we check all the objects in this event and record any service accounts we see + // (and remove any service accounts that got deleted); this way if the service account + // and the pod referencing it are created at the same time we don't fail (maybe we should, + // though? not sure, anyways it's fine for now). + self.record_service_accounts(event); let mut patches = vec![]; for (i, obj) in event.data.applied_objs.iter().enumerate() { let gvk = GVK::from_dynamic_obj(obj)?; if let Some(pod_spec_template_path) = config.pod_spec_template_path(&gvk) { - let sa_ptrs = [ + let ptrs = [ // serviceAccount is deprecated but still supported (for now) format_ptr!("{pod_spec_template_path}/spec/serviceAccount"), format_ptr!("{pod_spec_template_path}/spec/serviceAccountName"), ]; - if let Some(sa) = sa_ptrs.iter().filter_map(|ptr| ptr.resolve(&obj.data).ok()).next() { - if !self.seen_service_accounts.contains(sa.as_str().expect("expected string")) { - let fix = AnnotatedTracePatch { - locations: PatchLocations::ObjectReference( - obj.types.clone().unwrap_or_default(), - obj.namespaced_name(), - ), - ops: sa_ptrs.iter().map(|ptr| remove_operation(ptr.clone())).collect(), - }; - patches.push((i, vec![fix])); + + // If this obj references a service account that doesn't exist at this point in + // time, there are two possible fixes: + // + // 1) remove the reference to the service account from the pod template spec (recommended, because + // the pod won't exist and can't actually _do_ anything anyways), or + // 2) add the service account object in at the beginning of the simulation + if let Some(sa) = ptrs.iter().filter_map(|ptr| ptr.resolve(&obj.data).ok()).next() { + // if we're demanding a service account, we must have a namespace and a name, + // these unwraps should be safe + let svc_account = sa.as_str().unwrap(); + let svc_account_ns = &obj.namespace().unwrap(); + + if !self.seen_service_accounts.contains(&format!("{svc_account_ns}/{svc_account}")) { + patches.push(( + i, + vec![ + construct_remove_svc_account_ref_patch(obj, &ptrs), + construct_add_svc_account_patch(svc_account_ns, svc_account), + ], + )); } } } @@ -82,6 +106,29 @@ impl Diagnostic for ServiceAccountMissing { } } +fn construct_remove_svc_account_ref_patch(obj: &DynamicObject, ptrs: &[PointerBuf]) -> AnnotatedTracePatch { + AnnotatedTracePatch { + locations: PatchLocations::ObjectReference(obj.types.clone().unwrap_or_default(), obj.namespaced_name()), + ops: ptrs.iter().map(|ptr| remove_operation(ptr.clone())).collect(), + } +} + +fn construct_add_svc_account_patch(svc_account_ns: &str, svc_account: &str) -> AnnotatedTracePatch { + AnnotatedTracePatch { + locations: PatchLocations::InsertAt( + 0, + TraceAction::ObjectApplied, + SVC_ACCOUNT_GVK.into_type_meta(), + metav1::ObjectMeta { + name: Some(svc_account.into()), + namespace: Some(svc_account_ns.into()), + ..Default::default() + }, + ), + ops: vec![], + } +} + pub fn validator() -> Validator { Validator { type_: ValidatorType::Error, diff --git a/sk-cli/src/validation/rules/tests/mod.rs b/sk-cli/src/validation/rules/tests/mod.rs index 4c942210..f2dfc491 100644 --- a/sk-cli/src/validation/rules/tests/mod.rs +++ b/sk-cli/src/validation/rules/tests/mod.rs @@ -25,7 +25,7 @@ fn test_trace_config() -> TracerConfig { ..Default::default() }, ), - (SA_GVK.clone(), Default::default()), + (SVC_ACCOUNT_GVK.clone(), Default::default()), ]), } } diff --git a/sk-cli/src/validation/rules/tests/service_account_missing_test.rs b/sk-cli/src/validation/rules/tests/service_account_missing_test.rs index b410aca9..3353e207 100644 --- a/sk-cli/src/validation/rules/tests/service_account_missing_test.rs +++ b/sk-cli/src/validation/rules/tests/service_account_missing_test.rs @@ -12,8 +12,10 @@ use super::*; fn depl_event(test_deployment: DynamicObject, #[default("serviceAccount")] sa_key: &str) -> AnnotatedTraceEvent { AnnotatedTraceEvent { data: TraceEvent { - ts: 1, - applied_objs: vec![test_deployment.data(json!({"spec": {"template": {"spec": {sa_key: "foobar"}}}}))], + ts: 2, + applied_objs: vec![ + test_deployment.data(json!({"spec": {"template": {"spec": {sa_key: TEST_SERVICE_ACCOUNT}}}})) + ], deleted_objs: vec![], }, ..Default::default() @@ -40,7 +42,7 @@ fn test_service_account_missing(test_deployment: DynamicObject, test_trace_confi let mut evt = depl_event(test_deployment, sa_key); let annotations = v.check_next_event(&mut evt, &test_trace_config).unwrap(); - assert_eq!(annotations.keys().collect::>(), vec![&0]); + assert_eq!(annotations.get(&0).unwrap().len(), 2); } #[rstest] @@ -53,7 +55,7 @@ fn test_service_account_missing_deleted( let mut v = ServiceAccountMissing::default(); let mut sa_event_del = AnnotatedTraceEvent { data: TraceEvent { - ts: 0, + ts: 1, applied_objs: vec![], deleted_objs: vec![test_service_account], }, @@ -63,7 +65,7 @@ fn test_service_account_missing_deleted( v.check_next_event(&mut sa_event_del, &test_trace_config).unwrap(); let annotations = v.check_next_event(&mut depl_event, &test_trace_config).unwrap(); - assert_eq!(annotations.keys().collect::>(), vec![&0]); + assert_eq!(annotations.get(&0).unwrap().len(), 2); } #[rstest] @@ -76,7 +78,7 @@ fn test_service_account_not_missing( v.check_next_event(&mut sa_event, &test_trace_config).unwrap(); let annotations = v.check_next_event(&mut depl_event, &test_trace_config).unwrap(); - assert_eq!(annotations.keys().collect::>(), vec![&0]); + assert_none!(annotations.get(&0)); } #[rstest] @@ -100,7 +102,7 @@ fn test_service_account_not_missing_same_evt( }; let annotations = v.check_next_event(&mut depl_evt, &test_trace_config).unwrap(); - assert_eq!(annotations.keys().collect::>(), vec![&0]); + assert_none!(annotations.get(&0)); } #[rstest] diff --git a/sk-cli/src/validation/tests/annotated_trace_test.rs b/sk-cli/src/validation/tests/annotated_trace_test.rs index 34cc2ec0..edc7f8c3 100644 --- a/sk-cli/src/validation/tests/annotated_trace_test.rs +++ b/sk-cli/src/validation/tests/annotated_trace_test.rs @@ -1,7 +1,12 @@ use assertables::*; use json_patch_ext::prelude::*; +use serde_json::json; +use sk_store::TraceAction; use super::*; +use crate::validation::annotated_trace::find_or_create_event_at_ts; +use crate::validation::AnnotatedTracePatch; + #[rstest] fn test_apply_patch_everywhere(mut annotated_trace: AnnotatedTrace) { @@ -41,3 +46,53 @@ fn test_apply_patch_object_reference(mut annotated_trace: AnnotatedTrace) { } } } + +#[rstest] +#[case(TraceAction::ObjectApplied)] +fn test_apply_patch_insert_at(mut annotated_trace: AnnotatedTrace, #[case] action: TraceAction) { + annotated_trace + .apply_patch(AnnotatedTracePatch { + locations: PatchLocations::InsertAt( + 3, + action, + DS_GVK.into_type_meta(), + metav1::ObjectMeta { + namespace: Some(TEST_NAMESPACE.into()), + name: Some(TEST_DAEMONSET.into()), + ..Default::default() + }, + ), + ops: vec![add_operation(format_ptr!("/spec"), json!({"minReadySeconds": 5}))], + }) + .unwrap(); + + let obj_vec = match action { + TraceAction::ObjectApplied => &annotated_trace.events[3].data.applied_objs, + TraceAction::ObjectDeleted => &annotated_trace.events[3].data.deleted_objs, + }; + + assert_eq!(obj_vec[0].metadata.name, Some(TEST_DAEMONSET.into())); + assert_eq!(obj_vec[0].metadata.namespace, Some(TEST_NAMESPACE.into())); +} + +#[rstest] +#[case(0, 0, 4)] +#[case(1, 1, 4)] +#[case(3, 3, 5)] +#[case(7, 4, 5)] +fn test_find_or_create_event_at_ts( + mut annotated_trace: AnnotatedTrace, + #[case] ts: i64, + #[case] expected_idx: usize, + #[case] expected_len: usize, +) { + let event_idx = find_or_create_event_at_ts(&mut annotated_trace.events, ts); + assert_eq!(expected_idx, event_idx); + assert_len_eq_x!(annotated_trace.events, expected_len); +} + +#[rstest] +fn test_find_or_create_event_at_ts_empty() { + let event_idx = find_or_create_event_at_ts(&mut vec![], 5); + assert_eq!(0, event_idx); +} diff --git a/sk-cli/src/validation/tests/mod.rs b/sk-cli/src/validation/tests/mod.rs index d7f7ff12..7ebc72d8 100644 --- a/sk-cli/src/validation/tests/mod.rs +++ b/sk-cli/src/validation/tests/mod.rs @@ -46,7 +46,7 @@ pub fn annotated_trace() -> AnnotatedTrace { deleted_objs: vec![], }), AnnotatedTraceEvent::new(TraceEvent { - ts: 3, + ts: 5, applied_objs: vec![], deleted_objs: vec![test_deployment("test_depl1")], }), diff --git a/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list@0.snap b/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list@0.snap index 644504d5..8672d8ec 100644 --- a/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list@0.snap +++ b/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list@0.snap @@ -1,5 +1,5 @@ --- -source: sk-cli/src/xray/tests/view_test.rs +source: sk-cli/src/xray/view/tests/view_test.rs expression: cf --- CompletedFrame { @@ -10,7 +10,7 @@ CompletedFrame { "│>> 00:00:00 (0 applied/0 deleted) │", "│ 00:00:01 (1 applied/0 deleted) │", "│ 00:00:02 (3 applied/0 deleted) 1 error/0 warnings │", - "│ 00:00:03 (0 applied/1 deleted) │", + "│ 00:00:05 (0 applied/1 deleted) │", "│ │", "│ │", "│ │", diff --git a/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list@3.snap b/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list@3.snap index cbe305bc..62e8c262 100644 --- a/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list@3.snap +++ b/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list@3.snap @@ -1,5 +1,5 @@ --- -source: sk-cli/src/xray/tests/view_test.rs +source: sk-cli/src/xray/view/tests/view_test.rs expression: cf --- CompletedFrame { @@ -10,7 +10,7 @@ CompletedFrame { "│ 00:00:00 (0 applied/0 deleted) │", "│ 00:00:01 (1 applied/0 deleted) │", "│ 00:00:02 (3 applied/0 deleted) 1 error/0 warnings │", - "│>> 00:00:03 (0 applied/1 deleted) │", + "│>> 00:00:05 (0 applied/1 deleted) │", "│ │", "│ │", "│ │", diff --git a/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@0.snap b/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@0.snap index cd2bc5e5..0f8a0270 100644 --- a/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@0.snap +++ b/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@0.snap @@ -1,5 +1,5 @@ --- -source: sk-cli/src/xray/tests/view_test.rs +source: sk-cli/src/xray/view/tests/view_test.rs expression: cf --- CompletedFrame { @@ -11,7 +11,7 @@ CompletedFrame { "│++ │", "│ 00:00:01 (1 applied/0 deleted) │", "│ 00:00:02 (3 applied/0 deleted) 1 error/0 warnings │", - "│ 00:00:03 (0 applied/1 deleted) │", + "│ 00:00:05 (0 applied/1 deleted) │", "│ │", "│ │", "│ │", diff --git a/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@2.snap b/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@2.snap index 65bda7d4..83e2d70e 100644 --- a/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@2.snap +++ b/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@2.snap @@ -13,7 +13,7 @@ CompletedFrame { "│++ + test-namespace/test_depl1 │", "│ + test-namespace/test_depl2xxxxxxxxxxxxxxxxxxxxxx... 1 error/0 warnings │", "│ + test-namespace/test_depl3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx... │", - "│ 00:00:03 (0 applied/1 deleted) │", + "│ 00:00:05 (0 applied/1 deleted) │", "│ │", "│ │", "│ │", diff --git a/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@3.snap b/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@3.snap index fb843808..f6a7592d 100644 --- a/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@3.snap +++ b/sk-cli/src/xray/view/tests/snapshots/skctl__xray__view__tests__view_test__itest_render_event_list_event_selected@3.snap @@ -1,5 +1,5 @@ --- -source: sk-cli/src/xray/tests/view_test.rs +source: sk-cli/src/xray/view/tests/view_test.rs expression: cf --- CompletedFrame { @@ -10,7 +10,7 @@ CompletedFrame { "│ 00:00:00 (0 applied/0 deleted) │", "│ 00:00:01 (1 applied/0 deleted) │", "│ 00:00:02 (3 applied/0 deleted) 1 error/0 warnings │", - "│>> 00:00:03 (0 applied/1 deleted) │", + "│>> 00:00:05 (0 applied/1 deleted) │", "│++ - test-namespace/test_depl1 │", "│ │", "│ │", diff --git a/sk-core/Cargo.toml b/sk-core/Cargo.toml index 9796dde9..e89223d5 100644 --- a/sk-core/Cargo.toml +++ b/sk-core/Cargo.toml @@ -9,7 +9,7 @@ readme.workspace = true edition.workspace = true [features] -testutils = ["dep:http", "dep:httpmock", "dep:lazy_static", "dep:mockall", "dep:rstest"] +testutils = ["dep:http", "dep:httpmock", "dep:mockall", "dep:rstest"] [dependencies] anyhow = { workspace = true } @@ -19,6 +19,7 @@ bytes = { workspace = true } clockabilly = { workspace = true } kube = { workspace = true } k8s-openapi = { workspace = true } +lazy_static = { workspace = true } object_store = { workspace = true } parse_datetime_fork = { workspace = true } paste = { workspace = true } @@ -37,7 +38,6 @@ url = { workspace = true } # testutils dependencies http = { workspace = true, optional = true } httpmock = { workspace = true, optional = true } -lazy_static = { workspace = true, optional = true } mockall = { workspace = true, optional = true } rstest = { workspace = true, optional = true } diff --git a/sk-core/src/constants.rs b/sk-core/src/constants.rs index 91a8bab2..40f45902 100644 --- a/sk-core/src/constants.rs +++ b/sk-core/src/constants.rs @@ -1,3 +1,7 @@ +use lazy_static::lazy_static; + +use crate::k8s::GVK; + // Well-known labels, annotations, and taints pub const KUBERNETES_IO_METADATA_NAME_KEY: &str = "kubernetes.io/metadata.name"; pub const APP_KUBERNETES_IO_NAME_KEY: &str = "app.kubernetes.io/name"; @@ -28,11 +32,17 @@ pub const SK_LEASE_NAME: &str = "sk-lease"; pub const RETRY_DELAY_SECONDS: u64 = 5; pub const ERROR_RETRY_DELAY_SECONDS: u64 = 30; +// Kinds +pub const SVC_ACCOUNT_KIND: &str = "ServiceAccount"; + +// Built-in GVKs +lazy_static! { + pub static ref SVC_ACCOUNT_GVK: GVK = GVK::new("", "v1", SVC_ACCOUNT_KIND); +} + #[cfg(feature = "testutils")] mod test_constants { - use lazy_static::lazy_static; - - use crate::k8s::GVK; + use super::*; pub const EMPTY_POD_SPEC_HASH: u64 = 17506812802394981455; pub const TEST_DEPLOYMENT: &str = "the-deployment"; @@ -49,7 +59,6 @@ mod test_constants { lazy_static! { pub static ref DEPL_GVK: GVK = GVK::new("apps", "v1", "Deployment"); pub static ref DS_GVK: GVK = GVK::new("apps", "v1", "DaemonSet"); - pub static ref SA_GVK: GVK = GVK::new("", "v1", "ServiceAccount"); } } diff --git a/sk-core/src/k8s/testutils/objs.rs b/sk-core/src/k8s/testutils/objs.rs index 3471443c..0d66f320 100644 --- a/sk-core/src/k8s/testutils/objs.rs +++ b/sk-core/src/k8s/testutils/objs.rs @@ -24,5 +24,5 @@ pub fn test_daemonset(#[default(TEST_DAEMONSET)] name: &str) -> DynamicObject { #[fixture] pub fn test_service_account(#[default(TEST_SERVICE_ACCOUNT)] name: &str) -> DynamicObject { - DynamicObject::new(&name, &ApiResource::from_gvk(&SA_GVK)).within(TEST_NAMESPACE) + DynamicObject::new(&name, &ApiResource::from_gvk(&SVC_ACCOUNT_GVK)).within(TEST_NAMESPACE) } diff --git a/sk-store/src/lib.rs b/sk-store/src/lib.rs index 89d8d2df..bfc492cf 100644 --- a/sk-store/src/lib.rs +++ b/sk-store/src/lib.rs @@ -29,8 +29,8 @@ pub use crate::index::TraceIndex; use crate::pod_owners_map::PodLifecyclesMap; pub use crate::store::TraceStore; -#[derive(Debug)] -enum TraceAction { +#[derive(Clone, Copy, Debug)] +pub enum TraceAction { ObjectApplied, ObjectDeleted, }