Skip to content

Commit 4817663

Browse files
authored
Merge pull request #135 from PowerShell/errors_warnings
Changed List operation errors to non-terminating warnings
2 parents ac90e41 + 0932f54 commit 4817663

File tree

6 files changed

+111
-10
lines changed

6 files changed

+111
-10
lines changed

dsc_lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ schemars = { version = "0.8.12", features = ["preserve_order"] }
1212
serde = { version = "1.0", features = ["derive"] }
1313
serde_json = { version = "1.0", features = ["preserve_order"] }
1414
thiserror = "1.0"
15+
chrono = "0.4.26"

dsc_lib/src/discovery/command_discovery.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::discovery::discovery_trait::{ResourceDiscovery};
55
use crate::dscresources::dscresource::{DscResource, ImplementedAs};
66
use crate::dscresources::resource_manifest::ResourceManifest;
77
use crate::dscresources::command_resource::invoke_command;
8-
use crate::dscerror::DscError;
8+
use crate::dscerror::{DscError, StreamMessage, StreamMessageType};
99
use std::collections::BTreeMap;
1010
use std::env;
1111
use std::fs::File;
@@ -15,6 +15,7 @@ use std::path::Path;
1515
pub struct CommandDiscovery {
1616
pub resources: BTreeMap<String, DscResource>,
1717
provider_resources: Vec<String>,
18+
discovery_messages: Vec<StreamMessage>, // this will later be used to display only messages for resources used in specific operation
1819
initialized: bool,
1920
}
2021

@@ -23,6 +24,7 @@ impl CommandDiscovery {
2324
CommandDiscovery {
2425
resources: BTreeMap::new(),
2526
provider_resources: Vec::new(),
27+
discovery_messages: Vec::new(),
2628
initialized: false,
2729
}
2830
}
@@ -77,31 +79,51 @@ impl ResourceDiscovery for CommandDiscovery {
7779
// now go through the provider resources and add them to the list of resources
7880
for provider in &self.provider_resources {
7981
let provider_resource = self.resources.get(provider).unwrap();
82+
let provider_type_name = provider_resource.type_name.clone();
83+
let provider_path = provider_resource.path.clone();
8084
let manifest = serde_json::from_value::<ResourceManifest>(provider_resource.manifest.clone().unwrap())?;
8185
// invoke the list command
8286
let list_command = manifest.provider.unwrap().list;
8387
let (exit_code, stdout, stderr) = match invoke_command(&list_command.executable, list_command.args, None, Some(&provider_resource.directory))
8488
{
8589
Ok((exit_code, stdout, stderr)) => (exit_code, stdout, stderr),
86-
Err(_e) => {
87-
//TODO: add to debug stream: println!("Could not start {}: {}", list_command.executable, e);
90+
Err(e) => {
91+
self.discovery_messages.push(StreamMessage::new_error(
92+
format!("Could not start {}: {}", list_command.executable, e),
93+
Some(provider_type_name.clone()),
94+
Some(provider_path.clone())));
95+
8896
continue;
8997
},
9098
};
9199

92100
if exit_code != 0 {
93-
return Err(DscError::Operation(format!("Failed to list resources for provider {provider}: {exit_code} {stderr}")));
101+
self.discovery_messages.push(StreamMessage::new_error(
102+
format!("Provider failed to list resources with exit code {exit_code}: {stderr}"),
103+
Some(provider_type_name.clone()),
104+
Some(provider_path.clone())));
94105
}
106+
95107
for line in stdout.lines() {
96108
match serde_json::from_str::<DscResource>(line){
97109
Result::Ok(resource) => {
98110
if resource.requires.is_none() {
99-
return Err(DscError::MissingRequires(provider.clone(), resource.type_name));
111+
self.discovery_messages.push(StreamMessage::new_error(
112+
DscError::MissingRequires(provider.clone(), resource.type_name.clone()).to_string(),
113+
Some(resource.type_name.clone()),
114+
Some(resource.path.clone())));
115+
116+
continue;
100117
}
101118
self.resources.insert(resource.type_name.clone(), resource);
102119
},
103120
Result::Err(err) => {
104-
return Err(DscError::Operation(format!("Failed to parse resource from provider {provider}: {line} -> {err}")));
121+
self.discovery_messages.push(StreamMessage::new_error(
122+
format!("Failed to parse resource: {line} -> {err}"),
123+
Some(provider_type_name.clone()),
124+
Some(provider_path.clone())));
125+
126+
continue;
105127
}
106128
};
107129
}
@@ -110,6 +132,14 @@ impl ResourceDiscovery for CommandDiscovery {
110132
self.initialized = true;
111133
Ok(())
112134
}
135+
136+
fn print_initialization_messages(&mut self, error_format:StreamMessageType, warning_format:StreamMessageType) -> Result<(), DscError>{
137+
for msg in &self.discovery_messages {
138+
msg.print(&error_format, &warning_format)?;
139+
}
140+
141+
Ok(())
142+
}
113143
}
114144

115145
fn import_manifest(path: &Path) -> Result<DscResource, DscError> {
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
use crate::{dscresources::dscresource::DscResource, dscerror::DscError};
4+
use crate::{dscresources::dscresource::DscResource, dscerror::DscError, dscerror::StreamMessageType};
55

66
pub trait ResourceDiscovery {
77
fn discover(&self) -> Box<dyn Iterator<Item = DscResource>>;
88
fn initialize(&mut self) -> Result<(), DscError>;
9+
fn print_initialization_messages(&mut self, error_format:StreamMessageType, warning_format:StreamMessageType) -> Result<(), DscError>;
910
}

dsc_lib/src/discovery/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ mod command_discovery;
55
mod discovery_trait;
66

77
use crate::discovery::discovery_trait::ResourceDiscovery;
8-
use crate::dscerror::DscError;
9-
use crate::dscresources::dscresource::{DscResource};
8+
use crate::{dscresources::dscresource::DscResource, dscerror::DscError, dscerror::StreamMessageType};
109
use regex::RegexBuilder;
1110

1211
pub struct Discovery {
@@ -43,6 +42,8 @@ impl Discovery {
4342

4443
for mut discovery_type in discovery_types {
4544
discovery_type.initialize()?;
45+
discovery_type.print_initialization_messages(StreamMessageType::Warning, StreamMessageType::Warning)?;
46+
4647
let discovered_resources = discovery_type.discover();
4748
for resource in discovered_resources {
4849
resources.push(resource.clone());

dsc_lib/src/dscerror.rs

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

44
use reqwest::StatusCode;
55
use thiserror::Error;
6+
use chrono::{Local, DateTime};
67

78
#[derive(Error, Debug)]
89
pub enum DscError {
@@ -63,3 +64,70 @@ pub enum DscError {
6364
#[error("Validation: {0}")]
6465
Validation(String),
6566
}
67+
68+
#[derive(Debug)]
69+
#[derive(PartialEq)]
70+
pub enum StreamMessageType {
71+
None = 0,
72+
Data = 1,
73+
Error = 2,
74+
Warning = 3,
75+
Verbose = 4,
76+
Custom = 5
77+
}
78+
79+
pub struct StreamMessage {
80+
pub message: String,
81+
pub message_type: StreamMessageType,
82+
pub time: DateTime<Local>,
83+
pub resource_type_name: String,
84+
pub resource_path: String
85+
}
86+
87+
impl Default for StreamMessage {
88+
fn default() -> Self {
89+
Self::new()
90+
}
91+
}
92+
93+
impl StreamMessage {
94+
pub fn new() -> Self {
95+
Self {
96+
message: String::new(),
97+
message_type: StreamMessageType::None,
98+
time: Local::now(),
99+
resource_type_name: String::new(),
100+
resource_path: String::new(),
101+
}
102+
}
103+
pub fn new_error(message: String, resource_type_name: Option<String>, resource_path: Option<String>) -> StreamMessage {
104+
StreamMessage {
105+
message,
106+
message_type: StreamMessageType::Error,
107+
time: Local::now(),
108+
resource_type_name: resource_type_name.unwrap_or("None".to_string()),
109+
resource_path: resource_path.unwrap_or("None".to_string())
110+
}
111+
}
112+
pub fn new_warning(message: String, resource_type_name: Option<String>, resource_path: Option<String>) -> StreamMessage {
113+
StreamMessage {
114+
message,
115+
message_type: StreamMessageType::Warning,
116+
time: Local::now(),
117+
resource_type_name: resource_type_name.unwrap_or("None".to_string()),
118+
resource_path: resource_path.unwrap_or("None".to_string())
119+
}
120+
}
121+
pub fn print(&self, error_format:&StreamMessageType, warning_format:&StreamMessageType) -> Result<(), DscError>{
122+
if self.message_type == StreamMessageType::Error
123+
{
124+
eprintln!("{:?} -> {} {}", error_format, self.resource_type_name, self.message);
125+
}
126+
if self.message_type == StreamMessageType::Warning
127+
{
128+
eprintln!("{:?} -> {} {}", warning_format, self.resource_type_name, self.message);
129+
}
130+
131+
Ok(())
132+
}
133+
}

test_group_resource/tests/provider.tests.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ Describe 'Resource provider tests' {
5656
$env:PATH += [System.IO.Path]::PathSeparator + (Resolve-Path (Resolve-Path $TestDrive -Relative))
5757

5858
$out = dsc resource list *invalid* 2>&1
59-
$LASTEXITCODE | Should -Be 2
59+
$LASTEXITCODE | Should -Be 0
6060
,$out | Should -Match ".*?'requires'*"
6161
}
6262
finally {

0 commit comments

Comments
 (0)