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
63 changes: 62 additions & 1 deletion dsc/tests/dsc_adapter.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,67 @@ Describe 'Tests for adapter support' {
}
}

It 'Specifying adapted resource version succeeds for <operation>' -TestCases @(
@{ operation = 'get' },
@{ operation = 'set' },
@{ operation = 'test' },
@{ operation = 'export' }
){
param($operation)

$config_yaml = @"
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
resources:
- name: Test
type: Adapted/One
requireVersion: =1.0.0
properties:
one: '1'
"@
$out = dsc config $operation -i $config_yaml 2>$TestDrive/error.log | ConvertFrom-Json -Depth 10
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log | Out-String)
switch ($operation) {
'get' {
$out.results[0].result.actualState.one | Should -BeExactly 'value1'
}
'set' {
$out.results[0].result.afterState.one | Should -BeExactly 'value1'
}
'test' {
$out.results[0].result.actualState.one | Should -BeExactly 'value1'
$out.results[0].result.inDesiredState | Should -BeFalse
$out.results[0].result.differingProperties | Should -Be @('one')
}
'export' {
$out.resources[0].properties.one | Should -BeExactly 'first1'
$out.resources[1].properties.one | Should -BeExactly 'second1'
}
}
}

It 'Specifying invalid adapted resource version fails for <operation>' -TestCases @(
@{ operation = 'get' },
@{ operation = 'set' },
@{ operation = 'test' },
@{ operation = 'export' }
){
param($operation)

$config_yaml = @"
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
resources:
- name: Test
type: Adapted/One
requireVersion: =2.0.0
properties:
one: '1'
"@
$out = dsc config $operation -i $config_yaml 2>$TestDrive/error.log
$LASTEXITCODE | Should -Be 2 -Because (Get-Content $TestDrive/error.log | Out-String)
$errorContent = Get-Content $TestDrive/error.log -Raw
$errorContent | Should -Match "Resource not found: Adapted/One =2.0.0" -Because $errorContent
$out | Should -BeNullOrEmpty -Because $errorContent
}

It 'Specifying invalid adapter via metadata fails' {
$config_yaml = @"
Expand Down Expand Up @@ -183,7 +244,7 @@ Describe 'Tests for adapter support' {
$out = dsc -l trace resource set -r Adapted/Two -i '{"two":"2"}' 2>$TestDrive/error.log | ConvertFrom-Json -Depth 10
$errorLog = Get-Content $TestDrive/error.log -Raw
$LASTEXITCODE | Should -Be 0 -Because $errorLog
$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
$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
$out.afterState.two | Should -BeExactly 'value2' -Because $errorLog
}

Expand Down
12 changes: 12 additions & 0 deletions lib/dsc-lib/src/dscresources/command_resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,10 @@ pub fn process_get_args(args: Option<&Vec<GetArgKind>>, input: &str, resource: &
processed_args.push(resource_type_arg.clone());
processed_args.push(resource.type_name.to_string());
},
GetArgKind::ResourceVersion { resource_version_arg } => {
processed_args.push(resource_version_arg.clone());
processed_args.push(resource.version.to_string());
},
GetArgKind::ResourcePath { resource_path_arg, include_quotes} => {
processed_args.push(resource_path_arg.clone());
if *include_quotes {
Expand Down Expand Up @@ -1034,6 +1038,10 @@ fn process_schema_args(args: Option<&Vec<SchemaArgKind>>, command_resource: &Dsc
processed_args.push(resource_type_arg.clone());
processed_args.push(command_resource.type_name.to_string());
},
SchemaArgKind::ResourceVersion { resource_version_arg } => {
processed_args.push(resource_version_arg.clone());
processed_args.push(command_resource.version.to_string());
},
}
}

Expand Down Expand Up @@ -1091,6 +1099,10 @@ fn process_set_delete_args(args: Option<&Vec<SetDeleteArgKind>>, input: &str, re
processed_args.push(resource_type_arg.clone());
processed_args.push(resource.type_name.to_string());
},
SetDeleteArgKind::ResourceVersion { resource_version_arg } => {
processed_args.push(resource_version_arg.clone());
processed_args.push(resource.version.to_string());
},
SetDeleteArgKind::WhatIf { what_if_arg } => {
supports_whatif = true;
if execution_type == &ExecutionKind::WhatIf {
Expand Down
17 changes: 16 additions & 1 deletion lib/dsc-lib/src/dscresources/resource_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ pub enum GetArgKind {
/// The argument that accepts the resource type name.
resource_type_arg: String,
},
#[serde(rename_all = "camelCase")]
ResourceVersion {
/// The argument that accepts the resource version.
resource_version_arg: String,
},
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)]
Expand Down Expand Up @@ -162,6 +167,11 @@ pub enum SetDeleteArgKind {
/// The argument that accepts the resource type name.
resource_type_arg: String,
},
#[serde(rename_all = "camelCase")]
ResourceVersion {
/// The argument that accepts the resource version.
resource_version_arg: String,
},
/// The argument is passed when the resource is invoked in what-if mode.
#[serde(rename_all = "camelCase")]
WhatIf {
Expand All @@ -176,11 +186,16 @@ pub enum SetDeleteArgKind {
pub enum SchemaArgKind {
/// The argument is a string.
String(String),
#[serde(rename_all = "camelCase")]
ResourceType {
/// The argument that accepts the resource type name.
#[serde(rename = "resourceTypeArg")]
resource_type_arg: String,
},
#[serde(rename_all = "camelCase")]
ResourceVersion {
/// The argument that accepts the resource version.
resource_version_arg: String,
},
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)]
Expand Down
16 changes: 15 additions & 1 deletion tools/dsctest/dsctest.dsc.manifests.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/adaptedresource/manifest.json",
"type": "Adapted/Two",
"kind": "resource",
"version": "1.0.0",
"version": "2.0.0",
"capabilities": [
"get",
"set",
Expand Down Expand Up @@ -985,6 +985,9 @@
},
{
"resourcePathArg": "--resource-path"
},
{
"resourceVersionArg": "--resource-version"
}
]
},
Expand All @@ -1004,7 +1007,11 @@
{
"resourcePathArg": "--resource-path",
"includeQuotes": true
},
{
"resourceVersionArg": "--resource-version"
}
Comment thread
SteveL-MSFT marked this conversation as resolved.

]
},
"test": {
Expand All @@ -1019,7 +1026,11 @@
},
{
"resourceTypeArg": "--resource-type"
},
{
"resourceVersionArg": "--resource-version"
}

]
},
"export": {
Expand All @@ -1034,6 +1045,9 @@
},
{
"resourceTypeArg": "--resource-type"
},
{
"resourceVersionArg": "--resource-version"
}
]
},
Expand Down
32 changes: 27 additions & 5 deletions tools/dsctest/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,28 @@ use crate::args::AdapterOperation;

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct AdaptedOne {
struct AdaptedOne {
pub one: String,
#[serde(rename = "_name", skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
}

const ADAPTED_ONE_VERSION: &str = "1.0.0";

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct AdaptedTwo {
struct AdaptedTwo {
pub two: String,
#[serde(rename = "_name", skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
}

const ADAPTED_TWO_VERSION: &str = "2.0.0";

#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct DscResource {
Expand All @@ -52,13 +56,13 @@ pub struct DscResource {
pub require_adapter: Option<String>,
}

pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, resource_path: &Option<String>) -> Result<String, String> {
pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, resource_path: &Option<String>, resource_version: &Option<String>) -> Result<String, String> {
match operation {
Comment thread
SteveL-MSFT marked this conversation as resolved.
AdapterOperation::List => {
let resource_one = DscResource {
type_name: "Adapted/One".to_string(),
kind: "resource".to_string(),
version: "1.0.0".to_string(),
version: ADAPTED_ONE_VERSION.to_string(),
capabilities: vec!["get".to_string(), "set".to_string(), "test".to_string(), "export".to_string()],
path: "path/to/adapted/one".to_string(),
directory: "path/to/adapted".to_string(),
Expand All @@ -69,7 +73,7 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
let resource_two = DscResource {
type_name: "Adapted/Two".to_string(),
kind: "resource".to_string(),
version: "1.0.0".to_string(),
version: ADAPTED_TWO_VERSION.to_string(),
capabilities: vec!["get".to_string(), "set".to_string(), "test".to_string(), "export".to_string()],
path: "path/to/adapted/two".to_string(),
directory: "path/to/adapted".to_string(),
Expand All @@ -84,6 +88,9 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
AdapterOperation::Get => {
match resource_type {
"Adapted/One" => {
if let Some(version) = resource_version && version != ADAPTED_ONE_VERSION {
return Err(format!("Unsupported version for Adapted/One: {version}"));
}
let adapted_one = AdaptedOne {
one: "value1".to_string(),
name: None,
Expand All @@ -92,6 +99,9 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
Ok(serde_json::to_string(&adapted_one).unwrap())
},
"Adapted/Two" => {
if let Some(version) = resource_version && version != ADAPTED_TWO_VERSION {
return Err(format!("Unsupported version for Adapted/Two: {version}"));
}
let adapted_two = AdaptedTwo {
two: "value2".to_string(),
name: None,
Expand Down Expand Up @@ -121,11 +131,17 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
AdapterOperation::Set | AdapterOperation::Test => {
match resource_type {
"Adapted/One" => {
if let Some(version) = resource_version && version != ADAPTED_ONE_VERSION {
return Err(format!("Unsupported version for {resource_type}: {version}"));
}
let adapted_one: AdaptedOne = serde_json::from_str(input)
.map_err(|e| format!("Failed to parse input for Adapted/One: {e}"))?;
Ok(serde_json::to_string(&adapted_one).unwrap())
},
"Adapted/Two" => {
if let Some(version) = resource_version && version != ADAPTED_TWO_VERSION {
return Err(format!("Unsupported version for {resource_type}: {version}"));
}
let adapted_two: AdaptedTwo = serde_json::from_str(input)
.map_err(|e| format!("Failed to parse input for Adapted/Two: {e}"))?;
Ok(serde_json::to_string(&adapted_two).unwrap())
Expand All @@ -141,6 +157,9 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
AdapterOperation::Export => {
match resource_type {
"Adapted/One" => {
if let Some(version) = resource_version && version != ADAPTED_ONE_VERSION {
return Err(format!("Unsupported version for {resource_type}: {version}"));
}
let adapted_one = AdaptedOne {
one: "first1".to_string(),
name: Some("first".to_string()),
Expand All @@ -156,6 +175,9 @@ pub fn adapt(resource_type: &str, input: &str, operation: &AdapterOperation, res
std::process::exit(0);
},
"Adapted/Two" => {
if let Some(version) = resource_version && version != ADAPTED_TWO_VERSION {
return Err(format!("Unsupported version for {resource_type}: {version}"));
}
let adapted_two = AdaptedTwo {
two: "first2".to_string(),
name: Some("first".to_string()),
Expand Down
2 changes: 2 additions & 0 deletions tools/dsctest/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ pub enum SubCommand {
resource_type: String,
#[clap(name = "resource-path", long, help = "The path to the adapted resource")]
resource_path: Option<String>,
#[clap(name = "resource-version", long, help = "The version of the adapted resource")]
resource_version: Option<String>,
#[clap(name = "operation", short, long, help = "The operation to perform")]
operation: AdapterOperation,
},
Expand Down
4 changes: 2 additions & 2 deletions tools/dsctest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ use std::{thread, time::Duration};
fn main() {
let args = Args::parse();
let json = match args.subcommand {
SubCommand::Adapter { input , resource_type, resource_path, operation } => {
match adapter::adapt(&resource_type, &input, &operation, &resource_path) {
SubCommand::Adapter { input , resource_type, resource_path, resource_version, operation } => {
match adapter::adapt(&resource_type, &input, &operation, &resource_path, &resource_version) {
Ok(result) => result,
Err(err) => {
eprintln!("Error adapting resource: {err}");
Expand Down
Loading