Skip to content

Commit f79326f

Browse files
committed
connect output to result
1 parent 384c6fe commit f79326f

File tree

5 files changed

+80
-2
lines changed

5 files changed

+80
-2
lines changed

lib/dsc-lib/locales/en-us.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ circularDependency = "Circular dependency or unresolvable parameter references d
8080
userFunctionAlreadyDefined = "User function '%{name}' in namespace '%{namespace}' is already defined"
8181
addingUserFunction = "Adding user function '%{name}'"
8282
copyCountResultNotInteger = "Copy count result is not an integer: %{expression}"
83+
skippingOutput = "Skipping output for '%{name}' due to condition evaluating to false"
84+
outputValueNotDefined = "Output value '%{name}' is not defined"
85+
secureOutputSkipped = "Secure output '%{name}' is skipped"
86+
outputTypeNotMatched = "Output '%{name}' type does not match expected type '%{expected_type}'"
87+
copyNotSupported = "Copy for output '%{name}' is currently not supported"
8388

8489
[discovery.commandDiscovery]
8590
couldNotReadSetting = "Could not read 'resourcePath' setting"

lib/dsc-lib/src/configure/config_doc.rs

Lines changed: 1 addition & 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, fmt::Display};
10+
use std::fmt::Display;
1011

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

lib/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
}

lib/dsc-lib/src/configure/context.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub struct Context {
3636
pub system_root: PathBuf,
3737
pub user_functions: HashMap<String, UserFunctionDefinition>,
3838
pub variables: Map<String, Value>,
39+
pub outputs: Map<String, Value>,
3940
}
4041

4142
impl Context {
@@ -61,6 +62,8 @@ impl Context {
6162
system_root: get_default_os_system_root(),
6263
user_functions: HashMap::new(),
6364
variables: Map::new(),
65+
restart_required: None,
66+
outputs: Map::new(),
6467
}
6568
}
6669
}

lib/dsc-lib/src/configure/mod.rs

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

4-
use crate::configure::config_doc::{ExecutionKind, Metadata, Resource, Parameter};
54
use crate::configure::context::{Context, ProcessMode};
6-
use crate::configure::{config_doc::{IntOrExpression, RestartRequired}, parameters::Input};
5+
use crate::configure::{config_doc::{ExecutionKind, IntOrExpression, Metadata, Parameter, Resource, RestartRequired, ValueOrCopy}, parameters::Input};
76
use crate::discovery::discovery_trait::DiscoveryFilter;
87
use crate::dscerror::DscError;
98
use crate::dscresources::{
@@ -414,6 +413,10 @@ impl Configurator {
414413
result.metadata = Some(
415414
self.get_result_metadata(Operation::Get)
416415
);
416+
self.process_output()?;
417+
if !self.context.outputs.is_empty() {
418+
result.outputs = Some(self.context.outputs.clone());
419+
}
417420
Ok(result)
418421
}
419422

@@ -585,6 +588,10 @@ impl Configurator {
585588
result.metadata = Some(
586589
self.get_result_metadata(Operation::Set)
587590
);
591+
self.process_output()?;
592+
if !self.context.outputs.is_empty() {
593+
result.outputs = Some(self.context.outputs.clone());
594+
}
588595
Ok(result)
589596
}
590597

@@ -663,6 +670,10 @@ impl Configurator {
663670
result.metadata = Some(
664671
self.get_result_metadata(Operation::Test)
665672
);
673+
self.process_output()?;
674+
if !self.context.outputs.is_empty() {
675+
result.outputs = Some(self.context.outputs.clone());
676+
}
666677
Ok(result)
667678
}
668679

@@ -725,6 +736,10 @@ impl Configurator {
725736
}
726737

727738
result.result = Some(conf);
739+
self.process_output()?;
740+
if !self.context.outputs.is_empty() {
741+
result.outputs = Some(self.context.outputs.clone());
742+
}
728743
Ok(result)
729744
}
730745

@@ -739,6 +754,46 @@ impl Configurator {
739754
Ok(false)
740755
}
741756

757+
pub fn process_output(&mut self) -> Result<(), DscError> {
758+
if self.config.outputs.is_none() || self.context.execution_type == ExecutionKind::WhatIf {
759+
return Ok(());
760+
}
761+
if let Some(outputs) = &self.config.outputs {
762+
for (name, output) in outputs {
763+
if let Some(condition) = &output.condition {
764+
let condition_result = self.statement_parser.parse_and_execute(condition, &self.context)?;
765+
if condition_result != Value::Bool(true) {
766+
info!("{}", t!("configure.mod.skippingOutput", name = name));
767+
continue;
768+
}
769+
}
770+
771+
match &output.value_or_copy {
772+
ValueOrCopy::Value(value) => {
773+
let value_result = self.statement_parser.parse_and_execute(&value, &self.context)?;
774+
if output.r#type == DataType::SecureString || output.r#type == DataType::SecureObject {
775+
warn!("{}", t!("configure.mod.secureOutputSkipped", name = name));
776+
continue;
777+
}
778+
if value_result.is_string() && output.r#type != DataType::String ||
779+
value_result.is_i64() && output.r#type != DataType::Int ||
780+
value_result.is_boolean() && output.r#type != DataType::Bool ||
781+
value_result.is_array() && output.r#type != DataType::Array ||
782+
value_result.is_object() && output.r#type != DataType::Object {
783+
return Err(DscError::Validation(t!("configure.mod.outputTypeNotMatch", name = name, expected_type = output.r#type).to_string()));
784+
}
785+
self.context.outputs.insert(name.clone(), value_result);
786+
},
787+
_ => {
788+
warn!("{}", t!("configure.mod.copyNotSupported", name = name));
789+
continue;
790+
}
791+
}
792+
}
793+
}
794+
Ok(())
795+
}
796+
742797
/// Set the mounted path for the configuration.
743798
///
744799
/// # Arguments

0 commit comments

Comments
 (0)