Skip to content

Commit

Permalink
Merge pull request #135 from PowerShell/errors_warnings
Browse files Browse the repository at this point in the history
Changed List operation errors to non-terminating warnings
  • Loading branch information
SteveL-MSFT authored Aug 4, 2023
2 parents ac90e41 + 0932f54 commit 4817663
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 10 deletions.
1 change: 1 addition & 0 deletions dsc_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ schemars = { version = "0.8.12", features = ["preserve_order"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
thiserror = "1.0"
chrono = "0.4.26"
42 changes: 36 additions & 6 deletions dsc_lib/src/discovery/command_discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::discovery::discovery_trait::{ResourceDiscovery};
use crate::dscresources::dscresource::{DscResource, ImplementedAs};
use crate::dscresources::resource_manifest::ResourceManifest;
use crate::dscresources::command_resource::invoke_command;
use crate::dscerror::DscError;
use crate::dscerror::{DscError, StreamMessage, StreamMessageType};
use std::collections::BTreeMap;
use std::env;
use std::fs::File;
Expand All @@ -15,6 +15,7 @@ use std::path::Path;
pub struct CommandDiscovery {
pub resources: BTreeMap<String, DscResource>,
provider_resources: Vec<String>,
discovery_messages: Vec<StreamMessage>, // this will later be used to display only messages for resources used in specific operation
initialized: bool,
}

Expand All @@ -23,6 +24,7 @@ impl CommandDiscovery {
CommandDiscovery {
resources: BTreeMap::new(),
provider_resources: Vec::new(),
discovery_messages: Vec::new(),
initialized: false,
}
}
Expand Down Expand Up @@ -77,31 +79,51 @@ impl ResourceDiscovery for CommandDiscovery {
// now go through the provider resources and add them to the list of resources
for provider in &self.provider_resources {
let provider_resource = self.resources.get(provider).unwrap();
let provider_type_name = provider_resource.type_name.clone();
let provider_path = provider_resource.path.clone();
let manifest = serde_json::from_value::<ResourceManifest>(provider_resource.manifest.clone().unwrap())?;
// invoke the list command
let list_command = manifest.provider.unwrap().list;
let (exit_code, stdout, stderr) = match invoke_command(&list_command.executable, list_command.args, None, Some(&provider_resource.directory))
{
Ok((exit_code, stdout, stderr)) => (exit_code, stdout, stderr),
Err(_e) => {
//TODO: add to debug stream: println!("Could not start {}: {}", list_command.executable, e);
Err(e) => {
self.discovery_messages.push(StreamMessage::new_error(
format!("Could not start {}: {}", list_command.executable, e),
Some(provider_type_name.clone()),
Some(provider_path.clone())));
continue;
},
};
if exit_code != 0 {
return Err(DscError::Operation(format!("Failed to list resources for provider {provider}: {exit_code} {stderr}")));
self.discovery_messages.push(StreamMessage::new_error(
format!("Provider failed to list resources with exit code {exit_code}: {stderr}"),
Some(provider_type_name.clone()),
Some(provider_path.clone())));
}

for line in stdout.lines() {
match serde_json::from_str::<DscResource>(line){
Result::Ok(resource) => {
if resource.requires.is_none() {
return Err(DscError::MissingRequires(provider.clone(), resource.type_name));
self.discovery_messages.push(StreamMessage::new_error(
DscError::MissingRequires(provider.clone(), resource.type_name.clone()).to_string(),
Some(resource.type_name.clone()),
Some(resource.path.clone())));

continue;
}
self.resources.insert(resource.type_name.clone(), resource);
},
Result::Err(err) => {
return Err(DscError::Operation(format!("Failed to parse resource from provider {provider}: {line} -> {err}")));
self.discovery_messages.push(StreamMessage::new_error(
format!("Failed to parse resource: {line} -> {err}"),
Some(provider_type_name.clone()),
Some(provider_path.clone())));

continue;
}
};
}
Expand All @@ -110,6 +132,14 @@ impl ResourceDiscovery for CommandDiscovery {
self.initialized = true;
Ok(())
}

fn print_initialization_messages(&mut self, error_format:StreamMessageType, warning_format:StreamMessageType) -> Result<(), DscError>{
for msg in &self.discovery_messages {
msg.print(&error_format, &warning_format)?;
}

Ok(())
}
}

fn import_manifest(path: &Path) -> Result<DscResource, DscError> {
Expand Down
3 changes: 2 additions & 1 deletion dsc_lib/src/discovery/discovery_trait.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use crate::{dscresources::dscresource::DscResource, dscerror::DscError};
use crate::{dscresources::dscresource::DscResource, dscerror::DscError, dscerror::StreamMessageType};

pub trait ResourceDiscovery {
fn discover(&self) -> Box<dyn Iterator<Item = DscResource>>;
fn initialize(&mut self) -> Result<(), DscError>;
fn print_initialization_messages(&mut self, error_format:StreamMessageType, warning_format:StreamMessageType) -> Result<(), DscError>;
}
5 changes: 3 additions & 2 deletions dsc_lib/src/discovery/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ mod command_discovery;
mod discovery_trait;

use crate::discovery::discovery_trait::ResourceDiscovery;
use crate::dscerror::DscError;
use crate::dscresources::dscresource::{DscResource};
use crate::{dscresources::dscresource::DscResource, dscerror::DscError, dscerror::StreamMessageType};
use regex::RegexBuilder;

pub struct Discovery {
Expand Down Expand Up @@ -43,6 +42,8 @@ impl Discovery {

for mut discovery_type in discovery_types {
discovery_type.initialize()?;
discovery_type.print_initialization_messages(StreamMessageType::Warning, StreamMessageType::Warning)?;

let discovered_resources = discovery_type.discover();
for resource in discovered_resources {
resources.push(resource.clone());
Expand Down
68 changes: 68 additions & 0 deletions dsc_lib/src/dscerror.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use reqwest::StatusCode;
use thiserror::Error;
use chrono::{Local, DateTime};

#[derive(Error, Debug)]
pub enum DscError {
Expand Down Expand Up @@ -63,3 +64,70 @@ pub enum DscError {
#[error("Validation: {0}")]
Validation(String),
}

#[derive(Debug)]
#[derive(PartialEq)]
pub enum StreamMessageType {
None = 0,
Data = 1,
Error = 2,
Warning = 3,
Verbose = 4,
Custom = 5
}

pub struct StreamMessage {
pub message: String,
pub message_type: StreamMessageType,
pub time: DateTime<Local>,
pub resource_type_name: String,
pub resource_path: String
}

impl Default for StreamMessage {
fn default() -> Self {
Self::new()
}
}

impl StreamMessage {
pub fn new() -> Self {
Self {
message: String::new(),
message_type: StreamMessageType::None,
time: Local::now(),
resource_type_name: String::new(),
resource_path: String::new(),
}
}
pub fn new_error(message: String, resource_type_name: Option<String>, resource_path: Option<String>) -> StreamMessage {
StreamMessage {
message,
message_type: StreamMessageType::Error,
time: Local::now(),
resource_type_name: resource_type_name.unwrap_or("None".to_string()),
resource_path: resource_path.unwrap_or("None".to_string())
}
}
pub fn new_warning(message: String, resource_type_name: Option<String>, resource_path: Option<String>) -> StreamMessage {
StreamMessage {
message,
message_type: StreamMessageType::Warning,
time: Local::now(),
resource_type_name: resource_type_name.unwrap_or("None".to_string()),
resource_path: resource_path.unwrap_or("None".to_string())
}
}
pub fn print(&self, error_format:&StreamMessageType, warning_format:&StreamMessageType) -> Result<(), DscError>{
if self.message_type == StreamMessageType::Error
{
eprintln!("{:?} -> {} {}", error_format, self.resource_type_name, self.message);
}
if self.message_type == StreamMessageType::Warning
{
eprintln!("{:?} -> {} {}", warning_format, self.resource_type_name, self.message);
}

Ok(())
}
}
2 changes: 1 addition & 1 deletion test_group_resource/tests/provider.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Describe 'Resource provider tests' {
$env:PATH += [System.IO.Path]::PathSeparator + (Resolve-Path (Resolve-Path $TestDrive -Relative))

$out = dsc resource list *invalid* 2>&1
$LASTEXITCODE | Should -Be 2
$LASTEXITCODE | Should -Be 0
,$out | Should -Match ".*?'requires'*"
}
finally {
Expand Down

0 comments on commit 4817663

Please sign in to comment.