diff --git a/dsc_lib/src/dscresources/command_resource.rs b/dsc_lib/src/dscresources/command_resource.rs index 001c280a..ab0cf756 100644 --- a/dsc_lib/src/dscresources/command_resource.rs +++ b/dsc_lib/src/dscresources/command_resource.rs @@ -6,7 +6,7 @@ use serde_json::Value; use std::{collections::HashMap, env, process::Command, io::{Write, Read}, process::Stdio}; use crate::{dscerror::DscError, dscresources::invoke_result::{ResourceGetResponse, ResourceSetResponse, ResourceTestResponse}}; use crate::configure::config_result::ResourceGetResult; -use super::{dscresource::get_diff,resource_manifest::{ResourceManifest, InputKind, ReturnKind, SchemaKind}, invoke_result::{GetResult, SetResult, TestResult, ValidateResult, ExportResult}}; +use super::{dscresource::get_diff,resource_manifest::{Kind, ResourceManifest, InputKind, ReturnKind, SchemaKind}, invoke_result::{GetResult, SetResult, TestResult, ValidateResult, ExportResult}}; use tracing::{error, warn, info, debug, trace}; pub const EXIT_PROCESS_TERMINATED: i32 = 0x102; @@ -78,6 +78,11 @@ pub fn invoke_get(resource: &ResourceManifest, cwd: &str, filter: &str) -> Resul return Err(DscError::Command(resource.resource_type.clone(), exit_code, stderr)); } + if resource.kind == Some(Kind::Resource) { + debug!("Verifying output of get '{}' using '{}'", &resource.resource_type, &resource.get.executable); + verify_json(resource, cwd, &stdout)?; + } + let result: GetResult = if let Ok(group_response) = serde_json::from_str::>(&stdout) { trace!("Group get response: {:?}", &group_response); GetResult::Group(group_response) @@ -179,6 +184,11 @@ pub fn invoke_set(resource: &ResourceManifest, cwd: &str, desired: &str, skip_te return Err(DscError::Command(resource.resource_type.clone(), exit_code, stderr)); } + if resource.kind == Some(Kind::Resource) { + debug!("Verifying output of get '{}' using '{}'", &resource.resource_type, &resource.get.executable); + verify_json(resource, cwd, &stdout)?; + } + let pre_state: Value = if exit_code == 0 { serde_json::from_str(&stdout)? } @@ -192,9 +202,15 @@ pub fn invoke_set(resource: &ResourceManifest, cwd: &str, desired: &str, skip_te if exit_code != 0 { return Err(DscError::Command(resource.resource_type.clone(), exit_code, stderr)); } + match set.returns { Some(ReturnKind::State) => { + if resource.kind == Some(Kind::Resource) { + debug!("Verifying output of set '{}' using '{}'", &resource.resource_type, &set.executable); + verify_json(resource, cwd, &stdout)?; + } + let actual_value: Value = match serde_json::from_str(&stdout){ Result::Ok(r) => {r}, Result::Err(err) => { @@ -293,6 +309,11 @@ pub fn invoke_test(resource: &ResourceManifest, cwd: &str, expected: &str) -> Re return Err(DscError::Command(resource.resource_type.clone(), exit_code, stderr)); } + if resource.kind == Some(Kind::Resource) { + debug!("Verifying output of test '{}' using '{}'", &resource.resource_type, &test.executable); + verify_json(resource, cwd, &stdout)?; + } + let expected_value: Value = serde_json::from_str(expected)?; match test.returns { Some(ReturnKind::State) => { @@ -462,6 +483,10 @@ pub fn invoke_export(resource: &ResourceManifest, cwd: &str, input: Option<&str> return Err(DscError::Operation(format!("Failed to parse json from export {}|{}|{} -> {err}", &export.executable, stdout, stderr))) } }; + if resource.kind == Some(Kind::Resource) { + debug!("Verifying output of export '{}' using '{}'", &resource.resource_type, &resource.get.executable); + verify_json(resource, cwd, line)?; + } instances.push(instance); } diff --git a/dsc_lib/src/dscresources/dscresource.rs b/dsc_lib/src/dscresources/dscresource.rs index 2ca9f990..1a588d76 100644 --- a/dsc_lib/src/dscresources/dscresource.rs +++ b/dsc_lib/src/dscresources/dscresource.rs @@ -7,7 +7,6 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; -use tracing::{debug, trace}; use super::{command_resource, dscerror, invoke_result::{ExportResult, GetResult, ResourceTestResponse, SetResult, TestResult, ValidateResult}, resource_manifest::import_manifest}; @@ -77,54 +76,6 @@ impl DscResource { manifest: None, } } - - fn validate_input(&self, input: &str) -> Result<(), DscError> { - debug!("Validating input for resource: {}", &self.type_name); - if input.is_empty() { - return Ok(()); - } - let Some(manifest) = &self.manifest else { - return Err(DscError::MissingManifest(self.type_name.clone())); - }; - let resource_manifest = import_manifest(manifest.clone())?; - - if resource_manifest.validate.is_some() { - trace!("Using custom validation"); - let validation_result = match self.validate(input) { - Ok(validation_result) => validation_result, - Err(err) => { - return Err(DscError::Validation(format!("Validation failed: {err}"))); - }, - }; - trace!("Validation result is valid: {}", validation_result.valid); - if !validation_result.valid { - return Err(DscError::Validation("Validation failed".to_string())); - } - } - else { - trace!("Using JSON schema validation"); - let Ok(schema) = self.schema() else { - return Err(DscError::Validation("Schema not available".to_string())); - }; - - let schema = serde_json::from_str::(&schema)?; - - let Ok(compiled_schema) = jsonschema::JSONSchema::compile(&schema) else { - return Err(DscError::Validation("Schema compilation failed".to_string())); - }; - - let input = serde_json::from_str::(input)?; - if let Err(err) = compiled_schema.validate(&input) { - let mut error = format!("Resource '{}' failed validation: ", self.type_name); - for e in err { - error.push_str(&format!("\n{e} ")); - } - return Err(DscError::Validation(error)); - }; - } - - Ok(()) - } } impl Default for DscResource { @@ -201,7 +152,6 @@ pub trait Invoke { impl Invoke for DscResource { fn get(&self, filter: &str) -> Result { - self.validate_input(filter)?; match &self.implemented_as { ImplementedAs::Custom(_custom) => { Err(DscError::NotImplemented("get custom resources".to_string())) @@ -217,7 +167,6 @@ impl Invoke for DscResource { } fn set(&self, desired: &str, skip_test: bool) -> Result { - self.validate_input(desired)?; match &self.implemented_as { ImplementedAs::Custom(_custom) => { Err(DscError::NotImplemented("set custom resources".to_string())) @@ -233,7 +182,6 @@ impl Invoke for DscResource { } fn test(&self, expected: &str) -> Result { - self.validate_input(expected)?; match &self.implemented_as { ImplementedAs::Custom(_custom) => { Err(DscError::NotImplemented("test custom resources".to_string()))