Skip to content

Commit d889da8

Browse files
author
Andrew
committed
metaconfig 1
1 parent e97747d commit d889da8

File tree

3 files changed

+164
-17
lines changed

3 files changed

+164
-17
lines changed

build.ps1

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ $filesForWindowsPackage = @(
4747
'wmi.resource.ps1',
4848
'windows_baseline.dsc.yaml',
4949
'windows_inventory.dsc.yaml'
50+
'default_settings.v1.dsc.json',
51+
'settings.dsc.json'
5052
)
5153

5254
$filesForLinuxPackage = @(
@@ -61,7 +63,9 @@ $filesForLinuxPackage = @(
6163
'powershell.dsc.resource.json',
6264
'psDscAdapter/',
6365
'RunCommandOnSet.dsc.resource.json',
64-
'runcommandonset'
66+
'runcommandonset',
67+
'default_settings.v1.dsc.json',
68+
'settings.dsc.json'
6569
)
6670

6771
$filesForMacPackage = @(
@@ -76,7 +80,9 @@ $filesForMacPackage = @(
7680
'powershell.dsc.resource.json',
7781
'psDscAdapter/',
7882
'RunCommandOnSet.dsc.resource.json',
79-
'runcommandonset'
83+
'runcommandonset',
84+
'default_settings.v1.dsc.json',
85+
'settings.dsc.json'
8086
)
8187

8288
# the list of files other than the binaries which need to be executable

dsc_lib/src/discovery/command_discovery.rs

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,44 @@ use indicatif::ProgressStyle;
1111
use linked_hash_map::LinkedHashMap;
1212
use regex::RegexBuilder;
1313
use semver::Version;
14+
use serde::Deserialize;
1415
use std::collections::{BTreeMap, HashSet, HashMap};
1516
use std::env;
1617
use std::ffi::OsStr;
1718
use std::fs;
1819
use std::fs::File;
1920
use std::io::BufReader;
2021
use std::path::{Path, PathBuf};
22+
use std::str::FromStr;
2123
use tracing::{debug, info, trace, warn, warn_span};
2224
use tracing_indicatif::span_ext::IndicatifSpanExt;
2325

26+
use crate::util::get_setting;
27+
2428
pub struct CommandDiscovery {
2529
// use BTreeMap so that the results are sorted by the typename, the Vec is sorted by version
2630
resources: BTreeMap<String, Vec<DscResource>>,
2731
adapters: BTreeMap<String, Vec<DscResource>>,
2832
adapted_resources: BTreeMap<String, Vec<DscResource>>,
2933
}
3034

35+
#[derive(Deserialize)]
36+
pub struct ResourcePathSetting {
37+
allow_env_override: bool,
38+
append_env_path: bool,
39+
directories: Vec<String>
40+
}
41+
42+
impl Default for ResourcePathSetting {
43+
fn default() -> ResourcePathSetting {
44+
ResourcePathSetting {
45+
allow_env_override: true,
46+
append_env_path: true,
47+
directories: vec![],
48+
}
49+
}
50+
}
51+
3152
impl CommandDiscovery {
3253
pub fn new() -> CommandDiscovery {
3354
CommandDiscovery {
@@ -37,31 +58,58 @@ impl CommandDiscovery {
3758
}
3859
}
3960

61+
fn get_resource_path_setting() -> Result<ResourcePathSetting, DscError>
62+
{
63+
if let Ok(v) = get_setting("resource_path") {
64+
if let Ok(resource_path_setting) = serde_json::from_value(v) {
65+
return Ok(resource_path_setting);
66+
}
67+
}
68+
69+
return Err(DscError::Operation("Could not read resource_path setting".to_string()));
70+
}
71+
4072
fn get_resource_paths() -> Result<Vec<PathBuf>, DscError>
4173
{
74+
let mut resource_path_setting = ResourcePathSetting::default();
75+
if let Ok(v) = Self::get_resource_path_setting() {
76+
resource_path_setting = v;
77+
} else {
78+
debug!("Could not read resource_path setting");
79+
}
80+
4281
let mut using_custom_path = false;
82+
let mut paths: Vec<PathBuf> = vec![];
4383

44-
// try DSC_RESOURCE_PATH env var first otherwise use PATH
45-
let path_env = if let Some(value) = env::var_os("DSC_RESOURCE_PATH") {
84+
let dsc_resource_path = env::var_os("DSC_RESOURCE_PATH");
85+
if resource_path_setting.allow_env_override && dsc_resource_path.is_some(){
86+
let value = dsc_resource_path.unwrap();
4687
debug!("Using DSC_RESOURCE_PATH: {:?}", value.to_string_lossy());
4788
using_custom_path = true;
48-
value
89+
paths.append(&mut env::split_paths(&value).collect::<Vec<_>>());
4990
} else {
50-
trace!("DSC_RESOURCE_PATH not set, trying PATH");
51-
match env::var_os("PATH") {
52-
Some(value) => {
53-
trace!("Original PATH: {:?}", value.to_string_lossy());
54-
value
55-
},
56-
None => {
57-
return Err(DscError::Operation("Failed to get PATH environment variable".to_string()));
91+
for p in resource_path_setting.directories {
92+
if let Ok(v) = PathBuf::from_str(&p) {
93+
paths.push(v);
5894
}
5995
}
60-
};
6196

62-
let mut paths = env::split_paths(&path_env).collect::<Vec<_>>();
97+
if resource_path_setting.append_env_path {
98+
trace!("Appending PATH to resource_path");
99+
match env::var_os("PATH") {
100+
Some(value) => {
101+
trace!("Original PATH: {:?}", value.to_string_lossy());
102+
paths.append(&mut env::split_paths(&value).collect::<Vec<_>>());
103+
},
104+
None => {
105+
return Err(DscError::Operation("Failed to get PATH environment variable".to_string()));
106+
}
107+
}
108+
}
109+
}
110+
63111
// remove duplicate entries
64-
let mut uniques = HashSet::new();
112+
let mut uniques: HashSet<PathBuf> = HashSet::new();
65113
paths.retain(|e|uniques.insert((*e).clone()));
66114

67115
// if exe home is not already in PATH env var then add it to env var and list of searched paths
@@ -75,13 +123,16 @@ impl CommandDiscovery {
75123
paths.push(exe_home_pb);
76124

77125
if let Ok(new_path) = env::join_paths(paths.clone()) {
78-
debug!("Using PATH: {:?}", new_path.to_string_lossy());
79126
env::set_var("PATH", &new_path);
80127
}
81128
}
82129
}
83130
};
84131

132+
if let Ok(final_resource_path) = env::join_paths(paths.clone()) {
133+
debug!("Using Resource Path: {:?}", final_resource_path.to_string_lossy());
134+
}
135+
85136
Ok(paths)
86137
}
87138
}

dsc_lib/src/util.rs

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

44
use crate::dscerror::DscError;
55
use serde_json::Value;
6+
use std::fs::File;
7+
use std::io::BufReader;
8+
use std::path::PathBuf;
9+
use std::path::Path;
10+
use std::env;
11+
use tracing::debug;
612

713
/// Return JSON string whether the input is JSON or YAML
814
///
@@ -37,3 +43,87 @@ pub fn parse_input_to_json(value: &str) -> Result<String, DscError> {
3743
}
3844
}
3945
}
46+
47+
pub fn get_setting(value_name: &str) -> Result<serde_json::Value, DscError> {
48+
49+
const SETTINGS_FILE_NAME: &str = "settings.dsc.json";
50+
// Note that default settings file name has a version that is specific to this version of dsc
51+
const DEFAULT_SETTINGS_FILE_NAME: &str = "default_settings.v1.dsc.json";
52+
53+
let mut result:serde_json::Value = serde_json::Value::Null;
54+
let mut settings_file_path : PathBuf;
55+
56+
if let Some(exe_home) = env::current_exe()?.parent() {
57+
58+
// First, get setting from the default settings file
59+
settings_file_path = exe_home.join(DEFAULT_SETTINGS_FILE_NAME);
60+
if let Ok(v) = load_value_from_json(&settings_file_path, &value_name) {
61+
result = v;
62+
debug!("Found setting '{}' in {}", &value_name, settings_file_path.to_string_lossy())
63+
} else {
64+
debug!("Did not find setting '{}' in {}", &value_name, settings_file_path.to_string_lossy())
65+
}
66+
67+
// Second, get setting from the active settings file overwriting previous value
68+
settings_file_path = exe_home.join(SETTINGS_FILE_NAME);
69+
if let Ok(v) = load_value_from_json(&settings_file_path, &value_name) {
70+
result = v;
71+
debug!("Found setting '{}' in {}", &value_name, settings_file_path.to_string_lossy())
72+
} else {
73+
debug!("Did not find setting '{}' in {}", &value_name, settings_file_path.to_string_lossy())
74+
}
75+
} else {
76+
debug!("Can't get dsc executable path");
77+
}
78+
79+
// Third, get setting from the policy settings file overwriting previous value
80+
settings_file_path = PathBuf::from(get_settings_policy_file_path());
81+
if let Ok(v) = load_value_from_json(&settings_file_path, &value_name) {
82+
result = v;
83+
debug!("Found setting '{}' in {}", &value_name, settings_file_path.to_string_lossy())
84+
} else {
85+
debug!("Did not find setting '{}' in {}", &value_name, settings_file_path.to_string_lossy())
86+
}
87+
88+
if result == serde_json::Value::Null {
89+
return Err(DscError::NotSupported(format!("Could not find '{}' in settings", value_name).to_string()));
90+
}
91+
92+
Ok(result)
93+
}
94+
95+
pub fn load_value_from_json(path: &PathBuf, value_name: &str) -> Result<serde_json::Value, DscError> {
96+
let file = File::open(path)?;
97+
let reader = BufReader::new(file);
98+
let root: serde_json::Value = match serde_json::from_reader(reader) {
99+
Ok(j) => j,
100+
Err(err) => {
101+
return Err(DscError::Json(err));
102+
}
103+
};
104+
105+
for (key, value) in root.as_object().unwrap() {
106+
if *key == value_name {
107+
return Ok(value.clone())
108+
}
109+
}
110+
111+
Err(DscError::NotSupported(value_name.to_string()))
112+
}
113+
114+
#[cfg(target_os = "windows")]
115+
fn get_settings_policy_file_path() -> String
116+
{
117+
// $env:ProgramData+"\dsc\settings.dsc.json"
118+
// This location is writable only by admins, but readable by all users
119+
let Ok(local_program_data_path) = std::env::var("ProgramData") else { return String::new(); };
120+
Path::new(&local_program_data_path).join("dsc").join("settings.dsc.json").display().to_string()
121+
}
122+
123+
#[cfg(not(target_os = "windows"))]
124+
fn get_settings_policy_file_path() -> String
125+
{
126+
// "/etc/.dsc/settings.dsc.json"
127+
// This location is writable only by admins, but readable by all users
128+
Path::new("/etc").join(".dsc").join("settings.dsc.json").display().to_string()
129+
}

0 commit comments

Comments
 (0)