Skip to content

Commit

Permalink
Merge branch 'main' into resource_debug_msgs
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveL-MSFT authored Jan 10, 2024
2 parents 9eddd7f + 6581288 commit 6dc23d5
Show file tree
Hide file tree
Showing 23 changed files with 696 additions and 63 deletions.
2 changes: 2 additions & 0 deletions dsc/examples/osinfo.parameters.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
parameters:
osFamily: macOS
14 changes: 14 additions & 0 deletions dsc/examples/osinfo_parameters.dsc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
parameters:
osFamily:
type: string
defaultValue: Windows
allowedValues:
- Windows
- Linux
- macOS
resources:
- name: os
type: Microsoft/OSInfo
properties:
family: "[parameters('osFamily')]"
4 changes: 4 additions & 0 deletions dsc/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ pub enum SubCommand {
Config {
#[clap(subcommand)]
subcommand: ConfigSubCommand,
#[clap(short, long, help = "Parameters to pass to the configuration as JSON or YAML", conflicts_with = "parameters_file")]
parameters: Option<String>,
#[clap(short = 'f', long, help = "Parameters to pass to the configuration as a JSON or YAML file", conflicts_with = "parameters")]
parameters_file: Option<String>,
},
#[clap(name = "resource", about = "Invoke a specific DSC resource")]
Resource {
Expand Down
16 changes: 14 additions & 2 deletions dsc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,20 @@ fn main() {
let mut cmd = Args::command();
generate(shell, &mut cmd, "dsc", &mut io::stdout());
},
SubCommand::Config { subcommand } => {
subcommand::config(&subcommand, &args.format, &input);
SubCommand::Config { subcommand, parameters, parameters_file } => {
if let Some(file_name) = parameters_file {
info!("Reading parameters from file {}", file_name);
match std::fs::read_to_string(file_name) {
Ok(parameters) => subcommand::config(&subcommand, &Some(parameters), &args.format, &input),
Err(err) => {
error!("Error: Failed to read parameters file: {err}");
exit(util::EXIT_INVALID_INPUT);
}
}
}
else {
subcommand::config(&subcommand, &parameters, &args.format, &input);
}
},
SubCommand::Resource { subcommand } => {
subcommand::resource(&subcommand, &args.format, &input);
Expand Down
35 changes: 33 additions & 2 deletions dsc/src/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ pub fn config_export(configurator: &mut Configurator, format: &Option<OutputForm
}
}

pub fn config(subcommand: &ConfigSubCommand, format: &Option<OutputFormat>, stdin: &Option<String>) {
pub fn config(subcommand: &ConfigSubCommand, parameters: &Option<String>, format: &Option<OutputFormat>, stdin: &Option<String>) {
let Some(stdin) = stdin else {
error!("Configuration must be piped to STDIN");
exit(EXIT_INVALID_ARGS);
Expand Down Expand Up @@ -152,6 +152,37 @@ pub fn config(subcommand: &ConfigSubCommand, format: &Option<OutputFormat>, stdi
}
};

let parameters: Option<serde_json::Value> = match parameters {
None => None,
Some(parameters) => {
match serde_json::from_str(parameters) {
Ok(json) => Some(json),
Err(_) => {
match serde_yaml::from_str::<Value>(parameters) {
Ok(yaml) => {
match serde_json::to_value(yaml) {
Ok(json) => Some(json),
Err(err) => {
error!("Error: Failed to convert YAML to JSON: {err}");
exit(EXIT_DSC_ERROR);
}
}
},
Err(err) => {
error!("Error: Parameters are not valid JSON or YAML: {err}");
exit(EXIT_INVALID_INPUT);
}
}
}
}
}
};

if let Err(err) = configurator.set_parameters(&parameters) {
error!("Error: Paramter input failure: {err}");
exit(EXIT_INVALID_INPUT);
}

match subcommand {
ConfigSubCommand::Get => {
config_get(&mut configurator, format);
Expand Down Expand Up @@ -383,7 +414,7 @@ pub fn resource(subcommand: &ResourceSubCommand, format: &Option<OutputFormat>,
ResourceSubCommand::Get { resource, input, all } => {
dsc.discover_resources(&[resource.to_lowercase().to_string()]);
if *all { resource_command::get_all(&dsc, resource, input, stdin, format); }
else {
else {
resource_command::get(&dsc, resource, input, stdin, format);
};
},
Expand Down
218 changes: 218 additions & 0 deletions dsc/tests/dsc_parameters.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Describe 'Parameters tests' {
It 'Input can be provided as <inputType>' -TestCases @(
@{ inputType = 'string' }
@{ inputType = 'file' }
) {
param($inputType)

$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
parameters:
param1:
type: string
resources:
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = 'hello' }} | ConvertTo-Json

if ($inputType -eq 'file') {
$file_path = "$TestDrive/test.parameters.json"
Set-Content -Path $file_path -Value $params_json
$out = $config_yaml | dsc config -f $file_path get | ConvertFrom-Json
}
else {
$out = $config_yaml | dsc config -p $params_json get | ConvertFrom-Json
}

$LASTEXITCODE | Should -Be 0
$out.results[0].result.actualState.text | 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"]' }
) {
param($type, $value, $expected)

$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
parameters:
param1:
type: $type
resources:
- name: Echo
type: Test/Echo
properties:
text: '[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
}

It 'Input is incorrect type <type>' -TestCases @(
@{ type = 'string'; value = 42 }
@{ type = 'int'; value = 'hello' }
@{ type = 'bool'; value = 'hello' }
@{ type = 'array'; value = 'hello' }
) {
param($type, $value)

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

$null = $config_yaml | dsc config -p $params_json get
$LASTEXITCODE | Should -Be 4
}

It 'Input length is wrong for <type>' -TestCases @(
@{ type = 'string'; value = 'hi' }
@{ type = 'string'; value = 'hello' }
@{ type = 'array'; value = @('hello', 'there') }
@{ type = 'array'; value = @('hello', 'there', 'bye', 'now') }
) {
param($type, $value)

$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
parameters:
param1:
type: $type
minLength: 3
maxLength: 3
resources:
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = $value }} | ConvertTo-Json

$null = $config_yaml | dsc config -p $params_json get
$LASTEXITCODE | Should -Be 4
}

It 'Input number value is out of range for <min> and <max>' -TestCases @(
@{ value = 42; min = 43; max = 44 }
@{ value = 42; min = 41; max = 41 }
@{ value = 42; min = 43; max = 41 }
) {
param($type, $value, $min, $max)

$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
parameters:
param1:
type: int
minValue: $min
maxValue: $max
resources:
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = $value }} | ConvertTo-Json

$null = $config_yaml | dsc config -p $params_json get
$LASTEXITCODE | Should -Be 4
}

It 'Input is not in the allowed value list for <type>' -TestCases @(
@{ type = 'string'; value = 'hello'; allowed = @('world', 'planet') }
@{ type = 'int'; value = 42; allowed = @(43, 44) }
) {
param($type, $value, $allowed)

$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
parameters:
param1:
type: $type
allowedValues: $($allowed | ConvertTo-Json -Compress)
resources:
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = $value }} | ConvertTo-Json

$null = $config_yaml | dsc config -p $params_json get
$LASTEXITCODE | Should -Be 4
}

It 'Length constraint is incorrectly applied to <type> with <constraint>' -TestCases @(
@{ type = 'int'; value = 42; constraint = 'minLength' }
@{ type = 'int'; value = 42; constraint = 'maxLength' }
@{ type = 'bool'; value = $true; constraint = 'minLength' }
@{ type = 'bool'; value = $true; constraint = 'maxLength' }
) {
param($type, $value, $constraint)

$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
parameters:
param1:
type: $type
${constraint}: 3
resources:
- name: Echo
type: Test/Echo
properties:
text: '[parameters(''param1'')]'
"@
$params_json = @{ parameters = @{ param1 = $value }} | ConvertTo-Json

$null = $config_yaml | dsc config -p $params_json get | ConvertFrom-Json
$LASTEXITCODE | Should -Be 4
}

It 'Default value is used when not provided' {
$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
parameters:
param1:
type: string
defaultValue: 'hello'
param2:
type: int
defaultValue: 7
param3:
type: bool
defaultValue: false
param4:
type: array
defaultValue: ['hello', 'world']
resources:
- name: Echo
type: Test/Echo
properties:
text: '[concat(parameters(''param1''),'','',parameters(''param2''),'','',parameters(''param3''),'','',parameters(''param4''))]'
"@

$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"]'
}
}
8 changes: 4 additions & 4 deletions dsc_lib/src/configure/config_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ pub struct Parameter {
#[serde(rename = "allowedValues", skip_serializing_if = "Option::is_none")]
pub allowed_values: Option<Vec<Value>>,
#[serde(rename = "minValue", skip_serializing_if = "Option::is_none")]
pub min_value: Option<Value>,
pub min_value: Option<i64>,
#[serde(rename = "maxValue", skip_serializing_if = "Option::is_none")]
pub max_value: Option<Value>,
pub max_value: Option<i64>,
#[serde(rename = "minLength", skip_serializing_if = "Option::is_none")]
pub min_length: Option<Value>,
pub min_length: Option<i64>,
#[serde(rename = "maxLength", skip_serializing_if = "Option::is_none")]
pub max_length: Option<Value>,
pub max_length: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down
28 changes: 28 additions & 0 deletions dsc_lib/src/configure/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use serde_json::Value;
use std::collections::HashMap;

pub struct Context {
pub parameters: HashMap<String, Value>,
pub _variables: HashMap<String, Value>,
pub _outputs: HashMap<String, Value>, // This is eventually for References function to get output from resources
}

impl Context {
#[must_use]
pub fn new() -> Self {
Self {
parameters: HashMap::new(),
_variables: HashMap::new(),
_outputs: HashMap::new(),
}
}
}

impl Default for Context {
fn default() -> Self {
Self::new()
}
}
Loading

0 comments on commit 6dc23d5

Please sign in to comment.