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
3 changes: 3 additions & 0 deletions adapters/powershell/Tests/powershellgroup.config.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ Describe 'PowerShell adapter resource tests' {
if ($metadata -eq 'Microsoft.DSC') {
"$TestDrive/tracing.txt" | Should -FileContentMatch "Invoking $Operation for '$adapter'" -Because (Get-Content -Raw -Path $TestDrive/tracing.txt)
}
if ($adapter -eq 'Microsoft.DSC/PowerShell') {
(Get-Content -Raw -Path $TestDrive/tracing.txt) | Should -Match "Resource 'Microsoft.DSC/PowerShell' is deprecated" -Because (Get-Content -Raw -Path $TestDrive/tracing.txt)
}
}

It 'Config works with credential object' {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ Describe 'PowerShell adapter resource tests' {
It 'Specifying a non-existent version returns an error' {
$null = dsc resource get -r TestClassResource/TestClassResource --version 0.0.2 2> $TestDrive/error.log
$LASTEXITCODE | Should -Be 7
Get-Content -Path $TestDrive/error.log | Should -Match 'Resource not found: TestClassResource/TestClassResource 0.0.2'
(Get-Content -Raw -Path $TestDrive/error.log) | Should -BeLike '*Resource not found: TestClassResource/TestClassResource 0.0.2*' -Because (Get-Content -Raw -Path $TestDrive/error.log)
}

It 'Can process SecureString property' {
Expand Down
4 changes: 3 additions & 1 deletion adapters/powershell/Tests/win_powershellgroup.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,9 @@ resources:
}
if ($metadata -eq 'Microsoft.DSC') {
"$TestDrive/tracing.txt" | Should -FileContentMatch "Invoking $Operation for '$adapter'" -Because (Get-Content -Raw -Path $TestDrive/tracing.txt)

}
if ($adapter -eq 'Microsoft.Windows/WindowsPowerShell') {
(Get-Content -Raw -Path $TestDrive/tracing.txt) | Should -Match "Resource 'Microsoft.Windows/WindowsPowerShell' is deprecated" -Because (Get-Content -Raw -Path $TestDrive/tracing.txt)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions adapters/powershell/powershell.dsc.resource.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"type": "Microsoft.DSC/PowerShell",
"version": "0.1.0",
"kind": "adapter",
"deprecationMessage": "Use the 'Microsoft.Adapters/PowerShell' adapter instead.",
"description": "Resource adapter to classic DSC Powershell resources.",
"tags": [
"PowerShell"
Expand Down
1 change: 1 addition & 0 deletions adapters/powershell/windowspowershell.dsc.resource.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"type": "Microsoft.Windows/WindowsPowerShell",
"version": "0.1.0",
"kind": "adapter",
"deprecationMessage": "Use the 'Microsoft.Adapters/WindowsPowerShell' adapter instead.",
"description": "Resource adapter to classic DSC Powershell resources in Windows PowerShell.",
"tags": [
"PowerShell"
Expand Down
13 changes: 13 additions & 0 deletions dsc/tests/dsc_adapter.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -227,5 +227,18 @@ Describe 'Tests for adapter support' {
}
}
}

It 'Deprecated adapted resource shows message' {
try {
$dscHome = Split-Path (Get-Command dsc).Source -Parent
$env:DSC_RESOURCE_PATH = (Join-Path -Path $dscHome -ChildPath 'deprecated') + [System.IO.Path]::PathSeparator + $dscHome
$out = dsc resource get -r Adapted/Deprecated -i '{}' 2>$TestDrive/error.log | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log | Out-String)
$out | Should -Not -BeNullOrEmpty
(Get-Content $TestDrive/error.log -Raw) | Should -Match "Resource 'Adapted/Deprecated' is deprecated: This adapted resource is deprecated" -Because (Get-Content $TestDrive/error.log | Out-String)
} finally {
$env:DSC_RESOURCE_PATH = $null
}
}
}
}
13 changes: 13 additions & 0 deletions dsc/tests/dsc_extension_discover.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,17 @@ Describe 'Discover extension tests' {
$env:PATH = $oldPath
}
}

It 'Deprecated extension shows message' {
try {
$dscHome = Split-Path (Get-Command dsc).Source -Parent
$env:DSC_RESOURCE_PATH = (Join-Path -Path $dscHome -ChildPath 'deprecated') + [System.IO.Path]::PathSeparator + $dscHome

$null = dsc resource list 2> $TestDrive/error.log
$LASTEXITCODE | Should -Be 0
(Get-Content -Path "$TestDrive/error.log" -Raw) | Should -Match "Extension 'Test/ExtensionDeprecated' is deprecated: This extension is deprecated" -Because (Get-Content -Path "$TestDrive/error.log" -Raw | Out-String)
} finally {
$env:DSC_RESOURCE_PATH = $null
}
}
}
18 changes: 18 additions & 0 deletions dsc/tests/dsc_extension_import.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Describe 'Import extension tests' {
It 'Deprecated extension shows message' {
try {
$dscHome = Split-Path (Get-Command dsc).Source -Parent
$env:DSC_RESOURCE_PATH = (Join-Path -Path $dscHome -ChildPath 'deprecated') + [System.IO.Path]::PathSeparator + $dscHome

Set-Content -Path "$TestDrive/test.testimport" -Value 'Test content'
$null = dsc config get -f "$TestDrive/test.testimport" 2> $TestDrive/error.log | ConvertFrom-Json
$LASTEXITCODE | Should -Be 2 -Because (Get-Content -Path "$TestDrive/error.log" -Raw | Out-String)
(Get-Content -Path "$TestDrive/error.log" -Raw) | Should -Match "Extension 'Test/ExtensionDeprecated' is deprecated: This extension is deprecated" -Because (Get-Content -Path "$TestDrive/error.log" -Raw | Out-String)
} finally {
$env:DSC_RESOURCE_PATH = $null
}
}
}
23 changes: 23 additions & 0 deletions dsc/tests/dsc_extension_secret.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,27 @@ Describe 'Tests for the secret() function and extensions' {
$out.results.Count | Should -Be 1
$out.results[0].result.actualState.Output | Should -BeExactly 'Hello'
}

It 'Deprecated extension shows message' {
try {
$dscHome = Split-Path (Get-Command dsc).Source -Parent
$env:DSC_RESOURCE_PATH = (Join-Path -Path $dscHome -ChildPath 'deprecated') + [System.IO.Path]::PathSeparator + $dscHome

$configYaml = @'
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
variables:
myString: "[secret('nonExisting')]"
resources:
- name: Database Connection
type: Microsoft.DSC.Debug/Echo
properties:
output: "[variables('myString')]"
'@
dsc -l trace config get -i $configYaml 2> $TestDrive/error.log | ConvertFrom-Json
$LASTEXITCODE | Should -Be 4
(Get-Content -Raw -Path "$TestDrive/error.log") | Should -Match "Extension 'Test/ExtensionDeprecated' is deprecated: This extension is deprecated" -Because (Get-Content -Raw -Path "$TestDrive/error.log")
} finally {
$env:DSC_RESOURCE_PATH = $null
}
}
}
56 changes: 56 additions & 0 deletions dsc/tests/dsc_resource_deprecated.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Describe 'Deprecated resource tests' {
BeforeAll {
$dscHome = Split-Path (Get-Command dsc).Source -Parent
$env:DSC_RESOURCE_PATH = (Join-Path -Path $dscHome -ChildPath 'deprecated') + [System.IO.Path]::PathSeparator + $dscHome
}

AfterAll {
$env:DSC_RESOURCE_PATH = $null
}

It 'Deprecated resource for operation <operation>' -TestCases @(
@{ operation = 'get' }
@{ operation = 'set' }
@{ operation = 'delete' }
@{ operation = 'test' }
@{ operation = 'export' }
) {
param($operation)

$out = dsc resource $operation -r Test/OperationDeprecated -i '{}' 2>$TestDrive/error.log | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log -Raw | Out-String)
if ($operation -eq 'delete') {
$out | Should -BeNullOrEmpty
} else {
$out | Should -Not -BeNullOrEmpty
}
(Get-Content $TestDrive/error.log -Raw) | Should -Match "Resource 'Test/OperationDeprecated' is deprecated: This resource is deprecated"
}

It 'Deprecated resource for schema' {
$out = dsc resource schema -r Test/OperationDeprecated 2>$TestDrive/error.log | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log -Raw | Out-String)
$out | Should -Not -BeNullOrEmpty
(Get-Content $TestDrive/error.log -Raw) | Should -Match "Resource 'Test/OperationDeprecated' is deprecated: This resource is deprecated"
}

It 'Deprecated message when used in config' {
$configYaml = @'
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
resources:
- name: test
type: Test/OperationDeprecated
properties:
operation: get
'@

$out = dsc config get -i $configYaml 2>$TestDrive/error.log | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log -Raw | Out-String)
$out.results.count | Should -Be 1
$out.results[0].type | Should -BeExactly 'Test/OperationDeprecated'
(Get-Content $TestDrive/error.log -Raw) | Should -Match "Resource 'Test/OperationDeprecated' is deprecated: This resource is deprecated"
}
}
2 changes: 2 additions & 0 deletions lib/dsc-lib/locales/en-us.toml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ adapterResourceNotFound = "Adapter resource '%{adapter}' not found"
adapterManifestNotFound = "Adapter manifest for '%{adapter}' not found"
adapterDoesNotSupportDelete = "Adapter '%{adapter}' does not support delete operation"
validatingAgainstSchema = "Validating against resource schema"
deprecationMessage = "Resource '%{resource}' is deprecated: %{message}"

[dscresources.resource_manifest]
resourceManifestSchemaTitle = "Resource manifest schema URI"
Expand All @@ -239,6 +240,7 @@ importNotSupported = "Import is not supported by extension '%{extension}' for fi
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}"

[extensions.extension_manifest]
extensionManifestSchemaTitle = "Extension manifest schema URI"
Expand Down
3 changes: 3 additions & 0 deletions lib/dsc-lib/src/discovery/command_discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ fn load_adapted_resource_manifest(path: &Path, manifest: &AdaptedDscResourceMani
type_name: manifest.type_name.clone(),
kind: Kind::Resource,
implemented_as: None,
deprecation_message: manifest.deprecation_message.clone(),
description: manifest.description.clone(),
version: manifest.version.clone(),
capabilities: manifest.capabilities.clone(),
Expand Down Expand Up @@ -858,6 +859,7 @@ fn load_resource_manifest(path: &Path, manifest: &ResourceManifest) -> Result<Ds
type_name: manifest.resource_type.clone(),
kind,
implemented_as: Some(ImplementedAs::Command),
deprecation_message: manifest.deprecation_message.clone(),
description: manifest.description.clone(),
version: manifest.version.clone(),
capabilities,
Expand Down Expand Up @@ -899,6 +901,7 @@ fn load_extension_manifest(path: &Path, manifest: &ExtensionManifest) -> Result<

let extension = DscExtension {
type_name: manifest.r#type.clone(),
deprecation_message: manifest.deprecation_message.clone(),
description: manifest.description.clone(),
version: manifest.version.clone(),
capabilities,
Expand Down
6 changes: 4 additions & 2 deletions lib/dsc-lib/src/dscresources/adapted_resource_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use serde_json::{Map, Value};
use std::path::PathBuf;

#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, DscRepoSchema)]
#[serde(deny_unknown_fields)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
#[dsc_repo_schema(
base_name = "manifest",
folder_path = "resource",
Expand All @@ -43,14 +43,16 @@ pub struct AdaptedDscResourceManifest {
pub capabilities: Vec<Capability>,
/// An optional condition for the resource to be active.
pub condition: Option<String>,
/// An optional message indicating the resource is deprecated. If provided, the message will be shown when the resource is used.
#[serde(skip_serializing_if = "Option::is_none")]
pub deprecation_message: Option<String>,
/// The file path to the resource.
pub path: PathBuf,
/// The description of the resource.
pub description: Option<String>,
/// The author of the resource.
pub author: Option<String>,
/// The required resource adapter for the resource.
#[serde(rename="requireAdapter")]
pub require_adapter: FullyQualifiedTypeName,
/// The JSON Schema of the resource.
pub schema: Map<String, Value>,
Expand Down
33 changes: 29 additions & 4 deletions lib/dsc-lib/src/dscresources/dscresource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use std::collections::HashMap;
use std::path::PathBuf;
use tracing::{debug, info, trace};
use tracing::{debug, info, trace, warn};

use crate::schemas::dsc_repo::DscRepoSchema;

Expand All @@ -27,7 +27,7 @@ use super::{
};

#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, DscRepoSchema)]
#[serde(deny_unknown_fields)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
#[dsc_repo_schema(base_name = "list", folder_path = "outputs/resource")]
pub struct DscResource {
/// The namespaced name of the resource.
Expand All @@ -39,21 +39,21 @@ pub struct DscResource {
pub version: String,
/// The capabilities of the resource.
pub capabilities: Vec<Capability>,
/// An optional message indicating the resource is deprecated. If provided, the message will be shown when the resource is used.
pub deprecation_message: Option<String>,
/// The file path to the resource.
pub path: PathBuf,
/// The description of the resource.
pub description: Option<String>,
// The directory path to the resource.
pub directory: PathBuf,
/// The implementation of the resource.
#[serde(rename="implementedAs")]
pub implemented_as: Option<ImplementedAs>,
/// The author of the resource.
pub author: Option<String>,
/// The properties of the resource.
pub properties: Option<Vec<String>>,
/// The required resource adapter for the resource.
#[serde(rename="requireAdapter")]
pub require_adapter: Option<FullyQualifiedTypeName>,
/// The JSON Schema of the resource.
pub schema: Option<Map<String, Value>>,
Expand Down Expand Up @@ -103,6 +103,7 @@ impl DscResource {
kind: Kind::Resource,
version: String::new(),
capabilities: Vec::new(),
deprecation_message: None,
description: None,
path: PathBuf::new(),
directory: PathBuf::new(),
Expand Down Expand Up @@ -383,6 +384,9 @@ pub trait Invoke {
impl Invoke for DscResource {
fn get(&self, filter: &str) -> Result<GetResult, DscError> {
debug!("{}", t!("dscresources.dscresource.invokeGet", resource = self.type_name));
if let Some(deprecation_message) = self.deprecation_message.as_ref() {
warn!("{}", t!("dscresources.dscresource.deprecationMessage", resource = self.type_name, message = deprecation_message));
}
if let Some(adapter) = &self.require_adapter {
return self.invoke_get_with_adapter(adapter, &self, filter);
}
Expand All @@ -399,6 +403,9 @@ impl Invoke for DscResource {

fn set(&self, desired: &str, skip_test: bool, execution_type: &ExecutionKind) -> Result<SetResult, DscError> {
debug!("{}", t!("dscresources.dscresource.invokeSet", resource = self.type_name));
if let Some(deprecation_message) = self.deprecation_message.as_ref() {
warn!("{}", t!("dscresources.dscresource.deprecationMessage", resource = self.type_name, message = deprecation_message));
}
if let Some(adapter) = &self.require_adapter {
return self.invoke_set_with_adapter(adapter, &self, desired, skip_test, execution_type);
}
Expand All @@ -415,6 +422,9 @@ impl Invoke for DscResource {

fn test(&self, expected: &str) -> Result<TestResult, DscError> {
debug!("{}", t!("dscresources.dscresource.invokeTest", resource = self.type_name));
if let Some(deprecation_message) = self.deprecation_message.as_ref() {
warn!("{}", t!("dscresources.dscresource.deprecationMessage", resource = self.type_name, message = deprecation_message));
}
if let Some(adapter) = &self.require_adapter {
return self.invoke_test_with_adapter(adapter, &self, expected);
}
Expand Down Expand Up @@ -463,6 +473,9 @@ impl Invoke for DscResource {

fn delete(&self, filter: &str, execution_type: &ExecutionKind) -> Result<DeleteResultKind, DscError> {
debug!("{}", t!("dscresources.dscresource.invokeDelete", resource = self.type_name));
if let Some(deprecation_message) = self.deprecation_message.as_ref() {
warn!("{}", t!("dscresources.dscresource.deprecationMessage", resource = self.type_name, message = deprecation_message));
}
if let Some(adapter) = &self.require_adapter {
return self.invoke_delete_with_adapter(adapter, &self, filter, execution_type);
}
Expand All @@ -479,6 +492,9 @@ impl Invoke for DscResource {

fn validate(&self, config: &str) -> Result<ValidateResult, DscError> {
debug!("{}", t!("dscresources.dscresource.invokeValidate", resource = self.type_name));
if let Some(deprecation_message) = self.deprecation_message.as_ref() {
warn!("{}", t!("dscresources.dscresource.deprecationMessage", resource = self.type_name, message = deprecation_message));
}
if self.require_adapter.is_some() {
return Err(DscError::NotSupported(t!("dscresources.dscresource.invokeValidateNotSupported", resource = self.type_name).to_string()));
}
Expand All @@ -495,6 +511,9 @@ impl Invoke for DscResource {

fn schema(&self) -> Result<String, DscError> {
debug!("{}", t!("dscresources.dscresource.invokeSchema", resource = self.type_name));
if let Some(deprecation_message) = self.deprecation_message.as_ref() {
warn!("{}", t!("dscresources.dscresource.deprecationMessage", resource = self.type_name, message = deprecation_message));
}
if self.require_adapter.is_some() {
return Err(DscError::NotSupported(t!("dscresources.dscresource.invokeSchemaNotSupported", resource = self.type_name).to_string()));
}
Expand All @@ -511,6 +530,9 @@ impl Invoke for DscResource {

fn export(&self, input: &str) -> Result<ExportResult, DscError> {
debug!("{}", t!("dscresources.dscresource.invokeExport", resource = self.type_name));
if let Some(deprecation_message) = self.deprecation_message.as_ref() {
warn!("{}", t!("dscresources.dscresource.deprecationMessage", resource = self.type_name, message = deprecation_message));
}
if let Some(adapter) = &self.require_adapter {
return self.invoke_export_with_adapter(adapter, &self, input);
}
Expand All @@ -520,6 +542,9 @@ impl Invoke for DscResource {

fn resolve(&self, input: &str) -> Result<ResolveResult, DscError> {
debug!("{}", t!("dscresources.dscresource.invokeResolve", resource = self.type_name));
if let Some(deprecation_message) = self.deprecation_message.as_ref() {
warn!("{}", t!("dscresources.dscresource.deprecationMessage", resource = self.type_name, message = deprecation_message));
}
if self.require_adapter.is_some() {
return Err(DscError::NotSupported(t!("dscresources.dscresource.invokeResolveNotSupported", resource = self.type_name).to_string()));
}
Expand Down
Loading