Skip to content

Commit 2d37234

Browse files
authored
Add support to pass resource version to adapter (#1645)
* Add support to pass resource version to adapter * expand tests to include all operations * add version check to test adapter operations * fix clippy * fix test resource and tests
1 parent ed39a15 commit 2d37234

7 files changed

Lines changed: 136 additions & 10 deletions

File tree

dsc/tests/dsc_adapter.tests.ps1

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,67 @@ Describe 'Tests for adapter support' {
9898
}
9999
}
100100

101+
It 'Specifying adapted resource version succeeds for <operation>' -TestCases @(
102+
@{ operation = 'get' },
103+
@{ operation = 'set' },
104+
@{ operation = 'test' },
105+
@{ operation = 'export' }
106+
){
107+
param($operation)
108+
109+
$config_yaml = @"
110+
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
111+
resources:
112+
- name: Test
113+
type: Adapted/One
114+
requireVersion: =1.0.0
115+
properties:
116+
one: '1'
117+
"@
118+
$out = dsc config $operation -i $config_yaml 2>$TestDrive/error.log | ConvertFrom-Json -Depth 10
119+
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log | Out-String)
120+
switch ($operation) {
121+
'get' {
122+
$out.results[0].result.actualState.one | Should -BeExactly 'value1'
123+
}
124+
'set' {
125+
$out.results[0].result.afterState.one | Should -BeExactly 'value1'
126+
}
127+
'test' {
128+
$out.results[0].result.actualState.one | Should -BeExactly 'value1'
129+
$out.results[0].result.inDesiredState | Should -BeFalse
130+
$out.results[0].result.differingProperties | Should -Be @('one')
131+
}
132+
'export' {
133+
$out.resources[0].properties.one | Should -BeExactly 'first1'
134+
$out.resources[1].properties.one | Should -BeExactly 'second1'
135+
}
136+
}
137+
}
138+
139+
It 'Specifying invalid adapted resource version fails for <operation>' -TestCases @(
140+
@{ operation = 'get' },
141+
@{ operation = 'set' },
142+
@{ operation = 'test' },
143+
@{ operation = 'export' }
144+
){
145+
param($operation)
146+
147+
$config_yaml = @"
148+
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
149+
resources:
150+
- name: Test
151+
type: Adapted/One
152+
requireVersion: =2.0.0
153+
properties:
154+
one: '1'
155+
"@
156+
$out = dsc config $operation -i $config_yaml 2>$TestDrive/error.log
157+
$LASTEXITCODE | Should -Be 2 -Because (Get-Content $TestDrive/error.log | Out-String)
158+
$errorContent = Get-Content $TestDrive/error.log -Raw
159+
$errorContent | Should -Match "Resource not found: Adapted/One =2.0.0" -Because $errorContent
160+
$out | Should -BeNullOrEmpty -Because $errorContent
161+
}
101162

102163
It 'Specifying invalid adapter via metadata fails' {
103164
$config_yaml = @"
@@ -183,7 +244,7 @@ Describe 'Tests for adapter support' {
183244
$out = dsc -l trace resource set -r Adapted/Two -i '{"two":"2"}' 2>$TestDrive/error.log | ConvertFrom-Json -Depth 10
184245
$errorLog = Get-Content $TestDrive/error.log -Raw
185246
$LASTEXITCODE | Should -Be 0 -Because $errorLog
186-
$errorLog | Should -BeLike '*Invoking command ''dsctest'' with args Some(`["adapter", "--operation", "set", "--input", "{\"two\":\"2\"}", "--resource-type", "Adapted/Two", "--resource-path", "\"*adaptedTest.dsc.adaptedResource.json\""`])*' -Because $errorLog
247+
$errorLog | Should -BeLike '*Invoking command ''dsctest'' with args Some(`["adapter", "--operation", "set", "--input", "{\"two\":\"2\"}", "--resource-type", "Adapted/Two", "--resource-path", "\"*adaptedTest.dsc.adaptedResource.json\"", "--resource-version", "2.0.0"`])*' -Because $errorLog
187248
$out.afterState.two | Should -BeExactly 'value2' -Because $errorLog
188249
}
189250

lib/dsc-lib/src/dscresources/command_resource.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,10 @@ pub fn process_get_args(args: Option<&Vec<GetArgKind>>, input: &str, resource: &
10041004
processed_args.push(resource_type_arg.clone());
10051005
processed_args.push(resource.type_name.to_string());
10061006
},
1007+
GetArgKind::ResourceVersion { resource_version_arg } => {
1008+
processed_args.push(resource_version_arg.clone());
1009+
processed_args.push(resource.version.to_string());
1010+
},
10071011
GetArgKind::ResourcePath { resource_path_arg, include_quotes} => {
10081012
processed_args.push(resource_path_arg.clone());
10091013
if *include_quotes {
@@ -1034,6 +1038,10 @@ fn process_schema_args(args: Option<&Vec<SchemaArgKind>>, command_resource: &Dsc
10341038
processed_args.push(resource_type_arg.clone());
10351039
processed_args.push(command_resource.type_name.to_string());
10361040
},
1041+
SchemaArgKind::ResourceVersion { resource_version_arg } => {
1042+
processed_args.push(resource_version_arg.clone());
1043+
processed_args.push(command_resource.version.to_string());
1044+
},
10371045
}
10381046
}
10391047

@@ -1091,6 +1099,10 @@ fn process_set_delete_args(args: Option<&Vec<SetDeleteArgKind>>, input: &str, re
10911099
processed_args.push(resource_type_arg.clone());
10921100
processed_args.push(resource.type_name.to_string());
10931101
},
1102+
SetDeleteArgKind::ResourceVersion { resource_version_arg } => {
1103+
processed_args.push(resource_version_arg.clone());
1104+
processed_args.push(resource.version.to_string());
1105+
},
10941106
SetDeleteArgKind::WhatIf { what_if_arg } => {
10951107
supports_whatif = true;
10961108
if execution_type == &ExecutionKind::WhatIf {

lib/dsc-lib/src/dscresources/resource_manifest.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ pub enum GetArgKind {
129129
/// The argument that accepts the resource type name.
130130
resource_type_arg: String,
131131
},
132+
#[serde(rename_all = "camelCase")]
133+
ResourceVersion {
134+
/// The argument that accepts the resource version.
135+
resource_version_arg: String,
136+
},
132137
}
133138

134139
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)]
@@ -162,6 +167,11 @@ pub enum SetDeleteArgKind {
162167
/// The argument that accepts the resource type name.
163168
resource_type_arg: String,
164169
},
170+
#[serde(rename_all = "camelCase")]
171+
ResourceVersion {
172+
/// The argument that accepts the resource version.
173+
resource_version_arg: String,
174+
},
165175
/// The argument is passed when the resource is invoked in what-if mode.
166176
#[serde(rename_all = "camelCase")]
167177
WhatIf {
@@ -176,11 +186,16 @@ pub enum SetDeleteArgKind {
176186
pub enum SchemaArgKind {
177187
/// The argument is a string.
178188
String(String),
189+
#[serde(rename_all = "camelCase")]
179190
ResourceType {
180191
/// The argument that accepts the resource type name.
181-
#[serde(rename = "resourceTypeArg")]
182192
resource_type_arg: String,
183193
},
194+
#[serde(rename_all = "camelCase")]
195+
ResourceVersion {
196+
/// The argument that accepts the resource version.
197+
resource_version_arg: String,
198+
},
184199
}
185200

186201
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)]

tools/dsctest/dsctest.dsc.manifests.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/adaptedresource/manifest.json",
55
"type": "Adapted/Two",
66
"kind": "resource",
7-
"version": "1.0.0",
7+
"version": "2.0.0",
88
"capabilities": [
99
"get",
1010
"set",
@@ -985,6 +985,9 @@
985985
},
986986
{
987987
"resourcePathArg": "--resource-path"
988+
},
989+
{
990+
"resourceVersionArg": "--resource-version"
988991
}
989992
]
990993
},
@@ -1004,7 +1007,11 @@
10041007
{
10051008
"resourcePathArg": "--resource-path",
10061009
"includeQuotes": true
1010+
},
1011+
{
1012+
"resourceVersionArg": "--resource-version"
10071013
}
1014+
10081015
]
10091016
},
10101017
"test": {
@@ -1019,7 +1026,11 @@
10191026
},
10201027
{
10211028
"resourceTypeArg": "--resource-type"
1029+
},
1030+
{
1031+
"resourceVersionArg": "--resource-version"
10221032
}
1033+
10231034
]
10241035
},
10251036
"export": {
@@ -1034,6 +1045,9 @@
10341045
},
10351046
{
10361047
"resourceTypeArg": "--resource-type"
1048+
},
1049+
{
1050+
"resourceVersionArg": "--resource-version"
10371051
}
10381052
]
10391053
},

tools/dsctest/src/adapter.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,28 @@ use crate::args::AdapterOperation;
88

99
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
1010
#[serde(deny_unknown_fields)]
11-
pub struct AdaptedOne {
11+
struct AdaptedOne {
1212
pub one: String,
1313
#[serde(rename = "_name", skip_serializing_if = "Option::is_none")]
1414
pub name: Option<String>,
1515
#[serde(skip_serializing_if = "Option::is_none")]
1616
pub path: Option<String>,
1717
}
1818

19+
const ADAPTED_ONE_VERSION: &str = "1.0.0";
20+
1921
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
2022
#[serde(deny_unknown_fields)]
21-
pub struct AdaptedTwo {
23+
struct AdaptedTwo {
2224
pub two: String,
2325
#[serde(rename = "_name", skip_serializing_if = "Option::is_none")]
2426
pub name: Option<String>,
2527
#[serde(skip_serializing_if = "Option::is_none")]
2628
pub path: Option<String>,
2729
}
2830

31+
const ADAPTED_TWO_VERSION: &str = "2.0.0";
32+
2933
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
3034
#[serde(deny_unknown_fields)]
3135
pub struct DscResource {
@@ -52,13 +56,13 @@ pub struct DscResource {
5256
pub require_adapter: Option<String>,
5357
}
5458

55-
pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, resource_path: &Option<String>) -> Result<String, String> {
59+
pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, resource_path: &Option<String>, resource_version: &Option<String>) -> Result<String, String> {
5660
match operation {
5761
AdapterOperation::List => {
5862
let resource_one = DscResource {
5963
type_name: "Adapted/One".to_string(),
6064
kind: "resource".to_string(),
61-
version: "1.0.0".to_string(),
65+
version: ADAPTED_ONE_VERSION.to_string(),
6266
capabilities: vec!["get".to_string(), "set".to_string(), "test".to_string(), "export".to_string()],
6367
path: "path/to/adapted/one".to_string(),
6468
directory: "path/to/adapted".to_string(),
@@ -69,7 +73,7 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
6973
let resource_two = DscResource {
7074
type_name: "Adapted/Two".to_string(),
7175
kind: "resource".to_string(),
72-
version: "1.0.0".to_string(),
76+
version: ADAPTED_TWO_VERSION.to_string(),
7377
capabilities: vec!["get".to_string(), "set".to_string(), "test".to_string(), "export".to_string()],
7478
path: "path/to/adapted/two".to_string(),
7579
directory: "path/to/adapted".to_string(),
@@ -84,6 +88,9 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
8488
AdapterOperation::Get => {
8589
match resource_type {
8690
"Adapted/One" => {
91+
if let Some(version) = resource_version && version != ADAPTED_ONE_VERSION {
92+
return Err(format!("Unsupported version for Adapted/One: {version}"));
93+
}
8794
let adapted_one = AdaptedOne {
8895
one: "value1".to_string(),
8996
name: None,
@@ -92,6 +99,9 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
9299
Ok(serde_json::to_string(&adapted_one).unwrap())
93100
},
94101
"Adapted/Two" => {
102+
if let Some(version) = resource_version && version != ADAPTED_TWO_VERSION {
103+
return Err(format!("Unsupported version for Adapted/Two: {version}"));
104+
}
95105
let adapted_two = AdaptedTwo {
96106
two: "value2".to_string(),
97107
name: None,
@@ -121,11 +131,17 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
121131
AdapterOperation::Set | AdapterOperation::Test => {
122132
match resource_type {
123133
"Adapted/One" => {
134+
if let Some(version) = resource_version && version != ADAPTED_ONE_VERSION {
135+
return Err(format!("Unsupported version for {resource_type}: {version}"));
136+
}
124137
let adapted_one: AdaptedOne = serde_json::from_str(input)
125138
.map_err(|e| format!("Failed to parse input for Adapted/One: {e}"))?;
126139
Ok(serde_json::to_string(&adapted_one).unwrap())
127140
},
128141
"Adapted/Two" => {
142+
if let Some(version) = resource_version && version != ADAPTED_TWO_VERSION {
143+
return Err(format!("Unsupported version for {resource_type}: {version}"));
144+
}
129145
let adapted_two: AdaptedTwo = serde_json::from_str(input)
130146
.map_err(|e| format!("Failed to parse input for Adapted/Two: {e}"))?;
131147
Ok(serde_json::to_string(&adapted_two).unwrap())
@@ -141,6 +157,9 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
141157
AdapterOperation::Export => {
142158
match resource_type {
143159
"Adapted/One" => {
160+
if let Some(version) = resource_version && version != ADAPTED_ONE_VERSION {
161+
return Err(format!("Unsupported version for {resource_type}: {version}"));
162+
}
144163
let adapted_one = AdaptedOne {
145164
one: "first1".to_string(),
146165
name: Some("first".to_string()),
@@ -156,6 +175,9 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
156175
std::process::exit(0);
157176
},
158177
"Adapted/Two" => {
178+
if let Some(version) = resource_version && version != ADAPTED_TWO_VERSION {
179+
return Err(format!("Unsupported version for {resource_type}: {version}"));
180+
}
159181
let adapted_two = AdaptedTwo {
160182
two: "first2".to_string(),
161183
name: Some("first".to_string()),

tools/dsctest/src/args.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ pub enum SubCommand {
6464
resource_type: String,
6565
#[clap(name = "resource-path", long, help = "The path to the adapted resource")]
6666
resource_path: Option<String>,
67+
#[clap(name = "resource-version", long, help = "The version of the adapted resource")]
68+
resource_version: Option<String>,
6769
#[clap(name = "operation", short, long, help = "The operation to perform")]
6870
operation: AdapterOperation,
6971
},

tools/dsctest/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ use std::{thread, time::Duration};
5454
fn main() {
5555
let args = Args::parse();
5656
let json = match args.subcommand {
57-
SubCommand::Adapter { input , resource_type, resource_path, operation } => {
58-
match adapter::adapt(&resource_type, &input, &operation, &resource_path) {
57+
SubCommand::Adapter { input , resource_type, resource_path, resource_version, operation } => {
58+
match adapter::adapt(&resource_type, &input, &operation, &resource_path, &resource_version) {
5959
Ok(result) => result,
6060
Err(err) => {
6161
eprintln!("Error adapting resource: {err}");

0 commit comments

Comments
 (0)