Skip to content

Commit d9d3eee

Browse files
committed
add Import kind of resource used by the Include resource supporting a resolve operation
1 parent 93a9428 commit d9d3eee

26 files changed

+820
-378
lines changed

dsc/examples/include.dsc.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ resources:
66
type: Microsoft.DSC/Include
77
properties:
88
configurationFile: osinfo_parameters.dsc.yaml
9+
parametersFile: osinfo.parameters.yaml

dsc/include.dsc.resource.json

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,16 @@
22
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/bundled/resource/manifest.json",
33
"type": "Microsoft.DSC/Include",
44
"version": "0.1.0",
5-
"description": "Allows including a configuration file into current configuration.",
6-
"kind": "Group",
7-
"get": {
5+
"description": "Allows including a configuration file contents into current configuration.",
6+
"kind": "Import",
7+
"resolve": {
88
"executable": "dsc",
99
"args": [
10-
{
11-
"traceLevelArg": "--trace-level"
12-
},
1310
"config",
14-
"--as-group",
15-
"--as-include",
16-
"get"
17-
],
18-
"input": "stdin"
19-
},
20-
"set": {
21-
"executable": "dsc",
22-
"args": [
23-
{
24-
"traceLevelArg": "--trace-level"
25-
},
26-
"config",
27-
"--as-group",
28-
"--as-include",
29-
"set"
30-
],
31-
"input": "stdin",
32-
"implementsPretest": true,
33-
"return": "state"
34-
},
35-
"test": {
36-
"executable": "dsc",
37-
"args": [
38-
{
39-
"traceLevelArg": "--trace-level"
40-
},
41-
"config",
42-
"--as-group",
43-
"--as-include",
44-
"test"
11+
"resolve"
4512
],
4613
"input": "stdin",
47-
"return": "state"
14+
"handlingResourceType": "Microsoft.DSC/Group"
4815
},
4916
"exitCodes": {
5017
"0": "Success",

dsc/src/args.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub enum TraceFormat {
2121
#[derive(Debug, Clone, PartialEq, Eq, ValueEnum)]
2222
pub enum TraceLevel {
2323
Error,
24-
Warning,
24+
Warn,
2525
Info,
2626
Debug,
2727
Trace
@@ -33,8 +33,8 @@ pub struct Args {
3333
/// The subcommand to run
3434
#[clap(subcommand)]
3535
pub subcommand: SubCommand,
36-
#[clap(short = 'l', long, help = "Trace level to use", value_enum, default_value = "warning")]
37-
pub trace_level: TraceLevel,
36+
#[clap(short = 'l', long, help = "Trace level to use", value_enum)]
37+
pub trace_level: Option<TraceLevel>,
3838
#[clap(short = 'f', long, help = "Trace format to use", value_enum, default_value = "default")]
3939
pub trace_format: TraceFormat,
4040
}
@@ -57,9 +57,6 @@ pub enum SubCommand {
5757
// Used to inform when DSC is used as a group resource to modify it's output
5858
#[clap(long, hide = true)]
5959
as_group: bool,
60-
// Used for the Microsoft.DSC/Include resource
61-
#[clap(long, hide = true)]
62-
as_include: bool,
6360
},
6461
#[clap(name = "resource", about = "Invoke a specific DSC resource")]
6562
Resource {
@@ -123,6 +120,15 @@ pub enum ConfigSubCommand {
123120
path: Option<String>,
124121
#[clap(short = 'f', long, help = "The output format to use")]
125122
format: Option<OutputFormat>,
123+
},
124+
#[clap(name = "resolve", about = "Resolve the current configuration")]
125+
Resolve {
126+
#[clap(short = 'd', long, help = "The document to pass to the configuration or resource", conflicts_with = "path")]
127+
document: Option<String>,
128+
#[clap(short = 'p', long, help = "The path to a file used as input to the configuration or resource", conflicts_with = "document")]
129+
path: Option<String>,
130+
#[clap(short = 'f', long, help = "The output format to use")]
131+
format: Option<OutputFormat>,
126132
}
127133
}
128134

@@ -207,6 +213,7 @@ pub enum DscType {
207213
GetResult,
208214
SetResult,
209215
TestResult,
216+
ResolveResult,
210217
DscResource,
211218
ResourceManifest,
212219
Include,

dsc/src/include.rs

Lines changed: 0 additions & 15 deletions
This file was deleted.

dsc/src/main.rs

Lines changed: 8 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,7 @@ use args::{Args, SubCommand};
55
use atty::Stream;
66
use clap::{CommandFactory, Parser};
77
use clap_complete::generate;
8-
use dsc_lib::configure::config_doc::Configuration;
9-
use crate::include::Include;
108
use std::io::{self, Read};
11-
use std::fs::File;
12-
use std::path::Path;
139
use std::process::exit;
1410
use sysinfo::{Process, ProcessExt, RefreshKind, System, SystemExt, get_current_pid, ProcessRefreshKind};
1511
use tracing::{error, info, warn, debug};
@@ -20,7 +16,7 @@ use crossterm::event;
2016
use std::env;
2117

2218
pub mod args;
23-
pub mod include;
19+
pub mod resolve;
2420
pub mod resource_command;
2521
pub mod subcommand;
2622
pub mod tablewriter;
@@ -40,7 +36,7 @@ fn main() {
4036

4137
debug!("Running dsc {}", env!("CARGO_PKG_VERSION"));
4238

43-
let mut input = if atty::is(Stream::Stdin) {
39+
let input = if atty::is(Stream::Stdin) {
4440
None
4541
} else {
4642
info!("Reading input from STDIN");
@@ -70,23 +66,19 @@ fn main() {
7066
let mut cmd = Args::command();
7167
generate(shell, &mut cmd, "dsc", &mut io::stdout());
7268
},
73-
SubCommand::Config { subcommand, parameters, parameters_file, as_group, as_include} => {
74-
if as_include {
75-
input = Some(read_include_file(&input));
76-
}
77-
69+
SubCommand::Config { subcommand, parameters, parameters_file, as_group} => {
7870
if let Some(file_name) = parameters_file {
79-
info!("Reading parameters from file {}", file_name);
80-
match std::fs::read_to_string(file_name) {
81-
Ok(parameters) => subcommand::config(&subcommand, &Some(parameters), &input, &as_group, &as_include),
71+
info!("Reading parameters from file {file_name}");
72+
match std::fs::read_to_string(&file_name) {
73+
Ok(parameters) => subcommand::config(&subcommand, &Some(parameters), &input, &as_group),
8274
Err(err) => {
83-
error!("Error: Failed to read parameters file: {err}");
75+
error!("Error: Failed to read parameters file '{file_name}': {err}");
8476
exit(util::EXIT_INVALID_INPUT);
8577
}
8678
}
8779
}
8880
else {
89-
subcommand::config(&subcommand, &parameters, &input, &as_group, &as_include);
81+
subcommand::config(&subcommand, &parameters, &input, &as_group);
9082
}
9183
},
9284
SubCommand::Resource { subcommand } => {
@@ -108,96 +100,6 @@ fn main() {
108100
exit(util::EXIT_SUCCESS);
109101
}
110102

111-
fn read_include_file(input: &Option<String>) -> String {
112-
let Some(include) = input else {
113-
error!("Error: Include requires input from STDIN");
114-
exit(util::EXIT_INVALID_INPUT);
115-
};
116-
117-
// deserialize the Include input
118-
let include: Include = match serde_json::from_str(include) {
119-
Ok(include) => include,
120-
Err(err) => {
121-
error!("Error: Failed to deserialize Include input: {err}");
122-
exit(util::EXIT_INVALID_INPUT);
123-
}
124-
};
125-
126-
let path = Path::new(&include.configuration_file);
127-
if path.is_absolute() {
128-
error!("Error: Include path must be relative: {}", include.configuration_file);
129-
exit(util::EXIT_INVALID_INPUT);
130-
}
131-
132-
// check that no components of the path are '..'
133-
if path.components().any(|c| c == std::path::Component::ParentDir) {
134-
error!("Error: Include path must not contain '..': {}", include.configuration_file);
135-
exit(util::EXIT_INVALID_INPUT);
136-
}
137-
138-
// use DSC_CONFIG_ROOT env var as current directory
139-
let current_directory = match std::env::var("DSC_CONFIG_ROOT") {
140-
Ok(current_directory) => current_directory,
141-
Err(err) => {
142-
error!("Error: Could not read DSC_CONFIG_ROOT env var: {err}");
143-
exit(util::EXIT_INVALID_INPUT);
144-
}
145-
};
146-
147-
// combine the current directory with the Include path
148-
let include_path = Path::new(&current_directory).join(&include.configuration_file);
149-
150-
// read the file specified in the Include input
151-
let mut buffer: Vec<u8> = Vec::new();
152-
match File::open(&include_path) {
153-
Ok(mut file) => {
154-
match file.read_to_end(&mut buffer) {
155-
Ok(_) => (),
156-
Err(err) => {
157-
error!("Error: Failed to read file '{include_path:?}': {err}");
158-
exit(util::EXIT_INVALID_INPUT);
159-
}
160-
}
161-
},
162-
Err(err) => {
163-
error!("Error: Failed to included file '{include_path:?}': {err}");
164-
exit(util::EXIT_INVALID_INPUT);
165-
}
166-
}
167-
// convert the buffer to a string
168-
let include_content = match String::from_utf8(buffer) {
169-
Ok(input) => input,
170-
Err(err) => {
171-
error!("Error: Invalid UTF-8 sequence in included file '{include_path:?}': {err}");
172-
exit(util::EXIT_INVALID_INPUT);
173-
}
174-
};
175-
176-
// try to deserialize the Include content as YAML first
177-
let configuration: Configuration = match serde_yaml::from_str(&include_content) {
178-
Ok(configuration) => configuration,
179-
Err(_err) => {
180-
// if that fails, try to deserialize it as JSON
181-
match serde_json::from_str(&include_content) {
182-
Ok(configuration) => configuration,
183-
Err(err) => {
184-
error!("Error: Failed to read the configuration file '{include_path:?}' as YAML or JSON: {err}");
185-
exit(util::EXIT_INVALID_INPUT);
186-
}
187-
}
188-
}
189-
};
190-
191-
// serialize the Configuration as JSON
192-
match serde_json::to_string(&configuration) {
193-
Ok(json) => json,
194-
Err(err) => {
195-
error!("Error: JSON Error: {err}");
196-
exit(util::EXIT_JSON_ERROR);
197-
}
198-
}
199-
}
200-
201103
fn ctrlc_handler() {
202104
warn!("Ctrl-C received");
203105

0 commit comments

Comments
 (0)