Skip to content

Commit

Permalink
Merge pull request #398 from flavio/refactor
Browse files Browse the repository at this point in the history
refactor: change signature of `PolicyEvaluator.validate`
  • Loading branch information
fabriziosestito authored Dec 13, 2023
2 parents 130f6ec + 3a70b07 commit b1ac8af
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 129 deletions.
98 changes: 6 additions & 92 deletions src/policy_evaluator/mod.rs → src/policy_evaluator.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
mod evaluator;
pub mod policy_evaluator_builder;
pub mod policy_evaluator_pre;
mod policy_evaluator_pre;
mod stack_pre;

pub use evaluator::PolicyEvaluator;
pub use policy_evaluator_pre::PolicyEvaluatorPre;

use anyhow::{anyhow, Result};
use kubewarden_policy_sdk::metadata::ProtocolVersion;
use kubewarden_policy_sdk::settings::SettingsValidationResponse;
use serde::Serialize;
use serde_json::value;
use std::{convert::TryFrom, fmt};

use crate::admission_request::AdmissionRequest;
use crate::admission_response::AdmissionResponse;
use crate::evaluation_context::EvaluationContext;
use crate::runtimes::rego::Runtime as BurregoRuntime;
use crate::runtimes::wapc::Runtime as WapcRuntime;
use crate::runtimes::wasi_cli::Runtime as WasiRuntime;
use crate::runtimes::Runtime;

pub use policy_evaluator_pre::PolicyEvaluatorPre;

#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum PolicyExecutionMode {
Expand Down Expand Up @@ -82,87 +77,6 @@ impl TryFrom<PolicyExecutionMode> for RegoPolicyExecutionMode {
/// Settings specified by the user for a given policy.
pub type PolicySettings = serde_json::Map<String, serde_json::Value>;

pub struct PolicyEvaluator {
runtime: Runtime,
}

impl PolicyEvaluator {
pub(crate) fn new(runtime: Runtime) -> Self {
Self { runtime }
}

#[tracing::instrument(skip(request, eval_ctx))]
pub fn validate(
&mut self,
request: ValidateRequest,
settings: &PolicySettings,
eval_ctx: &EvaluationContext,
) -> AdmissionResponse {
match self.runtime {
Runtime::Wapc(ref mut wapc_stack) => {
WapcRuntime(wapc_stack).validate(settings, &request)
}
Runtime::Rego(ref mut burrego_evaluator) => {
let kube_ctx = burrego_evaluator.build_kubernetes_context(
eval_ctx.callback_channel.as_ref(),
&eval_ctx.ctx_aware_resources_allow_list,
);
match kube_ctx {
Ok(ctx) => BurregoRuntime(burrego_evaluator).validate(settings, &request, &ctx),
Err(e) => {
AdmissionResponse::reject(request.uid().to_string(), e.to_string(), 500)
}
}
}
Runtime::Cli(ref mut cli_stack) => WasiRuntime(cli_stack).validate(settings, &request),
}
}

#[tracing::instrument]
pub fn validate_settings(&mut self, settings: &PolicySettings) -> SettingsValidationResponse {
let settings_str = match serde_json::to_string(settings) {
Ok(settings) => settings,
Err(err) => {
return SettingsValidationResponse {
valid: false,
message: Some(format!("could not marshal settings: {err}")),
}
}
};

match self.runtime {
Runtime::Wapc(ref mut wapc_stack) => {
WapcRuntime(wapc_stack).validate_settings(settings_str)
}
Runtime::Rego(ref mut burrego_evaluator) => {
BurregoRuntime(burrego_evaluator).validate_settings(settings_str)
}
Runtime::Cli(ref mut cli_stack) => {
WasiRuntime(cli_stack).validate_settings(settings_str)
}
}
}

pub fn protocol_version(&mut self) -> Result<ProtocolVersion> {
match &mut self.runtime {
Runtime::Wapc(ref mut wapc_stack) => WapcRuntime(wapc_stack).protocol_version(),
_ => Err(anyhow!(
"protocol_version is only applicable to a Kubewarden policy"
)),
}
}
}

impl fmt::Debug for PolicyEvaluator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let runtime = self.runtime.to_string();

f.debug_struct("PolicyEvaluator")
.field("runtime", &runtime)
.finish()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
96 changes: 96 additions & 0 deletions src/policy_evaluator/evaluator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use anyhow::{anyhow, Result};
use kubewarden_policy_sdk::metadata::ProtocolVersion;
use kubewarden_policy_sdk::settings::SettingsValidationResponse;
use std::fmt;

use crate::admission_response::AdmissionResponse;
use crate::evaluation_context::EvaluationContext;
use crate::policy_evaluator::{PolicySettings, ValidateRequest};
use crate::runtimes::rego::Runtime as BurregoRuntime;
use crate::runtimes::wapc::Runtime as WapcRuntime;
use crate::runtimes::wasi_cli::Runtime as WasiRuntime;
use crate::runtimes::Runtime;

pub struct PolicyEvaluator {
runtime: Runtime,
eval_ctx: EvaluationContext,
}

impl PolicyEvaluator {
pub(crate) fn new(runtime: Runtime, eval_ctx: &EvaluationContext) -> Self {
Self {
runtime,
eval_ctx: eval_ctx.to_owned(),
}
}

#[tracing::instrument(skip(request))]
pub fn validate(
&mut self,
request: ValidateRequest,
settings: &PolicySettings,
) -> AdmissionResponse {
match self.runtime {
Runtime::Wapc(ref mut wapc_stack) => {
WapcRuntime(wapc_stack).validate(settings, &request)
}
Runtime::Rego(ref mut burrego_evaluator) => {
let kube_ctx = burrego_evaluator.build_kubernetes_context(
self.eval_ctx.callback_channel.as_ref(),
&self.eval_ctx.ctx_aware_resources_allow_list,
);
match kube_ctx {
Ok(ctx) => BurregoRuntime(burrego_evaluator).validate(settings, &request, &ctx),
Err(e) => {
AdmissionResponse::reject(request.uid().to_string(), e.to_string(), 500)
}
}
}
Runtime::Cli(ref mut cli_stack) => WasiRuntime(cli_stack).validate(settings, &request),
}
}

#[tracing::instrument]
pub fn validate_settings(&mut self, settings: &PolicySettings) -> SettingsValidationResponse {
let settings_str = match serde_json::to_string(settings) {
Ok(settings) => settings,
Err(err) => {
return SettingsValidationResponse {
valid: false,
message: Some(format!("could not marshal settings: {err}")),
}
}
};

match self.runtime {
Runtime::Wapc(ref mut wapc_stack) => {
WapcRuntime(wapc_stack).validate_settings(settings_str)
}
Runtime::Rego(ref mut burrego_evaluator) => {
BurregoRuntime(burrego_evaluator).validate_settings(settings_str)
}
Runtime::Cli(ref mut cli_stack) => {
WasiRuntime(cli_stack).validate_settings(settings_str)
}
}
}

pub fn protocol_version(&mut self) -> Result<ProtocolVersion> {
match &mut self.runtime {
Runtime::Wapc(ref mut wapc_stack) => WapcRuntime(wapc_stack).protocol_version(),
_ => Err(anyhow!(
"protocol_version is only applicable to a Kubewarden policy"
)),
}
}
}

impl fmt::Debug for PolicyEvaluator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let runtime = self.runtime.to_string();

f.debug_struct("PolicyEvaluator")
.field("runtime", &runtime)
.finish()
}
}
6 changes: 2 additions & 4 deletions src/policy_evaluator/policy_evaluator_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ use anyhow::{anyhow, Result};
use std::path::Path;
use wasmtime_provider::wasmtime;

use crate::policy_evaluator::{
policy_evaluator_pre::StackPre, PolicyEvaluatorPre, PolicyExecutionMode,
};
use crate::policy_evaluator::{stack_pre::StackPre, PolicyEvaluatorPre, PolicyExecutionMode};
use crate::runtimes::{rego, wapc, wasi_cli};

/// Configure behavior of wasmtime [epoch-based interruptions](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.epoch_interruption)
Expand Down Expand Up @@ -197,7 +195,7 @@ impl PolicyEvaluatorBuilder {
}
};

Ok(PolicyEvaluatorPre { stack_pre })
Ok(PolicyEvaluatorPre::new(stack_pre))
}

fn build_engine(&self) -> Result<wasmtime::Engine> {
Expand Down
40 changes: 7 additions & 33 deletions src/policy_evaluator/policy_evaluator_pre.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,22 @@
use anyhow::Result;

use crate::evaluation_context::EvaluationContext;
use crate::policy_evaluator::PolicyEvaluator;
use crate::policy_evaluator::{stack_pre::StackPre, PolicyEvaluator};
use crate::runtimes::{rego, wapc, wasi_cli, Runtime};

/// Holds pre-initialized stacks for all the types of policies we run
///
/// Pre-initialized instances are key to reduce the evaluation time when
/// using on-demand PolicyEvaluator instances; where on-demand means that
/// each validation request has a brand new PolicyEvaluator that is discarded
/// once the evaluation is done.
pub(crate) enum StackPre {
Wapc(crate::runtimes::wapc::StackPre),
Wasi(crate::runtimes::wasi_cli::StackPre),
Rego(crate::runtimes::rego::StackPre),
}

impl From<wapc::StackPre> for StackPre {
fn from(wapc_stack_pre: wapc::StackPre) -> Self {
StackPre::Wapc(wapc_stack_pre)
}
}

impl From<wasi_cli::StackPre> for StackPre {
fn from(wasi_stack_pre: wasi_cli::StackPre) -> Self {
StackPre::Wasi(wasi_stack_pre)
}
}

impl From<rego::StackPre> for StackPre {
fn from(rego_stack_pre: rego::StackPre) -> Self {
StackPre::Rego(rego_stack_pre)
}
}

/// This struct provides a way to quickly allocate a `PolicyEvaluator`
/// object.
///
/// See the [`rehydrate`](PolicyEvaluatorPre::rehydrate) method.
pub struct PolicyEvaluatorPre {
pub(crate) stack_pre: StackPre,
stack_pre: StackPre,
}

impl PolicyEvaluatorPre {
pub(crate) fn new(stack_pre: StackPre) -> Self {
PolicyEvaluatorPre { stack_pre }
}

/// Create a `PolicyEvaluator` instance. The creation of the instance is achieved by
/// using wasmtime low level primitives (like `wasmtime::InstancePre`) to make the operation
/// as fast as possible.
Expand All @@ -66,6 +40,6 @@ impl PolicyEvaluatorPre {
}
};

Ok(PolicyEvaluator::new(runtime))
Ok(PolicyEvaluator::new(runtime, eval_ctx))
}
}
31 changes: 31 additions & 0 deletions src/policy_evaluator/stack_pre.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::runtimes::{rego, wapc, wasi_cli};

/// Holds pre-initialized stacks for all the types of policies we run
///
/// Pre-initialized instances are key to reduce the evaluation time when
/// using on-demand PolicyEvaluator instances; where on-demand means that
/// each validation request has a brand new PolicyEvaluator that is discarded
/// once the evaluation is done.
pub(crate) enum StackPre {
Wapc(crate::runtimes::wapc::StackPre),
Wasi(crate::runtimes::wasi_cli::StackPre),
Rego(crate::runtimes::rego::StackPre),
}

impl From<wapc::StackPre> for StackPre {
fn from(wapc_stack_pre: wapc::StackPre) -> Self {
StackPre::Wapc(wapc_stack_pre)
}
}

impl From<wasi_cli::StackPre> for StackPre {
fn from(wasi_stack_pre: wasi_cli::StackPre) -> Self {
StackPre::Wasi(wasi_stack_pre)
}
}

impl From<rego::StackPre> for StackPre {
fn from(rego_stack_pre: rego::StackPre) -> Self {
StackPre::Rego(rego_stack_pre)
}
}

0 comments on commit b1ac8af

Please sign in to comment.