Skip to content

Commit

Permalink
feat: service_account_missing validation check
Browse files Browse the repository at this point in the history
  • Loading branch information
drmorr0 committed Dec 17, 2024
1 parent aa21161 commit 502b096
Show file tree
Hide file tree
Showing 11 changed files with 139 additions and 17 deletions.
6 changes: 3 additions & 3 deletions sk-cli/src/validation/annotated_trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,12 @@ impl AnnotatedTrace {
trace.export_all()
}

pub fn validate(&mut self, validators: &BTreeMap<ValidatorCode, Validator>) -> AnnotationSummary {
pub fn validate(&mut self, validators: &BTreeMap<ValidatorCode, Validator>) -> anyhow::Result<AnnotationSummary> {
let mut summary = BTreeMap::new();
for event in self.events.iter_mut() {
event.clear_annotations();
for (code, validator) in validators.iter() {
let affected_indices = validator.check_next_event(event);
let affected_indices = validator.check_next_event(event, self.base.config())?;
let count = affected_indices.len();
summary.entry(*code).and_modify(|e| *e += count).or_insert(count);

Expand All @@ -124,7 +124,7 @@ impl AnnotatedTrace {
}
}
}
summary
Ok(summary)
}

pub fn get_event(&self, idx: usize) -> Option<&AnnotatedTraceEvent> {
Expand Down
2 changes: 1 addition & 1 deletion sk-cli/src/validation/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod annotated_trace;
mod status_field_populated;
mod rules;
mod summary;
mod validation_store;
mod validator;
Expand Down
5 changes: 5 additions & 0 deletions sk-cli/src/validation/rules/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod service_account_missing;
pub mod status_field_populated;

#[cfg(test)]
mod tests;
90 changes: 90 additions & 0 deletions sk-cli/src/validation/rules/service_account_missing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use std::collections::HashSet;
use std::sync::{
Arc,
RwLock,
};

use json_patch_ext::prelude::*;
use sk_core::k8s::GVK;
use sk_core::prelude::*;
use sk_store::TracerConfig;

use crate::validation::annotated_trace::AnnotatedTraceEvent;
use crate::validation::validator::{
Diagnostic,
Validator,
ValidatorType,
};

const HELP: &str = r#"A pod needs a service account that is not present in
the trace file. The simulation will fail because pods cannot be created
if their service account does not exist."#;

#[derive(Default)]
pub struct ServiceAccountMissing {
seen_service_accounts: HashSet<String>,
}

fn get_service_account(obj: &DynamicObject, config: &TracerConfig) -> anyhow::Result<Option<String>> {
let gvk = GVK::from_dynamic_obj(obj)?;
if let Some(pod_spec_template_path) = config.pod_spec_template_path(&gvk) {
let sa_ptr = format_ptr!("{pod_spec_template_path}/spec/serviceAccount");
let sa_name_ptr = format_ptr!("{pod_spec_template_path}/spec/serviceAccountName");
if let Ok(sa) = sa_ptr.resolve(&obj.data) {
return Ok(Some(sa.to_string()));
} else if let Ok(sa) = sa_name_ptr.resolve(&obj.data) {
return Ok(Some(sa.to_string()));
}
}
Ok(None)
}

impl Diagnostic for ServiceAccountMissing {
fn check_next_event(
&mut self,
event: &mut AnnotatedTraceEvent,
config: &TracerConfig,
) -> anyhow::Result<Vec<usize>> {
for obj in &event.data.applied_objs {
if let Some(ref type_meta) = obj.types {
if &type_meta.kind == "ServiceAccount" {
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" {
self.seen_service_accounts.remove(&obj.namespaced_name());
}
}
}

let mut indices = vec![];
for (i, obj) in event.data.applied_objs.iter().enumerate() {
let maybe_sa = get_service_account(obj, config)?;
if let Some(sa) = maybe_sa {
if !self.seen_service_accounts.contains(&sa) {
indices.push(i);
}
}
}

Ok(indices)
}

fn fixes(&self) -> Vec<PatchOperation> {
vec![remove_operation(format_ptr!("/spec/serviceAccount"))]
}

fn reset(&mut self) {}
}

pub fn validator() -> Validator {
Validator {
type_: ValidatorType::Error,
name: "service_account_missing",
help: HELP,
diagnostic: Arc::new(RwLock::new(ServiceAccountMissing::default())),
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use std::sync::{
};

use json_patch_ext::prelude::*;
use sk_store::TracerConfig;

use super::annotated_trace::AnnotatedTraceEvent;
use super::validator::{
use crate::validation::annotated_trace::AnnotatedTraceEvent;
use crate::validation::validator::{
Diagnostic,
Validator,
ValidatorType,
Expand All @@ -18,11 +19,11 @@ and shouldn't be applied "by hand". This is probably "fine" but it would be
better to clean them up (and also they take up a lot of space."#;

#[derive(Default)]
pub(super) struct StatusFieldPopulated {}
pub struct StatusFieldPopulated {}

impl Diagnostic for StatusFieldPopulated {
fn check_next_event(&mut self, event: &mut AnnotatedTraceEvent) -> Vec<usize> {
event
fn check_next_event(&mut self, event: &mut AnnotatedTraceEvent, _: &TracerConfig) -> anyhow::Result<Vec<usize>> {
Ok(event
.data
.applied_objs
.iter()
Expand All @@ -39,7 +40,7 @@ impl Diagnostic for StatusFieldPopulated {
}
None
})
.collect()
.collect())
}

fn fixes(&self) -> Vec<PatchOperation> {
Expand All @@ -49,7 +50,7 @@ impl Diagnostic for StatusFieldPopulated {
fn reset(&mut self) {}
}

pub(super) fn validator() -> Validator {
pub fn validator() -> Validator {
Validator {
type_: ValidatorType::Warning,
name: "status_field_populated",
Expand Down
7 changes: 7 additions & 0 deletions sk-cli/src/validation/rules/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod status_field_populated_test;

use rstest::*;
use sk_core::prelude::*;

use super::*;
use crate::validation::AnnotatedTraceEvent;
1 change: 0 additions & 1 deletion sk-cli/src/validation/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
mod annotated_trace_test;
mod status_field_populated_test;
mod validation_store_test;

use std::collections::BTreeMap;
Expand Down
5 changes: 3 additions & 2 deletions sk-cli/src/validation/validation_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use lazy_static::lazy_static;
use serde::Serialize;
use sk_core::prelude::*;

use super::rules::*;
use super::summary::ValidationSummary;
use super::validator::{
Validator,
ValidatorCode,
};
use super::{
status_field_populated,
AnnotatedTrace,
AnnotatedTracePatch,
PatchLocations,
Expand All @@ -32,7 +32,7 @@ impl ValidationStore {
let mut summary = ValidationSummary::default();
let mut summary_populated = false;
loop {
let s = trace.validate(&self.validators);
let s = trace.validate(&self.validators)?;
if !summary_populated {
summary.annotations = s;
summary_populated = true;
Expand Down Expand Up @@ -109,6 +109,7 @@ impl ValidationStore {
let mut store = ValidationStore { validators: BTreeMap::new() };

store.register(status_field_populated::validator());
store.register(service_account_missing::validator());

store
}
Expand Down
15 changes: 12 additions & 3 deletions sk-cli/src/validation/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use serde::{
Serialize,
Serializer,
};
use sk_store::TracerConfig;

use super::annotated_trace::AnnotatedTraceEvent;

Expand Down Expand Up @@ -55,7 +56,11 @@ impl fmt::Display for ValidatorCode {
}

pub trait Diagnostic {
fn check_next_event(&mut self, evt: &mut AnnotatedTraceEvent) -> Vec<usize>;
fn check_next_event(
&mut self,
event: &mut AnnotatedTraceEvent,
config: &TracerConfig,
) -> anyhow::Result<Vec<usize>>;
fn fixes(&self) -> Vec<PatchOperation>;
fn reset(&mut self);
}
Expand All @@ -74,8 +79,12 @@ pub struct Validator {
}

impl Validator {
pub fn check_next_event(&self, a_event: &mut AnnotatedTraceEvent) -> Vec<usize> {
self.diagnostic.write().unwrap().check_next_event(a_event)
pub fn check_next_event(
&self,
event: &mut AnnotatedTraceEvent,
config: &TracerConfig,
) -> anyhow::Result<Vec<usize>> {
self.diagnostic.write().unwrap().check_next_event(event, config)
}

pub fn fixes(&self) -> Vec<PatchOperation> {
Expand Down
10 changes: 10 additions & 0 deletions sk-cli/src/xray/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,16 @@ fn render_object(app: &mut App, frame: &mut Frame, layout: Rect) {
}
}

// let contents = List::new(obj_str.split('\n').map(|s| {
// let mut span = Span::from(s);
// if s.contains("status") {
// span = span.style(Style::new().white().on_yellow());
// } else if s.contains("serviceAccount") {
// span = span.style(Style::new().white().on_red());
// }
// span
// }))
// .highlight_style(Style::new().bg(Color::Blue));
frame.render_stateful_widget(contents, layout, &mut app.object_contents_list_state);
}

Expand Down

0 comments on commit 502b096

Please sign in to comment.