Skip to content

Changed List operation errors to non-terminating warnings #135

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

Merged
merged 9 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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