Skip to content

Commit 0cd3fd7

Browse files
committed
add resource support for what-if through additional parameter during config set
1 parent f7ef3cb commit 0cd3fd7

File tree

8 files changed

+125
-5
lines changed

8 files changed

+125
-5
lines changed

dsc/tests/dsc_whatif.tests.ps1

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,40 @@ Describe 'whatif tests' {
6767
$result | Should -Match 'ERROR.*?Not implemented.*?what-if'
6868
$LASTEXITCODE | Should -Be 2
6969
}
70+
71+
It 'actual execution of WhatIf resource' {
72+
$config_yaml = @"
73+
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
74+
resources:
75+
- name: WhatIf
76+
type: Test/WhatIf
77+
properties:
78+
executionType: Actual
79+
"@
80+
$result = $config_yaml | dsc config set | ConvertFrom-Json
81+
$result.metadata.'Microsoft.DSC'.executionType | Should -BeExactly 'Actual'
82+
$result.results.result.afterState.executionType | Should -BeExactly 'Actual'
83+
$result.results.result.changedProperties | Should -Be $null
84+
$result.hadErrors | Should -BeFalse
85+
$result.results.Count | Should -Be 1
86+
$LASTEXITCODE | Should -Be 0
87+
}
88+
89+
It 'what-if execution of WhatIf resource' {
90+
$config_yaml = @"
91+
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
92+
resources:
93+
- name: WhatIf
94+
type: Test/WhatIf
95+
properties:
96+
executionType: Actual
97+
"@
98+
$result = $config_yaml | dsc config set -w | ConvertFrom-Json
99+
$result.metadata.'Microsoft.DSC'.executionType | Should -BeExactly 'WhatIf'
100+
$result.results.result.afterState.executionType | Should -BeExactly 'WhatIf'
101+
$result.results.result.changedProperties | Should -BeExactly 'executionType'
102+
$result.hadErrors | Should -BeFalse
103+
$result.results.Count | Should -Be 1
104+
$LASTEXITCODE | Should -Be 0
105+
}
70106
}

dsc_lib/src/dscresources/command_resource.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ pub fn invoke_set(resource: &ResourceManifest, cwd: &str, desired: &str, skip_te
105105
if !skip_test && set.pre_test != Some(true) {
106106
info!("No pretest, invoking test {}", &resource.resource_type);
107107
let test_result = invoke_test(resource, cwd, desired)?;
108-
if execution_type == &ExecutionKind::WhatIf {
108+
if execution_type == &ExecutionKind::WhatIf && set.handles_what_if != Some(true) {
109109
return Ok(test_result.into());
110110
}
111111
let (in_desired_state, actual_state) = match test_result {
@@ -130,9 +130,8 @@ pub fn invoke_set(resource: &ResourceManifest, cwd: &str, desired: &str, skip_te
130130
}
131131
}
132132

133-
if ExecutionKind::WhatIf == *execution_type {
134-
// TODO: continue execution when resources can implement what-if; only return an error here temporarily
135-
return Err(DscError::NotImplemented("what-if not yet supported for resources that implement pre-test".to_string()));
133+
if ExecutionKind::WhatIf == *execution_type && set.handles_what_if != Some(true) {
134+
return Err(DscError::NotImplemented("cannot process what-if execution type, resource does not implement what-if or pre-test".to_string()));
136135
}
137136

138137
let Some(get) = &resource.get else {
@@ -158,7 +157,16 @@ pub fn invoke_set(resource: &ResourceManifest, cwd: &str, desired: &str, skip_te
158157

159158
let mut env: Option<HashMap<String, String>> = None;
160159
let mut input_desired: Option<&str> = None;
161-
let args = process_args(&set.args, desired);
160+
let mut args = process_args(&set.args, desired);
161+
if ExecutionKind::WhatIf == *execution_type {
162+
if let Some(mut arguments) = args {
163+
arguments.push("--what-if".to_string());
164+
args = Some(arguments);
165+
}
166+
else {
167+
args = Some(vec!["--what-if".to_string()]);
168+
}
169+
}
162170
match &set.input {
163171
Some(InputKind::Env) => {
164172
env = Some(json_to_hashmap(desired)?);

dsc_lib/src/dscresources/dscresource.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ pub enum Capability {
5050
Set,
5151
/// The resource supports the `_exist` property directly.
5252
SetHandlesExist,
53+
/// The resource supports the `what-if` execution type directly.
54+
SetHandlesWhatIf,
5355
/// The resource supports validating configuration.
5456
Test,
5557
/// The resource supports deleting configuration.

dsc_lib/src/dscresources/resource_manifest.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ pub struct SetMethod {
171171
/// Indicates that the resource directly handles `_exist` as a property.
172172
#[serde(rename = "handlesExist", skip_serializing_if = "Option::is_none")]
173173
pub handles_exist: Option<bool>,
174+
/// Indicates that the resource directly handles `what-if` execution type.
175+
#[serde(rename = "handlesWhatIf", skip_serializing_if = "Option::is_none")]
176+
pub handles_what_if: Option<bool>,
174177
/// The type of return value expected from the Set method.
175178
#[serde(rename = "return", skip_serializing_if = "Option::is_none")]
176179
pub returns: Option<ReturnKind>,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/bundled/resource/manifest.json",
3+
"type": "Test/WhatIf",
4+
"version": "0.1.0",
5+
"get": {
6+
"executable": "dsctest",
7+
"args": [
8+
"what-if"
9+
]
10+
},
11+
"set": {
12+
"executable": "dsctest",
13+
"args": [
14+
"what-if"
15+
],
16+
"handlesWhatIf": true,
17+
"implementsPretest": true,
18+
"return": "state"
19+
},
20+
"schema": {
21+
"command": {
22+
"executable": "dsctest",
23+
"args": [
24+
"schema",
25+
"-s",
26+
"what-if"
27+
]
28+
}
29+
}
30+
}

tools/dsctest/src/args.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub enum Schemas {
1010
Exist,
1111
Sleep,
1212
Trace,
13+
WhatIf,
1314
}
1415

1516
#[derive(Debug, Parser)]
@@ -54,4 +55,10 @@ pub enum SubCommand {
5455

5556
#[clap(name = "trace", about = "The trace level")]
5657
Trace,
58+
59+
#[clap(name = "what-if", about = "Check if it is a what-if operation")]
60+
WhatIf {
61+
#[clap(name = "what-if", short, long, help = "The input to the what-if command as JSON")]
62+
what_if: bool,
63+
}
5764
}

tools/dsctest/src/main.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod echo;
77
mod exist;
88
mod sleep;
99
mod trace;
10+
mod whatif;
1011

1112
use args::{Args, Schemas, SubCommand};
1213
use clap::Parser;
@@ -16,6 +17,7 @@ use crate::echo::Echo;
1617
use crate::exist::{Exist, State};
1718
use crate::sleep::Sleep;
1819
use crate::trace::Trace;
20+
use crate::whatif::WhatIf;
1921
use std::{thread, time::Duration};
2022

2123
fn main() {
@@ -75,6 +77,9 @@ fn main() {
7577
Schemas::Trace => {
7678
schema_for!(Trace)
7779
},
80+
Schemas::WhatIf => {
81+
schema_for!(WhatIf)
82+
},
7883
};
7984
serde_json::to_string(&schema).unwrap()
8085
},
@@ -100,6 +105,14 @@ fn main() {
100105
};
101106
serde_json::to_string(&trace).unwrap()
102107
},
108+
SubCommand::WhatIf { what_if } => {
109+
let result: WhatIf = if what_if {
110+
WhatIf { execution_type: "WhatIf".to_string() }
111+
} else {
112+
WhatIf { execution_type: "Actual".to_string() }
113+
};
114+
serde_json::to_string(&result).unwrap()
115+
},
103116
};
104117

105118
println!("{json}");

tools/dsctest/src/whatif.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
use schemars::JsonSchema;
5+
use serde::{Deserialize, Serialize};
6+
7+
// #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
8+
// #[serde(untagged)]
9+
// pub enum ExecutionKind {
10+
// #[serde(rename = "actual")]
11+
// Actual,
12+
// #[serde(rename = "whatIf")]
13+
// WhatIf,
14+
// }
15+
16+
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
17+
#[serde(deny_unknown_fields)]
18+
pub struct WhatIf {
19+
#[serde(rename = "executionType")]
20+
pub execution_type: String,
21+
}

0 commit comments

Comments
 (0)