Skip to content

Commit 2ea358f

Browse files
committed
connect output to result
1 parent 73d4cbf commit 2ea358f

File tree

5 files changed

+93
-1
lines changed

5 files changed

+93
-1
lines changed

dsc_lib/locales/en-us.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ propertyNotString = "Property '%{name}' with value '%{value}' is not a string"
7171
metadataMicrosoftDscIgnored = "Resource returned '_metadata' property 'Microsoft.DSC' which is ignored"
7272
metadataNotObject = "Resource returned '_metadata' property which is not an object"
7373
metadataRestartRequiredInvalid = "Resource returned '_metadata' property '_restartRequired' which contains invalid value: %{value}"
74+
skippingOutput = "Skipping output for '%{name}' due to condition evaluating to false"
75+
outputValueNotDefined = "Output value '%{name}' is not defined"
76+
secureOutputSkipped = "Secure output '%{name}' is skipped"
77+
outputTypeNotMatched = "Output '%{name}' type does not match expected type '%{expected_type}'"
78+
copyNotSupported = "Copy for output '%{name}' is currently not supported"
7479

7580
[discovery.commandDiscovery]
7681
couldNotReadSetting = "Could not read 'resourcePath' setting"

dsc_lib/src/configure/config_doc.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use schemars::{JsonSchema, json_schema};
77
use serde::{Deserialize, Serialize};
88
use serde_json::{Map, Value};
99
use std::collections::HashMap;
10+
use std::fmt::Display;
1011

1112
use crate::{dscerror::DscError, schemas::DscRepoSchema};
1213

@@ -180,6 +181,20 @@ pub enum DataType {
180181
Array,
181182
}
182183

184+
impl Display for DataType {
185+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186+
match self {
187+
DataType::String => write!(f, "string"),
188+
DataType::SecureString => write!(f, "secureString"),
189+
DataType::Int => write!(f, "int"),
190+
DataType::Bool => write!(f, "bool"),
191+
DataType::Object => write!(f, "object"),
192+
DataType::SecureObject => write!(f, "secureObject"),
193+
DataType::Array => write!(f, "array"),
194+
}
195+
}
196+
}
197+
183198
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
184199
pub enum CopyMode {
185200
#[serde(rename = "serial")]

dsc_lib/src/configure/config_result.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use schemars::JsonSchema;
55
use serde::{Deserialize, Serialize};
6+
use serde_json::{Map, Value};
67
use crate::dscresources::invoke_result::{GetResult, SetResult, TestResult};
78
use crate::configure::config_doc::{Configuration, Metadata};
89

@@ -54,6 +55,8 @@ pub struct ConfigurationGetResult {
5455
pub messages: Vec<ResourceMessage>,
5556
#[serde(rename = "hadErrors")]
5657
pub had_errors: bool,
58+
#[serde(skip_serializing_if = "Option::is_none")]
59+
pub outputs: Option<Map<String, Value>>,
5760
}
5861

5962
impl ConfigurationGetResult {
@@ -64,6 +67,7 @@ impl ConfigurationGetResult {
6467
results: Vec::new(),
6568
messages: Vec::new(),
6669
had_errors: false,
70+
outputs: None,
6771
}
6872
}
6973
}
@@ -85,6 +89,7 @@ impl From<ConfigurationTestResult> for ConfigurationGetResult {
8589
results,
8690
messages: test_result.messages,
8791
had_errors: test_result.had_errors,
92+
outputs: test_result.outputs,
8893
}
8994
}
9095
}
@@ -140,6 +145,8 @@ pub struct ConfigurationSetResult {
140145
pub messages: Vec<ResourceMessage>,
141146
#[serde(rename = "hadErrors")]
142147
pub had_errors: bool,
148+
#[serde(skip_serializing_if = "Option::is_none")]
149+
pub outputs: Option<Map<String, Value>>,
143150
}
144151

145152
impl ConfigurationSetResult {
@@ -150,6 +157,7 @@ impl ConfigurationSetResult {
150157
results: Vec::new(),
151158
messages: Vec::new(),
152159
had_errors: false,
160+
outputs: None,
153161
}
154162
}
155163
}
@@ -200,6 +208,8 @@ pub struct ConfigurationTestResult {
200208
pub messages: Vec<ResourceMessage>,
201209
#[serde(rename = "hadErrors")]
202210
pub had_errors: bool,
211+
#[serde(skip_serializing_if = "Option::is_none")]
212+
pub outputs: Option<Map<String, Value>>,
203213
}
204214

205215
impl ConfigurationTestResult {
@@ -210,6 +220,7 @@ impl ConfigurationTestResult {
210220
results: Vec::new(),
211221
messages: Vec::new(),
212222
had_errors: false,
223+
outputs: None,
213224
}
214225
}
215226
}
@@ -228,6 +239,8 @@ pub struct ConfigurationExportResult {
228239
pub messages: Vec<ResourceMessage>,
229240
#[serde(rename = "hadErrors")]
230241
pub had_errors: bool,
242+
#[serde(skip_serializing_if = "Option::is_none")]
243+
pub outputs: Option<Map<String, Value>>,
231244
}
232245

233246
impl ConfigurationExportResult {
@@ -238,6 +251,7 @@ impl ConfigurationExportResult {
238251
result: None,
239252
messages: Vec::new(),
240253
had_errors: false,
254+
outputs: None,
241255
}
242256
}
243257
}

dsc_lib/src/configure/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub struct Context {
1919
pub variables: Map<String, Value>,
2020
pub start_datetime: DateTime<Local>,
2121
pub restart_required: Option<Vec<RestartRequired>>,
22+
pub outputs: Map<String, Value>,
2223
}
2324

2425
impl Context {
@@ -37,6 +38,7 @@ impl Context {
3738
variables: Map::new(),
3839
start_datetime: chrono::Local::now(),
3940
restart_required: None,
41+
outputs: Map::new(),
4042
}
4143
}
4244
}

dsc_lib/src/configure/mod.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
use crate::configure::config_doc::{ExecutionKind, Metadata, Resource};
4+
use crate::configure::config_doc::{ExecutionKind, Metadata, Resource, ValueOrCopy};
55
use crate::configure::{config_doc::RestartRequired, parameters::Input};
66
use crate::dscerror::DscError;
77
use crate::dscresources::invoke_result::ExportResult;
@@ -376,6 +376,10 @@ impl Configurator {
376376
result.metadata = Some(
377377
self.get_result_metadata(Operation::Get)
378378
);
379+
self.process_output()?;
380+
if !self.context.outputs.is_empty() {
381+
result.outputs = Some(self.context.outputs.clone());
382+
}
379383
Ok(result)
380384
}
381385

@@ -533,6 +537,10 @@ impl Configurator {
533537
result.metadata = Some(
534538
self.get_result_metadata(Operation::Set)
535539
);
540+
self.process_output()?;
541+
if !self.context.outputs.is_empty() {
542+
result.outputs = Some(self.context.outputs.clone());
543+
}
536544
Ok(result)
537545
}
538546

@@ -607,6 +615,10 @@ impl Configurator {
607615
result.metadata = Some(
608616
self.get_result_metadata(Operation::Test)
609617
);
618+
self.process_output()?;
619+
if !self.context.outputs.is_empty() {
620+
result.outputs = Some(self.context.outputs.clone());
621+
}
610622
Ok(result)
611623
}
612624

@@ -665,6 +677,10 @@ impl Configurator {
665677
}
666678

667679
result.result = Some(conf);
680+
self.process_output()?;
681+
if !self.context.outputs.is_empty() {
682+
result.outputs = Some(self.context.outputs.clone());
683+
}
668684
Ok(result)
669685
}
670686

@@ -679,6 +695,46 @@ impl Configurator {
679695
Ok(false)
680696
}
681697

698+
pub fn process_output(&mut self) -> Result<(), DscError> {
699+
if self.config.outputs.is_none() || self.context.execution_type == ExecutionKind::WhatIf {
700+
return Ok(());
701+
}
702+
if let Some(outputs) = &self.config.outputs {
703+
for (name, output) in outputs {
704+
if let Some(condition) = &output.condition {
705+
let condition_result = self.statement_parser.parse_and_execute(condition, &self.context)?;
706+
if condition_result != Value::Bool(true) {
707+
info!("{}", t!("configure.mod.skippingOutput", name = name));
708+
continue;
709+
}
710+
}
711+
712+
match &output.value_or_copy {
713+
ValueOrCopy::Value(value) => {
714+
let value_result = self.statement_parser.parse_and_execute(&value, &self.context)?;
715+
if output.r#type == DataType::SecureString || output.r#type == DataType::SecureObject {
716+
warn!("{}", t!("configure.mod.secureOutputSkipped", name = name));
717+
continue;
718+
}
719+
if value_result.is_string() && output.r#type != DataType::String ||
720+
value_result.is_i64() && output.r#type != DataType::Int ||
721+
value_result.is_boolean() && output.r#type != DataType::Bool ||
722+
value_result.is_array() && output.r#type != DataType::Array ||
723+
value_result.is_object() && output.r#type != DataType::Object {
724+
return Err(DscError::Validation(t!("configure.mod.outputTypeNotMatch", name = name, expected_type = output.r#type).to_string()));
725+
}
726+
self.context.outputs.insert(name.clone(), value_result);
727+
},
728+
_ => {
729+
warn!("{}", t!("configure.mod.copyNotSupported", name = name));
730+
continue;
731+
}
732+
}
733+
}
734+
}
735+
Ok(())
736+
}
737+
682738
/// Set the mounted path for the configuration.
683739
///
684740
/// # Arguments

0 commit comments

Comments
 (0)