From 5de7a3c2cefba8d9d26943b8c476e7b16bdb763e Mon Sep 17 00:00:00 2001 From: "tgauth@bu.edu" Date: Wed, 7 Feb 2024 14:34:49 -0500 Subject: [PATCH 1/4] add tests for yaml resource discovery --- dsc/tests/dsc_discovery.tests.ps1 | 46 ++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/dsc/tests/dsc_discovery.tests.ps1 b/dsc/tests/dsc_discovery.tests.ps1 index bee5efdb..0b99bf1d 100644 --- a/dsc/tests/dsc_discovery.tests.ps1 +++ b/dsc/tests/dsc_discovery.tests.ps1 @@ -2,6 +2,18 @@ # Licensed under the MIT License. Describe 'tests for resource discovery' { + BeforeAll { + $env:DSC_RESOURCE_PATH = $testdrive + } + + AfterEach { + Remove-Item -Path "$testdrive/test.dsc.resource.*" -ErrorAction SilentlyContinue + } + + AfterAll { + $env:DSC_RESOURCE_PATH = $null + } + It 'Use DSC_RESOURCE_PATH instead of PATH when defined' { $resourceJson = @' { @@ -14,15 +26,29 @@ Describe 'tests for resource discovery' { } '@ - try { - $env:DSC_RESOURCE_PATH = $testdrive - Set-Content -Path "$testdrive/test.dsc.resource.json" -Value $resourceJson - $resources = dsc resource list | ConvertFrom-Json - $resources.Count | Should -Be 1 - $resources.type | Should -BeExactly 'DSC/TestPathResource' - } - finally { - $env:DSC_RESOURCE_PATH = $null - } + Set-Content -Path "$testdrive/test.dsc.resource.json" -Value $resourceJson + $resources = dsc resource list | ConvertFrom-Json + $resources.Count | Should -Be 1 + $resources.type | Should -BeExactly 'DSC/TestPathResource' + } + + It 'support discovering ' -TestCases @( + @{ extension = 'yaml' } + @{ extension = 'yml' } + ) { + param($extension) + + $resourceYaml = @' + $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json + type: DSC/TestYamlResource + version: 0.1.0 + get: + executable: dsc +'@ + + Set-Content -Path "$testdrive/test.dsc.resource.$extension" -Value $resourceYaml + $resources = dsc resource list | ConvertFrom-Json + $resources.Count | Should -Be 1 + $resources.type | Should -BeExactly 'DSC/TestYamlResource' } } From bf9a2a97cd82fd75f2b23166ebe5d4c176d5c20a Mon Sep 17 00:00:00 2001 From: "tgauth@bu.edu" Date: Wed, 7 Feb 2024 14:35:04 -0500 Subject: [PATCH 2/4] update discovery to include yml/yaml extensions --- dsc_lib/Cargo.toml | 1 + dsc_lib/src/discovery/command_discovery.rs | 24 +++++++++++++++++----- dsc_lib/src/dscerror.rs | 3 +++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/dsc_lib/Cargo.toml b/dsc_lib/Cargo.toml index ad4c2f50..f32d78c4 100644 --- a/dsc_lib/Cargo.toml +++ b/dsc_lib/Cargo.toml @@ -12,6 +12,7 @@ reqwest = { version = "0.11", features = ["blocking"] } schemars = { version = "0.8.12", features = ["preserve_order"] } serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } +serde_yaml = { version = "0.9.3" } thiserror = "1.0" chrono = "0.4.26" tracing = "0.1.37" diff --git a/dsc_lib/src/discovery/command_discovery.rs b/dsc_lib/src/discovery/command_discovery.rs index a7a939c0..18e4e625 100644 --- a/dsc_lib/src/discovery/command_discovery.rs +++ b/dsc_lib/src/discovery/command_discovery.rs @@ -8,6 +8,7 @@ use crate::dscresources::command_resource::invoke_command; use crate::dscerror::DscError; use std::collections::BTreeMap; use std::env; +use std::ffi::OsStr; use std::fs::File; use std::io::BufReader; use std::path::Path; @@ -50,7 +51,9 @@ impl CommandDiscovery { let path = entry.path(); if path.is_file() { let file_name = path.file_name().unwrap().to_str().unwrap(); - if file_name.to_lowercase().ends_with(".dsc.resource.json") { + if file_name.to_lowercase().ends_with(".dsc.resource.json") | + file_name.to_lowercase().ends_with(".dsc.resource.yaml") | + file_name.to_lowercase().ends_with(".dsc.resource.yml") { let resource = match load_manifest(&path) { Ok(r) => r, @@ -203,12 +206,23 @@ impl ResourceDiscovery for CommandDiscovery { fn load_manifest(path: &Path) -> Result { let file = File::open(path)?; let reader = BufReader::new(file); - let manifest: ResourceManifest = match serde_json::from_reader(reader) { - Ok(manifest) => manifest, - Err(err) => { - return Err(DscError::Manifest(path.to_string_lossy().to_string(), err)); + let manifest: ResourceManifest = if path.extension() == Some(OsStr::new("json")) { + match serde_json::from_reader(reader) { + Ok(manifest) => manifest, + Err(err) => { + return Err(DscError::Manifest(path.to_string_lossy().to_string(), err)); + } + } + } + else { + match serde_yaml::from_reader(reader) { + Ok(manifest) => manifest, + Err(err) => { + return Err(DscError::ManifestYaml(path.to_string_lossy().to_string(), err)); + } } }; + let resource = DscResource { type_name: manifest.resource_type.clone(), implemented_as: ImplementedAs::Command, diff --git a/dsc_lib/src/dscerror.rs b/dsc_lib/src/dscerror.rs index b5bb1fdb..214be45f 100644 --- a/dsc_lib/src/dscerror.rs +++ b/dsc_lib/src/dscerror.rs @@ -52,6 +52,9 @@ pub enum DscError { #[error("Manifest: {0}\nJSON: {1}")] Manifest(String, serde_json::Error), + #[error("Manifest: {0}\nYAML: {1}")] + ManifestYaml(String, serde_yaml::Error), + #[error("Missing manifest: {0}")] MissingManifest(String), From c25cd5cd4b436d8865382f1eead95acc4b2f7142 Mon Sep 17 00:00:00 2001 From: "tgauth@bu.edu" Date: Wed, 7 Feb 2024 17:07:39 -0500 Subject: [PATCH 3/4] store lowercase filename in var --- dsc_lib/src/discovery/command_discovery.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dsc_lib/src/discovery/command_discovery.rs b/dsc_lib/src/discovery/command_discovery.rs index 18e4e625..7c2ec9d6 100644 --- a/dsc_lib/src/discovery/command_discovery.rs +++ b/dsc_lib/src/discovery/command_discovery.rs @@ -51,9 +51,10 @@ impl CommandDiscovery { let path = entry.path(); if path.is_file() { let file_name = path.file_name().unwrap().to_str().unwrap(); - if file_name.to_lowercase().ends_with(".dsc.resource.json") | - file_name.to_lowercase().ends_with(".dsc.resource.yaml") | - file_name.to_lowercase().ends_with(".dsc.resource.yml") { + let file_name_lowercase = file_name.to_lowercase(); + if file_name_lowercase.ends_with(".dsc.resource.json") | + file_name_lowercase.ends_with(".dsc.resource.yaml") | + file_name_lowercase.ends_with(".dsc.resource.yml") { let resource = match load_manifest(&path) { Ok(r) => r, From bd0bc514faef6640933cd11c9c3fa7e733b67788 Mon Sep 17 00:00:00 2001 From: "tgauth@bu.edu" Date: Thu, 8 Feb 2024 10:31:36 -0500 Subject: [PATCH 4/4] update if statement --- dsc/tests/dsc_discovery.tests.ps1 | 16 ++++++++++++++++ dsc_lib/src/discovery/command_discovery.rs | 6 +++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/dsc/tests/dsc_discovery.tests.ps1 b/dsc/tests/dsc_discovery.tests.ps1 index 0b99bf1d..8c1c4897 100644 --- a/dsc/tests/dsc_discovery.tests.ps1 +++ b/dsc/tests/dsc_discovery.tests.ps1 @@ -51,4 +51,20 @@ Describe 'tests for resource discovery' { $resources.Count | Should -Be 1 $resources.type | Should -BeExactly 'DSC/TestYamlResource' } + + It 'does not support discovering a file with an extension that is not json or yaml' { + param($extension) + + $resourceInput = @' + $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json + type: DSC/TestYamlResource + version: 0.1.0 + get: + executable: dsc +'@ + + Set-Content -Path "$testdrive/test.dsc.resource.txt" -Value $resourceInput + $resources = dsc resource list | ConvertFrom-Json + $resources.Count | Should -Be 0 + } } diff --git a/dsc_lib/src/discovery/command_discovery.rs b/dsc_lib/src/discovery/command_discovery.rs index 7c2ec9d6..5b13f4a5 100644 --- a/dsc_lib/src/discovery/command_discovery.rs +++ b/dsc_lib/src/discovery/command_discovery.rs @@ -52,9 +52,9 @@ impl CommandDiscovery { if path.is_file() { let file_name = path.file_name().unwrap().to_str().unwrap(); let file_name_lowercase = file_name.to_lowercase(); - if file_name_lowercase.ends_with(".dsc.resource.json") | - file_name_lowercase.ends_with(".dsc.resource.yaml") | - file_name_lowercase.ends_with(".dsc.resource.yml") { + if file_name_lowercase.ends_with(".dsc.resource.json") || + file_name_lowercase.ends_with(".dsc.resource.yaml") || + file_name_lowercase.ends_with(".dsc.resource.yml") { let resource = match load_manifest(&path) { Ok(r) => r,