diff --git a/dsc/locales/en-us.toml b/dsc/locales/en-us.toml index 5ca2bf42a..61d5946b6 100644 --- a/dsc/locales/en-us.toml +++ b/dsc/locales/en-us.toml @@ -107,6 +107,7 @@ invalidOperationOnAdapter = "Can not perform this operation on the adapter itsel setInputEmpty = "Desired input is empty" testInputEmpty = "Expected input is required" jsonError = "JSON: %{err}" +routingToDelete = "Routing to delete operation because _exist is false" [subcommand] actualStateNotObject = "actual_state is not an object" diff --git a/dsc/src/resource_command.rs b/dsc/src/resource_command.rs index 22b6c7a74..b12c0a354 100644 --- a/dsc/src/resource_command.rs +++ b/dsc/src/resource_command.rs @@ -5,9 +5,11 @@ use crate::args::{GetOutputFormat, OutputFormat}; use crate::util::{EXIT_DSC_ERROR, EXIT_INVALID_ARGS, EXIT_JSON_ERROR, EXIT_DSC_RESOURCE_NOT_FOUND, write_object}; use dsc_lib::configure::config_doc::{Configuration, ExecutionKind}; use dsc_lib::configure::add_resource_export_results_to_configuration; -use dsc_lib::dscresources::{resource_manifest::Kind, invoke_result::{GetResult, ResourceGetResponse}}; +use dsc_lib::dscresources::{resource_manifest::Kind, invoke_result::{GetResult, ResourceGetResponse, ResourceSetResponse, SetResult}}; +use dsc_lib::dscresources::dscresource::{Capability, get_diff}; use dsc_lib::dscerror::DscError; use rust_i18n::t; +use serde_json::Value; use tracing::{error, debug}; use dsc_lib::{ @@ -142,6 +144,62 @@ pub fn set(dsc: &mut DscManager, resource_type: &str, version: Option<&str>, inp exit(EXIT_DSC_ERROR); } + let exist = match serde_json::from_str::(input) { + Ok(v) => { + if let Some(exist_value) = v.get("_exist") { + !matches!(exist_value, Value::Bool(false)) + } else { + true + } + }, + Err(_) => true, + }; + + if !exist && resource.capabilities.contains(&Capability::Delete) && !resource.capabilities.contains(&Capability::SetHandlesExist) { + debug!("{}", t!("resource_command.routingToDelete")); + + let before_state = match resource.get(input) { + Ok(GetResult::Resource(response)) => response.actual_state, + Ok(_) => unreachable!(), + Err(err) => { + error!("{err}"); + exit(EXIT_DSC_ERROR); + } + }; + + if let Err(err) = resource.delete(input) { + error!("{err}"); + exit(EXIT_DSC_ERROR); + } + + let after_state = match resource.get(input) { + Ok(GetResult::Resource(response)) => response.actual_state, + Ok(_) => unreachable!(), + Err(err) => { + error!("{err}"); + exit(EXIT_DSC_ERROR); + } + }; + + let diff = get_diff(&after_state, &before_state); + + let result = SetResult::Resource(ResourceSetResponse { + before_state, + after_state, + changed_properties: Some(diff), + }); + + let json = match serde_json::to_string(&result) { + Ok(json) => json, + Err(err) => { + error!("{}", t!("resource_command.jsonError", err = err)); + exit(EXIT_JSON_ERROR); + } + }; + write_object(&json, format, false); + return; + } + match resource.set(input, true, &ExecutionKind::Actual) { Ok(result) => { // convert to json diff --git a/dsc/tests/dsc_resource_set.tests.ps1 b/dsc/tests/dsc_resource_set.tests.ps1 index a0c94395a..1c3dfce0d 100644 --- a/dsc/tests/dsc_resource_set.tests.ps1 +++ b/dsc/tests/dsc_resource_set.tests.ps1 @@ -14,4 +14,10 @@ Describe 'Invoke a resource set directly' { $out.afterState.version | Should -BeExactly '1.1.2' $out.changedProperties | Should -BeNullOrEmpty } + + It '_exist false routes to delete operation' { + $out = dsc -l trace resource set --resource Test/Delete --input '{"_exist": false}' 2>&1 + $LASTEXITCODE | Should -Be 0 + $out | Out-String | Should -Match 'Routing to delete operation because _exist is false' + } }