diff --git a/dsc/tests/dsc_config_export.tests.ps1 b/dsc/tests/dsc_config_export.tests.ps1 new file mode 100644 index 000000000..8fcf2326d --- /dev/null +++ b/dsc/tests/dsc_config_export.tests.ps1 @@ -0,0 +1,34 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe 'config export tests' { + It 'Execution information is included in config export results' { + $config_yaml = @' +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: os + type: Microsoft/OSInfo +'@ + + $out = dsc config export -i $config_yaml | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.executionInformation | Should -Not -BeNullOrEmpty + $out.executionInformation.startDatetime | Should -Not -BeNullOrEmpty + $out.executionInformation.endDatetime | Should -Not -BeNullOrEmpty + $out.executionInformation.duration | Should -Not -BeNullOrEmpty + $out.executionInformation.operation | Should -BeExactly 'export' + $out.executionInformation.executionType | Should -BeExactly 'actual' + $out.executionInformation.securityContext | Should -Not -BeNullOrEmpty + $out.executionInformation.version | Should -BeExactly (dsc --version).replace("dsc ", "") + $out.resources | Should -Not -BeNullOrEmpty + $out.resources.count | Should -Be 1 + $out.resources[0].Name | Should -Not -BeNullOrEmpty + $out.resources[0].type | Should -BeExactly 'Microsoft/OSInfo' + $out.resources[0].executionInformation | Should -Not -BeNullOrEmpty + $out.resources[0].executionInformation.duration | Should -Not -BeNullOrEmpty + $out.resources[0].properties.family | Should -BeIn @('Windows', 'Linux', 'macOS') + $out.resources[0].properties.architecture | Should -BeIn @('x86_64', 'arm64') + $out.resources[0].properties.version | Should -Not -BeNullOrEmpty + $out.resources[0].properties.bitness | Should -BeIn @(32, 64) + } +} diff --git a/lib/dsc-lib/src/configure/config_doc.rs b/lib/dsc-lib/src/configure/config_doc.rs index a4d2b42fb..5c1b93ca6 100644 --- a/lib/dsc-lib/src/configure/config_doc.rs +++ b/lib/dsc-lib/src/configure/config_doc.rs @@ -296,7 +296,7 @@ pub struct Output { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] -#[serde(deny_unknown_fields)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] #[dsc_repo_schema( base_name = "document", folder_path = "config", @@ -464,7 +464,7 @@ pub struct Sku { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] -#[serde(deny_unknown_fields)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] #[dsc_repo_schema(base_name = "document.resource", folder_path = "config")] pub struct Resource { #[serde(skip_serializing_if = "Option::is_none")] @@ -472,7 +472,7 @@ pub struct Resource { /// The fully qualified name of the resource type #[serde(rename = "type")] pub resource_type: FullyQualifiedTypeName, - #[serde(skip_serializing_if = "Option::is_none", rename = "requireVersion", alias = "apiVersion")] + #[serde(skip_serializing_if = "Option::is_none", alias = "apiVersion")] pub require_version: Option, /// A friendly name for the resource instance #[serde(default)] diff --git a/lib/dsc-lib/src/configure/mod.rs b/lib/dsc-lib/src/configure/mod.rs index 3dd32ab43..46b3968b3 100644 --- a/lib/dsc-lib/src/configure/mod.rs +++ b/lib/dsc-lib/src/configure/mod.rs @@ -50,6 +50,7 @@ pub struct Configurator { /// /// * `resource` - The resource to export. /// * `conf` - The configuration to add the results to. +/// * `input` - The input to the export operation. /// /// # Panics /// @@ -60,11 +61,15 @@ pub struct Configurator { /// This function will return an error if the underlying resource fails. pub fn add_resource_export_results_to_configuration(resource: &DscResource, conf: &mut Configuration, input: &str) -> Result { + let start_datetime = chrono::Local::now(); let export_result = resource.export(input)?; + let end_datetime = chrono::Local::now(); if resource.kind == Kind::Exporter { for instance in &export_result.actual_state { - let resource = serde_json::from_value::(instance.clone())?; + let mut resource = serde_json::from_value::(instance.clone())?; + let execution_information = ExecutionInformation::new_with_duration(&start_datetime, &end_datetime); + resource.execution_information = Some(execution_information); conf.resources.push(resource); } } else { @@ -105,7 +110,7 @@ pub fn add_resource_export_results_to_configuration(resource: &DscResource, conf } r.properties = escape_property_values(&props)?; let mut properties = serde_json::to_value(&r.properties)?; - let mut execution_information = ExecutionInformation::new(); + let mut execution_information = ExecutionInformation::new_with_duration(&start_datetime, &end_datetime); get_metadata_from_result(None, &mut properties, &mut metadata, &mut execution_information)?; r.properties = Some(properties.as_object().cloned().unwrap_or_default()); r.metadata = if metadata.microsoft.is_some() || !metadata.other.is_empty() { @@ -894,6 +899,9 @@ impl Configurator { }, } + let mut execution_information = ExecutionInformation::new(); + self.get_execution_information(Operation::Export, &mut execution_information); + conf.execution_information = Some(execution_information); result.result = Some(conf); self.process_output()?; if !self.context.outputs.is_empty() {