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

[WIP] Add metadata from resources #554

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Draft
41 changes: 41 additions & 0 deletions dsc/tests/dsc_metadata.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Describe 'metadata tests' {
BeforeAll {
$config_yaml = @"
`$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
resources:
- name: Message
type: Test/Metadata
properties:
_metadata:
messages:
- hello world
"@
}

It 'can pull _metadata from config set' {
$result = $config_yaml | dsc config set | ConvertFrom-Json
$result.results.metadata.messages[0] | Should -BeExactly 'hello world'
$result.results.result.afterState | Should -Be ''
$result.hadErrors | Should -BeFalse
$result.results.Count | Should -Be 1
$LASTEXITCODE | Should -Be 0
}

# It 'can pull _metadata from config get' {
# $result = $config_yaml | dsc config get | ConvertFrom-Json
# $result.results.metadata.messages[0] | Should -BeExactly 'hello world'
# $result.results.result.actualState | Should -Be ''
# $result.hadErrors | Should -BeFalse
# $result.results.Count | Should -Be 1
# $LASTEXITCODE | Should -Be 0
# }

# It 'can pull _metadata from config test' {
# $result = $config_yaml | dsc config test | ConvertFrom-Json
# $result.results.metadata.messages[0] | Should -BeExactly 'hello world'
# $result.results.result.actualState | Should -Be ''
# $result.hadErrors | Should -BeFalse
# $result.results.Count | Should -Be 1
# $LASTEXITCODE | Should -Be 0
# }
}
2 changes: 2 additions & 0 deletions dsc_lib/src/configure/config_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ pub struct MicrosoftDscMetadata {
pub struct Metadata {
#[serde(rename = "Microsoft.DSC", skip_serializing_if = "Option::is_none")]
pub microsoft: Option<MicrosoftDscMetadata>,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub resource: Option<Value>,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
Expand Down
42 changes: 37 additions & 5 deletions dsc_lib/src/configure/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@ impl Configurator {
duration: Some(end_datetime.signed_duration_since(start_datetime).to_string()),
..Default::default()
}
)
),
resource: None
}
),
name: resource.name.clone(),
Expand Down Expand Up @@ -364,6 +365,8 @@ impl Configurator {
}

self.context.outputs.insert(format!("{}:{}", resource.resource_type, resource.name), serde_json::to_value(&set_result)?);
// Process SetResult by checking for _metadata field
let (set_result_parsed, resource_metadata) = Configurator::parse_metadata_from_set(set_result)?;
let resource_result = config_result::ResourceSetResult {
metadata: Some(
Metadata {
Expand All @@ -372,12 +375,13 @@ impl Configurator {
duration: Some(end_datetime.signed_duration_since(start_datetime).to_string()),
..Default::default()
}
)
),
resource: resource_metadata
}
),
name: resource.name.clone(),
resource_type: resource.resource_type.clone(),
result: set_result,
result: set_result_parsed,
};
result.results.push(resource_result);
}
Expand Down Expand Up @@ -426,7 +430,8 @@ impl Configurator {
duration: Some(end_datetime.signed_duration_since(start_datetime).to_string()),
..Default::default()
}
)
),
resource: None
}
),
name: resource.name.clone(),
Expand Down Expand Up @@ -598,7 +603,8 @@ impl Configurator {
duration: Some(end_datetime.signed_duration_since(self.context.start_datetime).to_string()),
security_context: Some(self.context.security_context.clone()),
}
)
),
resource: None
}
}

Expand Down Expand Up @@ -711,4 +717,30 @@ impl Configurator {
}
Ok(Some(result))
}

fn parse_metadata(mut input: Value) -> Result<(Value, Option<Value>), DscError> {
let result = input.clone();
if let Value::Object(mut map) = input.take() {
let metadata = map.remove("_metadata");
return Ok((Value::Object(map), metadata));
}
// TODO: if the after_state can't be parsed as a map, it may be because it's nested in a group like - afterState.result.afterState?
// returning original for now
return Ok((result, None))
}

fn parse_metadata_from_set(set_result: SetResult) -> Result<(SetResult, Option<Value>), DscError> {
match set_result {
SetResult::Resource(result) => {
let mut set_result_parsed = result.clone();
let (after_state, metadata) = Configurator::parse_metadata(result.after_state)?;
set_result_parsed.after_state = after_state;
return Ok((SetResult::Resource(set_result_parsed), metadata));
},
SetResult::Group(_results) => {
//Ok((SetResult::Group(results.clone()), None))
Err(DscError::NotImplemented("group resources not implemented yet".to_string()))
}
}
}
}
36 changes: 36 additions & 0 deletions tools/dsctest/dscmetadata.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/bundled/resource/manifest.json",
"type": "Test/Metadata",
"version": "0.1.0",
"get": {
"executable": "dsctest",
"args": [
"metadata",
{
"jsonInputArg": "--input",
"mandatory": true
}
]
},
"set": {
"executable": "dsctest",
"args": [
"metadata",
{
"jsonInputArg": "--input",
"mandatory": true
}
],
"return": "state"
},
"schema": {
"command": {
"executable": "dsctest",
"args": [
"schema",
"-s",
"metadata"
]
}
}
}
7 changes: 7 additions & 0 deletions tools/dsctest/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub enum Schemas {
Echo,
Exist,
ExitCode,
Metadata,
Sleep,
Trace,
WhatIf,
Expand Down Expand Up @@ -48,6 +49,12 @@ pub enum SubCommand {
input: String,
},

#[clap(name = "metadata", about = "Return the metadata")]
Metadata {
#[clap(name = "input", short, long, help = "The input to the metadata command as JSON")]
input: String,
},

#[clap(name = "schema", about = "Get the JSON schema for a subcommand")]
Schema {
#[clap(name = "subcommand", short, long, help = "The subcommand to get the schema for")]
Expand Down
15 changes: 15 additions & 0 deletions tools/dsctest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod delete;
mod echo;
mod exist;
mod exit_code;
mod metadata;
mod sleep;
mod trace;
mod whatif;
Expand All @@ -17,6 +18,7 @@ use crate::delete::Delete;
use crate::echo::Echo;
use crate::exist::{Exist, State};
use crate::exit_code::ExitCode;
use crate::metadata::Metadata;
use crate::sleep::Sleep;
use crate::trace::Trace;
use crate::whatif::WhatIf;
Expand Down Expand Up @@ -77,6 +79,16 @@ fn main() {
}
input
},
SubCommand::Metadata { input } => {
let metadata = match serde_json::from_str::<Metadata>(&input) {
Ok(metadata) => metadata,
Err(err) => {
eprintln!("Error JSON does not match schema: {err}");
std::process::exit(1);
}
};
serde_json::to_string(&metadata).unwrap()
},
SubCommand::Schema { subcommand } => {
let schema = match subcommand {
Schemas::Delete => {
Expand All @@ -91,6 +103,9 @@ fn main() {
Schemas::ExitCode => {
schema_for!(ExitCode)
},
Schemas::Metadata => {
schema_for!(Metadata)
},
Schemas::Sleep => {
schema_for!(Sleep)
},
Expand Down
19 changes: 19 additions & 0 deletions tools/dsctest/src/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Metadata {
#[serde(rename="_metadata", skip_serializing_if = "Option::is_none")]
pub metadata: Option<SubMetadata>
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct SubMetadata {
#[serde(skip_serializing_if = "Option::is_none")]
pub messages: Option<Vec<String>>
}
Loading