Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dsc/locales/en-us.toml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ setInputEmpty = "Desired input is empty"
testInputEmpty = "Expected input is required"
jsonError = "JSON: %{err}"
routingToDelete = "Routing to delete operation because _exist is false"
syntheticWhatIf = "Resource does not natively support what-if, engine will generate synthetic what-if"

[subcommand]
actualStateNotObject = "actual_state is not an object"
Expand Down
4 changes: 4 additions & 0 deletions dsc/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,10 @@ pub enum ResourceSubCommand {
input: Option<String>,
#[clap(short = 'f', long, help = t!("args.file").to_string(), conflicts_with = "input")]
file: Option<String>,
#[clap(short = 'o', long, help = t!("args.outputFormat").to_string())]
output_format: Option<OutputFormat>,
#[clap(short = 'w', long, visible_aliases = ["dry-run", "noop"], help = t!("args.whatIf").to_string())]
what_if: bool,
},
#[clap(name = "schema", about = "Get the JSON schema for a resource", arg_required_else_help = true)]
Schema {
Expand Down
29 changes: 24 additions & 5 deletions dsc/src/resource_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ use crate::util::{EXIT_DSC_ERROR, EXIT_INVALID_ARGS, EXIT_JSON_ERROR, EXIT_DSC_R
use dsc_lib::configure::config_doc::{Configuration, ExecutionKind};
use dsc_lib::configure::add_resource_export_results_to_configuration;
use dsc_lib::discovery::discovery_trait::DiscoveryFilter;
use dsc_lib::dscresources::{resource_manifest::Kind, invoke_result::{GetResult, ResourceGetResponse, ResourceSetResponse, SetResult}};
use dsc_lib::dscresources::{resource_manifest::Kind, invoke_result::{DeleteResultKind, 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 tracing::{debug, error, info};

use dsc_lib::{
dscresources::dscresource::{Invoke, DscResource},
Expand Down Expand Up @@ -258,7 +258,7 @@ pub fn test(dsc: &mut DscManager, resource_type: &str, version: Option<&str>, in
}
}

pub fn delete(dsc: &mut DscManager, resource_type: &str, version: Option<&str>, input: &str) {
pub fn delete(dsc: &mut DscManager, resource_type: &str, version: Option<&str>, input: &str, format: Option<&OutputFormat>, what_if: bool) {
let Some(resource) = get_resource(dsc, resource_type, version) else {
error!("{}", DscError::ResourceNotFound(resource_type.to_string(), version.unwrap_or("").to_string()).to_string());
exit(EXIT_DSC_RESOURCE_NOT_FOUND);
Expand All @@ -270,8 +270,27 @@ pub fn delete(dsc: &mut DscManager, resource_type: &str, version: Option<&str>,
exit(EXIT_DSC_ERROR);
}

match resource.delete(input, &ExecutionKind::Actual) {
Ok(_) => {}
let execution_kind = if what_if { ExecutionKind::WhatIf } else { ExecutionKind::Actual };

match resource.delete(input, &execution_kind) {
Ok(result) => {
match result {
DeleteResultKind::ResourceActual => {
},
DeleteResultKind::ResourceWhatIf(delete_result) => {
match serde_json::to_string(&delete_result) {
Ok(json) => write_object(&json, format, false),
Err(err) => {
error!("JSON: {err}");
exit(EXIT_JSON_ERROR);
}
}
},
DeleteResultKind::SyntheticWhatIf(_) => {
info!("{} {}", resource.type_name, t!("resource_command.syntheticWhatIf"));
}
}
},
Err(err) => {
error!("{err}");
exit(EXIT_DSC_ERROR);
Expand Down
4 changes: 2 additions & 2 deletions dsc/src/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,13 +595,13 @@ pub fn resource(subcommand: &ResourceSubCommand, progress_format: ProgressFormat
let parsed_input = get_input(input.as_ref(), path.as_ref());
resource_command::test(&mut dsc, resource, version.as_deref(), &parsed_input, output_format.as_ref());
},
ResourceSubCommand::Delete { resource, version, input, file: path } => {
ResourceSubCommand::Delete { resource, version, input, file: path, output_format, what_if } => {
if let Err(err) = dsc.find_resources(&[DiscoveryFilter::new(resource, version.as_deref(), None)], progress_format) {
error!("{}: {err}", t!("subcommand.failedDiscoverResource"));
exit(EXIT_DSC_ERROR);
}
let parsed_input = get_input(input.as_ref(), path.as_ref());
resource_command::delete(&mut dsc, resource, version.as_deref(), &parsed_input);
resource_command::delete(&mut dsc, resource, version.as_deref(), &parsed_input, output_format.as_ref(), *what_if);
},
}
}
Expand Down
15 changes: 15 additions & 0 deletions dsc/tests/dsc_whatif.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,21 @@ Describe 'whatif tests' {
$out.metadata.'Microsoft.DSC'.executionType | Should -BeExactly 'whatIf'
}

It 'dsc resource delete supports what-if flag' {
$result = dsc resource delete -r Test/WhatIfDelete -i '{"_exist": false}' --what-if | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0
$result._metadata.whatIf | Should -Not -BeNullOrEmpty
$result._metadata.whatIf | Should -Contain 'Delete what-if message 1'
$result._metadata.whatIf | Should -Contain 'Delete what-if message 2'
}

It 'dsc resource delete synthetic what-if logs info message and produces no output' {
$result = dsc -l info resource delete -r Test/Delete -i '{"_exist": false}' --what-if 2>&1
$LASTEXITCODE | Should -Be 0
"$result" | Should -Match 'generate synthetic what-if'
"$result" | Should -Not -Match '^\s*\{'
}

It 'Test/WhatIfReturnDiff resource returns state and diff in what-if mode' {
$config_yaml = @"
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
Expand Down
Loading