diff --git a/dsc/tests/dsc_discovery.tests.ps1 b/dsc/tests/dsc_discovery.tests.ps1 index a6809ec60..8e7c42b64 100644 --- a/dsc/tests/dsc_discovery.tests.ps1 +++ b/dsc/tests/dsc_discovery.tests.ps1 @@ -342,4 +342,31 @@ Describe 'tests for resource discovery' { $traceLog | Should -Match "Skipping resource discovery due to 'resourceDiscovery' mode set to 'DuringDeployment'" } } + + It 'Invalid resource manifest will generate info message' { + $invalidManifest = @' + { + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Test/InvalidManifest", + "version": "0.1.0", + "get": { + "executable": "dsctest", + "unexpectedField": "This field is not expected in the get section and should be ignored by the discovery process" + }, + "newProperty": "This property is not expected in the manifest and should be ignored by the discovery process" + } +'@ + Set-Content -Path "$testdrive/test.dsc.resource.json" -Value $invalidManifest + try { + $env:DSC_RESOURCE_PATH = $testdrive + [System.IO.Path]::PathSeparator + $env:PATH + + $out = dsc -l info resource list 'Test/InvalidManifest' 2> "$testdrive/error.txt" | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out | Should -BeNullOrEmpty -Because (Get-Content -Raw -Path "$testdrive/error.txt") + $errorLog = Get-Content -Raw -Path "$testdrive/error.txt" + $errorLog | Should -BeLike "*INFO Failed to load manifest: Invalid manifest for resource '*test.dsc.resource.json'*" -Because $errorLog + } finally { + $env:DSC_RESOURCE_PATH = $null + } + } } diff --git a/dsc/tests/dsc_extension_discover.tests.ps1 b/dsc/tests/dsc_extension_discover.tests.ps1 index 2be1256db..6e3cd372c 100644 --- a/dsc/tests/dsc_extension_discover.tests.ps1 +++ b/dsc/tests/dsc_extension_discover.tests.ps1 @@ -148,4 +148,61 @@ Describe 'Discover extension tests' { $env:DSC_RESOURCE_PATH = $null } } + + It 'Invalid manifest from extension discovery should not fail overall discovery' { + $invalidManifest = @' + { + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Test/InvalidManifest", + "version": "0.1.0", + "get": { + "executable": "dsctest", + "unexpectedField": "This field is not expected in the get section and should be ignored by the discovery process" + }, + "newProperty": "This property is not expected in the manifest and should be ignored by the discovery process" + } +'@ + $resourceScript = @' + $resource = @{ + manifestPath = "$env:TestDrive" + [System.IO.Path]::DirectorySeparatorChar + 'invalidManifest.dsc.resource.json' + } + $resource | ConvertTo-Json -Compress +'@ + $extensionManifest = @' +{ + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Test/DiscoverInvalid", + "version": "0.1.0", + "description": "Test discover resource, this is a really long description to test that the table can be rendered without truncating the description text from this extension.", + "discover": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-Command", + "./discover.ps1" + ] + } +} +'@ + + Set-Content -Path "$TestDrive/invalidManifest.dsc.resource.json" -Value $invalidManifest + Set-Content -Path "$TestDrive/discover.ps1" -Value $resourceScript + Set-Content -Path "$TestDrive/extension.dsc.extension.json" -Value $extensionManifest + try { + $env:DSC_RESOURCE_PATH = $TestDrive + [System.IO.Path]::PathSeparator + $env:PATH + $env:TestDrive = $TestDrive + $out = dsc -l info resource list 2> $TestDrive/error.log | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 -Because (Get-Content -Path "$TestDrive/error.log" -Raw | Out-String) + # The invalid manifest should be skipped and not included in the discovered resources + foreach ($resource in $out) { + $resource.type | Should -Not -Be 'Test/InvalidManifest' + } + (Get-Content -Path "$TestDrive/error.log" -Raw) | Should -BeLike "*INFO Extension 'Test/DiscoverInvalid' failed to load manifest: Invalid manifest for resource '*invalidManifest.dsc.resource.json'*" -Because (Get-Content -Path "$TestDrive/error.log" -Raw | Out-String) + } finally { + $env:DSC_RESOURCE_PATH = $null + $env:TestDrive = $null + } + } } diff --git a/lib/dsc-lib/locales/en-us.toml b/lib/dsc-lib/locales/en-us.toml index 617aac17c..2fe07e7f8 100644 --- a/lib/dsc-lib/locales/en-us.toml +++ b/lib/dsc-lib/locales/en-us.toml @@ -140,6 +140,7 @@ conditionNotBoolean = "Condition '%{condition}' did not evaluate to a boolean" conditionNotMet = "Condition '%{condition}' not met, skipping manifest at '%{path}' for resource '%{resource}'" adaptedResourcePathNotFound = "Adapted resource '%{resource}' path not found: %{path}" invalidManifestFileName = "Invalid manifest file name '%{path}'" +failedLoadManifest = "Failed to load manifest: %{err}" [dscresources.commandResource] invokeGet = "Invoking get for '%{resource}'" @@ -252,6 +253,7 @@ importNoResults = "Extension '%{extension}' returned no results for import" secretMultipleLinesReturned = "Extension '%{extension}' returned multiple lines which is not supported for secrets" importProcessingOutput = "Processing output from extension '%{extension}'" deprecationMessage = "Extension '%{extension}' is deprecated: %{message}" +failedLoadManifest = "Extension '%{extension}' failed to load manifest: %{err}" [extensions.extension_manifest] extensionManifestSchemaTitle = "Extension manifest schema URI" diff --git a/lib/dsc-lib/src/discovery/command_discovery.rs b/lib/dsc-lib/src/discovery/command_discovery.rs index cdb899744..2baba3ac7 100644 --- a/lib/dsc-lib/src/discovery/command_discovery.rs +++ b/lib/dsc-lib/src/discovery/command_discovery.rs @@ -277,8 +277,8 @@ impl ResourceDiscovery for CommandDiscovery { // At this point we can't determine whether or not the bad manifest contains // resource that is requested by resource/config operation // if it is, then "ResouceNotFound" error will be issued later - // and here we just write as warning - warn!("{e}"); + // and here we just write as info + info!("{}", t!("discovery.commandDiscovery.failedLoadManifest", err = e)); continue; }, }; diff --git a/lib/dsc-lib/src/extensions/discover.rs b/lib/dsc-lib/src/extensions/discover.rs index 42549328b..4b017ae3f 100644 --- a/lib/dsc-lib/src/extensions/discover.rs +++ b/lib/dsc-lib/src/extensions/discover.rs @@ -99,7 +99,14 @@ impl DscExtension { return Err(DscError::Extension(t!("extensions.dscextension.discoverNotAbsolutePath", extension = self.type_name.clone(), path = discover_result.manifest_path.display()).to_string())); } // Currently we don't support extensions discovering other extensions - for imported_manifest in load_manifest(&discover_result.manifest_path)? { + let manifests = match load_manifest(&discover_result.manifest_path) { + Ok(manifests) => manifests, + Err(err) => { + info!("{}", t!("extensions.dscextension.failedLoadManifest", extension = self.type_name, err = err)); + continue; + } + }; + for imported_manifest in manifests { if let ImportedManifest::Resource(resource) = imported_manifest { resources.push(resource); }