Skip to content
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

Support resource version pinning #630

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
20 changes: 13 additions & 7 deletions dsc/src/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use dsc_lib::{
},
dscresources::dscresource::{Capability, ImplementedAs, Invoke},
dscresources::resource_manifest::{import_manifest, ResourceManifest},
util::ResourceFilter,
};
use rust_i18n::t;
use std::{
Expand Down Expand Up @@ -476,7 +477,12 @@ pub fn validate_config(config: &Configuration) -> Result<(), DscError> {

resource_types.push(type_name.to_lowercase().to_string());
}
dsc.find_resources(&resource_types);

let mut resource_filters: Vec<ResourceFilter> = Vec::new();
for a in resource_types {
resource_filters.push(ResourceFilter::new(a));
}
dsc.find_resources(&resource_filters);

for resource_block in resources {
let Some(type_name) = resource_block["type"].as_str() else {
Expand Down Expand Up @@ -541,33 +547,33 @@ pub fn resource(subcommand: &ResourceSubCommand) {
list_resources(&mut dsc, resource_name.as_ref(), adapter_name.as_ref(), description.as_ref(), tags.as_ref(), output_format.as_ref());
},
ResourceSubCommand::Schema { resource , output_format } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[ResourceFilter::new(resource.to_string())]);
resource_command::schema(&dsc, resource, output_format.as_ref());
},
ResourceSubCommand::Export { resource, output_format } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[ResourceFilter::new(resource.to_string())]);
resource_command::export(&mut dsc, resource, output_format.as_ref());
},
ResourceSubCommand::Get { resource, input, file: path, all, output_format } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[ResourceFilter::new(resource.to_string())]);
if *all { resource_command::get_all(&dsc, resource, output_format.as_ref()); }
else {
let parsed_input = get_input(input.as_ref(), path.as_ref());
resource_command::get(&dsc, resource, parsed_input, output_format.as_ref());
}
},
ResourceSubCommand::Set { resource, input, file: path, output_format } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[ResourceFilter::new(resource.to_string())]);
let parsed_input = get_input(input.as_ref(), path.as_ref());
resource_command::set(&dsc, resource, parsed_input, output_format.as_ref());
},
ResourceSubCommand::Test { resource, input, file: path, output_format } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[ResourceFilter::new(resource.to_string())]);
let parsed_input = get_input(input.as_ref(), path.as_ref());
resource_command::test(&dsc, resource, parsed_input, output_format.as_ref());
},
ResourceSubCommand::Delete { resource, input, file: path } => {
dsc.find_resources(&[resource.to_string()]);
dsc.find_resources(&[ResourceFilter::new(resource.to_string())]);
let parsed_input = get_input(input.as_ref(), path.as_ref());
resource_command::delete(&dsc, resource, parsed_input);
},
Expand Down
9 changes: 7 additions & 2 deletions dsc_lib/src/configure/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use self::config_doc::{Configuration, DataType, MicrosoftDscMetadata, Operation,
use self::depends_on::get_resource_invocation_order;
use self::config_result::{ConfigurationExportResult, ConfigurationGetResult, ConfigurationSetResult, ConfigurationTestResult};
use self::contraints::{check_length, check_number_limits, check_allowed_values};
use crate::util::ResourceFilter;
use indicatif::ProgressStyle;
use security_context_lib::{SecurityContext, get_security_context};
use serde_json::{Map, Value};
Expand Down Expand Up @@ -649,8 +650,12 @@ impl Configurator {
check_security_context(config.metadata.as_ref())?;

// Perform discovery of resources used in config
let required_resources = config.resources.iter().map(|p| p.resource_type.clone()).collect::<Vec<String>>();
self.discovery.find_resources(&required_resources);
let required_resource_types = config.resources.iter().map(|p| p.resource_type.clone()).collect::<Vec<String>>();
let mut resource_filters: Vec<ResourceFilter> = Vec::new();
for a in required_resource_types {
resource_filters.push(ResourceFilter::new(a));
}
self.discovery.find_resources(&resource_filters);
self.config = config;
Ok(())
}
Expand Down
34 changes: 13 additions & 21 deletions dsc_lib/src/discovery/command_discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use tracing_indicatif::span_ext::IndicatifSpanExt;

use crate::util::get_setting;
use crate::util::get_exe_path;
use crate::util::ResourceFilter;

pub struct CommandDiscovery {
// use BTreeMap so that the results are sorted by the typename, the Vec is sorted by version
Expand Down Expand Up @@ -381,34 +382,25 @@ impl ResourceDiscovery for CommandDiscovery {
Ok(resources)
}

// TODO: handle version requirements
fn find_resources(&mut self, required_resource_types: &[String]) -> Result<BTreeMap<String, DscResource>, DscError>
fn find_resources(&mut self, required_resource_types: &[ResourceFilter]) -> Result<BTreeMap<String, DscResource>, DscError>
{
debug!("Searching for resources: {:?}", required_resource_types);
self.discover_resources("*")?;

// convert required_resource_types to lowercase to handle case-insentiive search
let mut remaining_required_resource_types = required_resource_types.iter().map(|x| x.to_lowercase()).collect::<Vec<String>>();
remaining_required_resource_types.sort_unstable();
remaining_required_resource_types.dedup();

let mut remaining_required_resource_types = required_resource_types.to_vec();
let mut found_resources = BTreeMap::<String, DscResource>::new();

for (resource_name, resources) in &self.resources {
// TODO: handle version requirements
let Some(resource ) = resources.first() else {
// skip if no resources
continue;
};

if remaining_required_resource_types.contains(&resource_name.to_lowercase())
{
// remove the resource from the list of required resources
remaining_required_resource_types.retain(|x| *x != resource_name.to_lowercase());
found_resources.insert(resource_name.to_lowercase(), resource.clone());
if remaining_required_resource_types.is_empty()
{
return Ok(found_resources);
for (pos, req) in remaining_required_resource_types.iter().enumerate() {
for res in resources {
if req.matches(res) {
remaining_required_resource_types.swap_remove(pos);
found_resources.insert(resource_name.to_lowercase(), res.clone());
if remaining_required_resource_types.is_empty()
{
return Ok(found_resources);
}
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions dsc_lib/src/discovery/discovery_trait.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use crate::{dscresources::dscresource::DscResource, dscerror::DscError};
use crate::{dscresources::dscresource::DscResource, dscerror::DscError, util::ResourceFilter};
use std::collections::BTreeMap;

pub trait ResourceDiscovery {
fn discover_resources(&mut self, filter: &str) -> Result<(), DscError>;
fn discover_adapted_resources(&mut self, name_filter: &str, adapter_filter: &str) -> Result<(), DscError>;
fn list_available_resources(&mut self, type_name_filter: &str, adapter_name_filter: &str) -> Result<BTreeMap<String, Vec<DscResource>>, DscError>;
fn find_resources(&mut self, required_resource_types: &[String]) -> Result<BTreeMap<String, DscResource>, DscError>;
fn find_resources(&mut self, required_resource_types: &[ResourceFilter]) -> Result<BTreeMap<String, DscResource>, DscError>;
}
6 changes: 3 additions & 3 deletions dsc_lib/src/discovery/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod command_discovery;
mod discovery_trait;

use crate::discovery::discovery_trait::ResourceDiscovery;
use crate::{dscresources::dscresource::DscResource, dscerror::DscError};
use crate::{dscresources::dscresource::DscResource, dscerror::DscError, util::ResourceFilter};
use std::collections::BTreeMap;
use tracing::error;

Expand Down Expand Up @@ -73,7 +73,7 @@ impl Discovery {
/// # Arguments
///
/// * `required_resource_types` - The required resource types.
pub fn find_resources(&mut self, required_resource_types: &[String]) {
pub fn find_resources(&mut self, required_resource_types: &[ResourceFilter]) {
let discovery_types: Vec<Box<dyn ResourceDiscovery>> = vec![
Box::new(command_discovery::CommandDiscovery::new()),
];
Expand All @@ -90,7 +90,7 @@ impl Discovery {

for resource in discovered_resources {
self.resources.insert(resource.0.clone(), resource.1);
remaining_required_resource_types.retain(|x| *x != resource.0);
remaining_required_resource_types.retain(|x| *x.type_name_filter != resource.0);
};
}
}
Expand Down
3 changes: 2 additions & 1 deletion dsc_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use configure::config_doc::ExecutionKind;
use dscerror::DscError;
use dscresources::{dscresource::{DscResource, Invoke}, invoke_result::{GetResult, SetResult, TestResult}};
use crate::util::ResourceFilter;

pub mod configure;
pub mod discovery;
Expand Down Expand Up @@ -45,7 +46,7 @@ impl DscManager {
self.discovery.list_available_resources(type_name_filter, adapter_name_filter)
}

pub fn find_resources(&mut self, required_resource_types: &[String]) {
pub fn find_resources(&mut self, required_resource_types: &[ResourceFilter]) {
self.discovery.find_resources(required_resource_types);
}
/// Invoke the get operation on a resource.
Expand Down
30 changes: 30 additions & 0 deletions dsc_lib/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// Licensed under the MIT License.

use crate::dscerror::DscError;
use crate::dscresources::dscresource::DscResource;
use semver::VersionReq;
use semver::Version;
use serde_json::Value;
use std::fs;
use std::fs::File;
Expand All @@ -25,6 +28,33 @@ impl Default for DscSettingValue {
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct ResourceFilter {
pub type_name_filter: String,
pub version_filter: String,
version_req: VersionReq
}

impl ResourceFilter {
pub fn new(type_name_filter: String) -> Self {
Self {
type_name_filter: type_name_filter.to_lowercase(),
version_filter: ">=0.0.0".to_string(),
version_req: VersionReq::parse(">=0.0.0".to_string()).expect("Failed VersionReq parsing")
}
}

pub fn matches(self: &ResourceFilter, resource: &DscResource) -> bool {
if self.type_name_filter.eq(&resource.type_name.to_lowercase()) {
let resource_ver = Version::parse(&resource.version);
if self.version_req.matches(resource_ver) {
return true;
}
};

return false;
}
}
/// Return JSON string whether the input is JSON or YAML
///
/// # Arguments
Expand Down
Loading