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
5 changes: 5 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
"type": "lldb",
"request": "attach",
"pid": "${command:pickMyProcess}",
"expressions": "simple",
"preRunCommands": [
// !! change this path if you placed the script somewhere else !!
"command script import ~/.vscode/rust_prettifier_for_lldb.py"
],
},
{
"name": "(Windows) Attach",
Expand Down
91 changes: 91 additions & 0 deletions dsc/tests/dsc_adapter.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Describe 'Tests for adapter support' {
Context 'Adapter support single resource' {
It 'Direct resource invocation for: <operation>' -TestCases @(
@{ operation = 'get' },
@{ operation = 'set' },
@{ operation = 'test' },
@{ operation = 'export' }
){
param($operation)

$out = dsc resource $operation -r Adapted/One -i '{"one":"1"}' 2>$TestDrive/error.log | ConvertFrom-Json -Depth 10
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log | Out-String)
switch ($operation) {
'get' {
$out.actualState.one | Should -BeExactly 'value1'
}
'set' {
$out.afterState.one | Should -BeExactly 'value1'
}
'test' {
$out.actualState.one | Should -BeExactly 'value1'
$out.inDesiredState | Should -BeFalse
$out.differingProperties | Should -Be @('one')
}
'export' {
$out.resources.count | Should -Be 2
$out.resources[0].type | Should -BeExactly 'Adapted/One'
$out.resources[0].name | Should -BeExactly 'first'
$out.resources[0].properties.one | Should -BeExactly 'first1'
$out.resources[1].type | Should -BeExactly 'Adapted/One'
$out.resources[1].name | Should -BeExactly 'second'
$out.resources[1].properties.one | Should -BeExactly 'second1'
}
}
}

It 'Config resource invocation 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/Two
properties:
two: '2'
"@
$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.Count | Should -Be 1
$out.results[0].Name | Should -Be 'Test'
$out.results[0].type | Should -BeExactly 'Adapted/Two'
$out.results[0].result.actualState.two | Should -BeExactly 'value2' -Because ($out | ConvertTo-Json -Depth 10 | Out-String)
}
'set' {
$out.results.Count | Should -Be 1
$out.results[0].Name | Should -Be 'Test'
$out.results[0].type | Should -BeExactly 'Adapted/Two'
$out.results[0].result.afterState.two | Should -BeExactly 'value2' -Because ($out | ConvertTo-Json -Depth 10 | Out-String)
}
'test' {
$out.results.Count | Should -Be 1
$out.results[0].Name | Should -Be 'Test'
$out.results[0].type | Should -BeExactly 'Adapted/Two'
$out.results[0].result.actualState.two | Should -BeExactly 'value2' -Because ($out | ConvertTo-Json -Depth 10 | Out-String)
$out.results[0].result.inDesiredState | Should -BeFalse
$out.results[0].result.differingProperties | Should -Be @('two') -Because ($out | ConvertTo-Json -Depth 10 | Out-String)
}
'export' {
$out.resources.Count | Should -Be 2
$out.resources[0].Name | Should -Be 'first'
$out.resources[0].type | Should -BeExactly 'Adapted/Two'
$out.resources[0].properties.two | Should -BeExactly 'first2'
$out.resources[1].Name | Should -Be 'second'
$out.resources[1].type | Should -BeExactly 'Adapted/Two'
$out.resources[1].properties.two | Should -BeExactly 'second2'
}
}
}
}
}
3 changes: 3 additions & 0 deletions dsc_lib/locales/en-us.toml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ resourceImplementsValidate = "Resource implements validation"
resourceValidationFailed = "Resource failed validation"
validatingSchema = "Validating against schema"
validationFailed = "Failed validation"
adapterResourceNotFound = "Adapter resource '%{adapter}' not found"
adapterManifestNotFound = "Adapter manifest for '%{adapter}' not found"
adapterDoesNotSupportDelete = "Adapter '%{adapter}' does not support delete operation"

[dscresources.resource_manifest]
resourceManifestSchemaTitle = "Resource manifest schema URI"
Expand Down
44 changes: 26 additions & 18 deletions dsc_lib/src/configure/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ use crate::configure::context::{Context, ProcessMode};
use crate::configure::{config_doc::RestartRequired, parameters::Input};
use crate::discovery::discovery_trait::DiscoveryFilter;
use crate::dscerror::DscError;
use crate::dscresources::invoke_result::ExportResult;
use crate::dscresources::{
{dscresource::{Capability, Invoke, get_diff, validate_properties},
invoke_result::{GetResult, SetResult, TestResult, ResourceSetResponse}},
resource_manifest::Kind,
{dscresource::{Capability, Invoke, get_diff, validate_properties, get_adapter_input_kind},
invoke_result::{GetResult, SetResult, TestResult, ExportResult, ResourceSetResponse}},
resource_manifest::{AdapterInputKind, Kind},
};
use crate::DscResource;
use crate::discovery::Discovery;
Expand Down Expand Up @@ -177,7 +176,7 @@ fn escape_property_values(properties: &Map<String, Value>) -> Result<Option<Map<
}

fn add_metadata(dsc_resource: &DscResource, mut properties: Option<Map<String, Value>>, resource_metadata: Option<Metadata> ) -> Result<String, DscError> {
if dsc_resource.kind == Kind::Adapter {
if dsc_resource.kind == Kind::Adapter && get_adapter_input_kind(dsc_resource)? == AdapterInputKind::Full {
// add metadata to the properties so the adapter knows this is a config
let mut metadata: Map<String, Value> = Map::new();
if let Some(resource_metadata) = resource_metadata {
Expand Down Expand Up @@ -319,6 +318,15 @@ impl Configurator {
&self.config
}

/// Get the discovery.
///
/// # Returns
///
/// * `&Discovery` - The discovery.
pub fn discovery(&mut self) -> &mut Discovery {
&mut self.discovery
}

fn get_properties(&mut self, resource: &Resource, resource_kind: &Kind) -> Result<Option<Map<String, Value>>, DscError> {
match resource_kind {
Kind::Group => {
Expand All @@ -342,14 +350,14 @@ impl Configurator {
/// This function will return an error if the underlying resource fails.
pub fn invoke_get(&mut self) -> Result<ConfigurationGetResult, DscError> {
self.unroll_copy_loops()?;

let mut result = ConfigurationGetResult::new();
let resources = get_resource_invocation_order(&self.config, &mut self.statement_parser, &self.context)?;
let mut progress = ProgressBar::new(resources.len() as u64, self.progress_format)?;
let discovery = &mut self.discovery.clone();
for resource in resources {
let evaluated_name = self.evaluate_resource_name(&resource.name)?;

progress.set_resource(&evaluated_name, &resource.resource_type);
progress.write_activity(format!("Get '{evaluated_name}'").as_str());
if self.skip_resource(&resource)? {
Expand Down Expand Up @@ -424,14 +432,14 @@ impl Configurator {
#[allow(clippy::too_many_lines)]
pub fn invoke_set(&mut self, skip_test: bool) -> Result<ConfigurationSetResult, DscError> {
self.unroll_copy_loops()?;

let mut result = ConfigurationSetResult::new();
let resources = get_resource_invocation_order(&self.config, &mut self.statement_parser, &self.context)?;
let mut progress = ProgressBar::new(resources.len() as u64, self.progress_format)?;
let discovery = &mut self.discovery.clone();
for resource in resources {
let evaluated_name = self.evaluate_resource_name(&resource.name)?;

progress.set_resource(&evaluated_name, &resource.resource_type);
progress.write_activity(format!("Set '{evaluated_name}'").as_str());
if self.skip_resource(&resource)? {
Expand Down Expand Up @@ -580,14 +588,14 @@ impl Configurator {
/// This function will return an error if the underlying resource fails.
pub fn invoke_test(&mut self) -> Result<ConfigurationTestResult, DscError> {
self.unroll_copy_loops()?;

let mut result = ConfigurationTestResult::new();
let resources = get_resource_invocation_order(&self.config, &mut self.statement_parser, &self.context)?;
let mut progress = ProgressBar::new(resources.len() as u64, self.progress_format)?;
let discovery = &mut self.discovery.clone();
for resource in resources {
let evaluated_name = self.evaluate_resource_name(&resource.name)?;

progress.set_resource(&evaluated_name, &resource.resource_type);
progress.write_activity(format!("Test '{evaluated_name}'").as_str());
if self.skip_resource(&resource)? {
Expand Down Expand Up @@ -658,7 +666,7 @@ impl Configurator {
/// This function will return an error if the underlying resource fails.
pub fn invoke_export(&mut self) -> Result<ConfigurationExportResult, DscError> {
self.unroll_copy_loops()?;

let mut result = ConfigurationExportResult::new();
let mut conf = config_doc::Configuration::new();
conf.metadata.clone_from(&self.config.metadata);
Expand All @@ -668,7 +676,7 @@ impl Configurator {
let discovery = &mut self.discovery.clone();
for resource in &resources {
let evaluated_name = self.evaluate_resource_name(&resource.name)?;

progress.set_resource(&evaluated_name, &resource.resource_type);
progress.write_activity(format!("Export '{evaluated_name}'").as_str());
if self.skip_resource(resource)? {
Expand Down Expand Up @@ -916,7 +924,7 @@ impl Configurator {
fn unroll_copy_loops(&mut self) -> Result<(), DscError> {
let mut config = self.config.clone();
let config_copy = config.clone();

for resource in config_copy.resources {
// if the resource contains `Copy`, unroll it
if let Some(copy) = &resource.copy {
Expand All @@ -931,7 +939,7 @@ impl Configurator {
return Err(DscError::Parser(t!("configure.mod.copyNameResultNotString").to_string()))
};
new_resource.name = new_name.to_string();

new_resource.copy = None;
copy_resources.push(new_resource);
}
Expand All @@ -941,7 +949,7 @@ impl Configurator {
config.resources.extend(copy_resources);
}
}

self.config = config;
Ok(())
}
Expand All @@ -967,12 +975,12 @@ impl Configurator {
if self.context.process_mode == ProcessMode::Copy {
return Ok(name.to_string());
}

// evaluate the resource name (handles both expressions and literals)
let Value::String(evaluated_name) = self.statement_parser.parse_and_execute(name, &self.context)? else {
return Err(DscError::Parser(t!("configure.mod.nameResultNotString").to_string()))
};

Ok(evaluated_name)
}

Expand Down
Loading