Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix concat() function and add createArray() function #322

Merged
merged 3 commits into from
Feb 23, 2024
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
2 changes: 1 addition & 1 deletion dsc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ serde_json = { version = "1.0", features = ["preserve_order"] }
serde_yaml = { version = "0.9.3" }
syntect = { version = "5.0", features = ["default-fancy"], default-features = false }
sysinfo = { version = "0.29.10" }
thiserror = "1.0"
thiserror = "1.0.52"
tracing = { version = "0.1.37" }
tracing-subscriber = { version = "0.3.17", features = ["ansi", "env-filter", "json"] }
2 changes: 1 addition & 1 deletion dsc/tests/dsc_config_get.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Describe 'dsc config get tests' {
- name: Echo
type: Test/Echo
properties:
text: hello
output: hello
"@
$null = $config_yaml | dsc config get --format pretty-json | Out-String
$LASTEXITCODE | Should -Be 0
Expand Down
6 changes: 3 additions & 3 deletions dsc/tests/dsc_functions.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Describe 'tests for function expressions' {
It 'function works: <text>' -TestCases @(
@{ text = "[concat('a', 'b')]"; expected = 'ab' }
@{ text = "[concat('a', 'b', 'c')]"; expected = 'abc' }
@{ text = "[concat('a', 1, concat(2, 'b'))]"; expected = 'a12b' }
@{ text = "[concat('a', concat('b', 'c'))]"; expected = 'abc' }
@{ text = "[base64('ab')]"; expected = 'YWI=' }
@{ text = "[base64(concat('a','b'))]"; expected = 'YWI=' }
@{ text = "[base64(base64(concat('a','b')))]"; expected = 'WVdJPQ==' }
Expand All @@ -19,9 +19,9 @@ Describe 'tests for function expressions' {
- name: Echo
type: Test/Echo
properties:
text: '$escapedText'
output: '$escapedText'
"@
$out = $config_yaml | dsc config get | ConvertFrom-Json
$out.results[0].result.actualState.text | Should -Be $expected
$out.results[0].result.actualState.output | Should -Be $expected
}
}
57 changes: 36 additions & 21 deletions dsc/tests/dsc_parameters.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Describe 'Parameters tests' {
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
output: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = 'hello' }} | ConvertTo-Json

Expand All @@ -31,16 +31,16 @@ Describe 'Parameters tests' {
}

$LASTEXITCODE | Should -Be 0
$out.results[0].result.actualState.text | Should -BeExactly 'hello'
$out.results[0].result.actualState.output | Should -BeExactly 'hello'
}

It 'Input is <type>' -TestCases @(
@{ type = 'string'; value = 'hello'; expected = 'hello' }
@{ type = 'int'; value = 42; expected = 42 }
@{ type = 'bool'; value = $true; expected = $true }
@{ type = 'array'; value = @('hello', 'world'); expected = '["hello","world"]' }
@{ type = 'string'; value = 'hello' }
@{ type = 'int'; value = 42}
@{ type = 'bool'; value = $true}
@{ type = 'array'; value = @('hello', 'world')}
) {
param($type, $value, $expected)
param($type, $value)

$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
Expand All @@ -51,13 +51,13 @@ Describe 'Parameters tests' {
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
output: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = $value }} | ConvertTo-Json

$out = $config_yaml | dsc config -p $params_json get | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0
$out.results[0].result.actualState.text | Should -BeExactly $expected
$out.results[0].result.actualState.output | Should -BeExactly $value
}

It 'Input is incorrect type <type>' -TestCases @(
Expand All @@ -77,7 +77,7 @@ Describe 'Parameters tests' {
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
output: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = $value }} | ConvertTo-Json

Expand All @@ -104,7 +104,7 @@ Describe 'Parameters tests' {
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
output: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = $value }} | ConvertTo-Json

Expand All @@ -130,7 +130,7 @@ Describe 'Parameters tests' {
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
output: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = $value }} | ConvertTo-Json

Expand All @@ -154,7 +154,7 @@ Describe 'Parameters tests' {
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
output: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = $value }} | ConvertTo-Json

Expand All @@ -180,7 +180,7 @@ Describe 'Parameters tests' {
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
output: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = $value }} | ConvertTo-Json

Expand All @@ -192,28 +192,43 @@ Describe 'Parameters tests' {
$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
parameters:
param1:
paramString:
type: string
defaultValue: 'hello'
param2:
paramInt:
type: int
defaultValue: 7
param3:
paramBool:
type: bool
defaultValue: false
param4:
paramArray:
type: array
defaultValue: ['hello', 'world']
resources:
- name: Echo
- name: String
type: Test/Echo
properties:
output: '[parameters(''paramString'')]'
- name: Int
type: Test/Echo
properties:
output: '[parameters(''paramInt'')]'
- name: Bool
type: Test/Echo
properties:
output: '[parameters(''paramBool'')]'
- name: Array
type: Test/Echo
properties:
text: '[concat(parameters(''param1''),'','',parameters(''param2''),'','',parameters(''param3''),'','',parameters(''param4''))]'
output: '[parameters(''paramArray'')]'
"@

$out = $config_yaml | dsc config get | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0
$out.results[0].result.actualState.text | Should -BeExactly 'hello,7,false,["hello","world"]'
$out.results[0].result.actualState.output | Should -BeExactly 'hello'
$out.results[1].result.actualState.output | Should -BeExactly 7
$out.results[2].result.actualState.output | Should -BeExactly $false
$out.results[3].result.actualState.output | Should -BeExactly @('hello', 'world')
}

It 'property value uses parameter value' {
Expand Down
2 changes: 1 addition & 1 deletion dsc/tests/dsc_test.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Describe 'config test tests' {
}

It 'can accept the use of --format as a subcommand' {
$null = "text: hello" | dsc resource test -r Test/Echo --format pretty-json
$null = "output: hello" | dsc resource test -r Test/Echo --format pretty-json
$LASTEXITCODE | Should -Be 0
}
}
10 changes: 8 additions & 2 deletions dsc_lib/src/configure/depends_on.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ pub fn get_resource_invocation_order(config: &Configuration, parser: &mut Statem
if let Some(depends_on) = resource.depends_on.clone() {
for dependency in depends_on {
let statement = parser.parse_and_execute(&dependency, context)?;
let (resource_type, resource_name) = get_type_and_name(&statement)?;
let Some(string_result) = statement.as_str() else {
return Err(DscError::Validation(format!("'dependsOn' syntax is incorrect: {dependency}")));
};
let (resource_type, resource_name) = get_type_and_name(string_result)?;

// find the resource by name
let Some(dependency_resource) = config.resources.iter().find(|r| r.name.eq(resource_name)) else {
Expand Down Expand Up @@ -64,7 +67,10 @@ pub fn get_resource_invocation_order(config: &Configuration, parser: &mut Statem
let resource_index = order.iter().position(|r| r.name == resource.name && r.resource_type == resource.resource_type).ok_or(DscError::Validation("Resource not found in order".to_string()))?;
for dependency in depends_on {
let statement = parser.parse_and_execute(dependency, context)?;
let (resource_type, resource_name) = get_type_and_name(&statement)?;
let Some(string_result) = statement.as_str() else {
return Err(DscError::Validation(format!("'dependsOn' syntax is incorrect: {dependency}")));
};
let (resource_type, resource_name) = get_type_and_name(string_result)?;
let dependency_index = order.iter().position(|r| r.name == resource_name && r.resource_type == resource_type).ok_or(DscError::Validation("Dependency not found in order".to_string()))?;
if resource_index < dependency_index {
return Err(DscError::Validation(format!("Circular dependency detected for resource named '{0}'", resource.name)));
Expand Down
16 changes: 13 additions & 3 deletions dsc_lib/src/configure/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use self::config_result::{ConfigurationGetResult, ConfigurationSetResult, Config
use self::contraints::{check_length, check_number_limits, check_allowed_values};
use serde_json::{Map, Value};
use std::collections::{HashMap, HashSet};
use tracing::debug;
use tracing::{debug, trace};

pub mod context;
pub mod config_doc;
Expand Down Expand Up @@ -73,6 +73,7 @@ pub fn add_resource_export_results_to_configuration(resource: &DscResource, prov
// for values returned by resources, they may look like expressions, so we make sure to escape them in case
// they are re-used to apply configuration
fn escape_property_values(properties: &Map<String, Value>) -> Result<Option<Map<String, Value>>, DscError> {
debug!("Escape returned property values");
let mut result: Map<String, Value> = Map::new();
for (name, value) in properties {
match value {
Expand Down Expand Up @@ -400,13 +401,15 @@ impl Configurator {
}

fn invoke_property_expressions(&mut self, properties: &Option<Map<String, Value>>) -> Result<Option<Map<String, Value>>, DscError> {
debug!("Invoke property expressions");
if properties.is_none() {
return Ok(None);
}

let mut result: Map<String, Value> = Map::new();
if let Some(properties) = properties {
for (name, value) in properties {
trace!("Invoke property expression for {name}: {value}");
match value {
Value::Object(object) => {
let value = self.invoke_property_expressions(&Some(object.clone()))?;
Expand All @@ -431,7 +434,10 @@ impl Configurator {
return Err(DscError::Parser("Array element could not be transformed as string".to_string()));
};
let statement_result = self.statement_parser.parse_and_execute(statement, &self.context)?;
result_array.push(Value::String(statement_result));
let Some(string_result) = statement_result.as_str() else {
return Err(DscError::Parser("Array element could not be transformed as string".to_string()));
};
result_array.push(Value::String(string_result.to_string()));
}
_ => {
result_array.push(element.clone());
Expand All @@ -446,7 +452,11 @@ impl Configurator {
return Err(DscError::Parser(format!("Property value '{value}' could not be transformed as string")));
};
let statement_result = self.statement_parser.parse_and_execute(statement, &self.context)?;
result.insert(name.clone(), Value::String(statement_result));
if let Some(string_result) = statement_result.as_str() {
result.insert(name.clone(), Value::String(string_result.to_string()));
} else {
result.insert(name.clone(), statement_result);
};
},
_ => {
result.insert(name.clone(), value.clone());
Expand Down
12 changes: 5 additions & 7 deletions dsc_lib/src/functions/base64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ use base64::{Engine as _, engine::general_purpose};

use crate::DscError;
use crate::configure::context::Context;
use crate::parser::functions::{FunctionArg, FunctionResult};
use super::{Function, AcceptedArgKind};
use crate::functions::AcceptedArgKind;
use serde_json::Value;
use super::Function;

#[derive(Debug, Default)]
pub struct Base64 {}
Expand All @@ -24,11 +25,8 @@ impl Function for Base64 {
1
}

fn invoke(&self, args: &[FunctionArg], _context: &Context) -> Result<FunctionResult, DscError> {
let FunctionArg::String(arg) = args.first().unwrap() else {
return Err(DscError::Parser("Invalid argument type".to_string()));
};
Ok(FunctionResult::String(general_purpose::STANDARD.encode(arg)))
fn invoke(&self, args: &[Value], _context: &Context) -> Result<Value, DscError> {
Ok(Value::String(general_purpose::STANDARD.encode(args[0].as_str().unwrap_or_default())))
}
}

Expand Down
Loading
Loading