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

Config discovery #6

Merged
merged 2 commits into from
Dec 15, 2022
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
19 changes: 19 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug config",
"program": "${workspaceFolder}/config/target/debug/config",
"args": [
"list",
"r*"
],
"cwd": "${workspaceFolder}"
}
]
}
1 change: 1 addition & 0 deletions config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition = "2021"
[dependencies]
atty = { version = "0.2" }
clap = { version = "3.2", features = ["derive"] }
regex = "1.7"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
thiserror = "1.0"
45 changes: 28 additions & 17 deletions config/src/discovery/command_discovery.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,41 @@
// find resources via PATH
// reuse code from https://github.com/PowerShell/MSH/blob/main/config/src/main.rs

use crate::dscerror::DscError;
use crate::discovery::discovery_trait::{ResourceDiscovery};
use crate::dscresources::dscresource::DscResource;
use crate::dscresources::dscresource::{DscResource, ImplementedAs};

pub struct CommandDiscovery {
pub command: String,
pub resources: Vec<DscResource>,
}

pub struct CommandIterator {
pub command: String,
impl CommandDiscovery {
pub fn new() -> CommandDiscovery {
CommandDiscovery {
resources: Vec::new(),
}
}
}

impl Iterator for CommandIterator {
type Item = DscResource;

fn next(&mut self) -> Option<Self::Item> {
None
impl Default for CommandDiscovery {
fn default() -> Self {
Self::new()
}
}

impl ResourceDiscovery for CommandDiscovery {
fn discover(&self, _filter: Option<String>) -> Result<Box<dyn Iterator<Item = DscResource>>, DscError> {
Ok(Box::new(CommandIterator {
command: self.command.clone(),
}))
fn discover(&self) -> Box<dyn Iterator<Item = DscResource>> {
// find resources via PATH including .ps1 resources so PATH doesn't need to be traversed more than once
// reuse code from https://github.com/PowerShell/MSH/blob/main/config/src/main.rs
// these are just test resources
let mut sshd_resource = DscResource::new();
sshd_resource.name = "SSHDConfig".to_string();
sshd_resource.implemented_as = ImplementedAs::Command;
let mut registry_resource = DscResource::new();
registry_resource.name = "Registry".to_string();
registry_resource.implemented_as = ImplementedAs::Command;

let resources = vec![
sshd_resource,
registry_resource,
];

Box::new(resources.into_iter())
}
}
5 changes: 1 addition & 4 deletions config/src/discovery/discovery_trait.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use dscerror::DscError;
use crate::dscresources::dscresource::DscResource;

use super::*;

pub trait ResourceDiscovery {
fn discover(&self, filter: Option<String>) -> Result<Box<dyn Iterator<Item = DscResource>>, DscError>;
fn discover(&self) -> Box<dyn Iterator<Item = DscResource>>;
}
106 changes: 105 additions & 1 deletion config/src/discovery/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,108 @@ pub mod command_discovery;
pub mod discovery_trait;
pub mod powershell_discovery;

use super::*;
use crate::discovery::discovery_trait::ResourceDiscovery;
use crate::dscresources::dscresource::DscResource;
use regex::{RegexBuilder};

pub struct Discovery {
resources: Vec<DscResource>,
}

impl Discovery {
pub fn new() -> Discovery {
let discovery_types: Vec<Box<dyn ResourceDiscovery>> = vec![
Box::new(command_discovery::CommandDiscovery::new()),
Box::new(powershell_discovery::PowerShellDiscovery::new()),
];

let mut resources: Vec<DscResource> = Vec::new();

for discovery_type in discovery_types {
let discovered_resources = discovery_type.discover();
for resource in discovered_resources {
resources.push(resource);
}
}

Discovery {
resources,
}
}

pub fn find_resource(&self, resource_name: &str) -> ResourceIterator {
let mut regex_builder = RegexBuilder::new(convert_wildcard_to_regex(resource_name).as_str());
regex_builder.case_insensitive(true);
let regex = regex_builder.build().unwrap();

let mut resources: Vec<DscResource> = Vec::new();
for resource in &self.resources {
if resource_name.is_empty() | regex.is_match(resource.name.as_str()) {
resources.push(resource.clone());
}
}

ResourceIterator::new(resources)
}
}

fn convert_wildcard_to_regex(wildcard: &str) -> String {
let mut regex = wildcard.to_string().replace('*', ".*").replace('?', ".");
regex.insert(0, '^');
regex.push('$');
regex
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_convert_wildcard_to_regex() {
let wildcard = "*";
let regex = convert_wildcard_to_regex(wildcard);
assert_eq!(regex, "^.*$");

let wildcard = "File";
let regex = convert_wildcard_to_regex(wildcard);
assert_eq!(regex, "^File$");

let wildcard = "r*";
let regex = convert_wildcard_to_regex(wildcard);
assert_eq!(regex, "^r.*$");
}
}

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

pub struct ResourceIterator {
resources: Vec<DscResource>,
index: usize,
}

impl ResourceIterator {
pub fn new(resources: Vec<DscResource>) -> ResourceIterator {
ResourceIterator {
resources,
index: 0,
}
}
}

impl Iterator for ResourceIterator {
type Item = DscResource;

fn next(&mut self) -> Option<Self::Item> {
if self.index < self.resources.len() {
let resource = self.resources[self.index].clone();
self.index += 1;
Some(resource)
} else {
None
}
}
}
41 changes: 40 additions & 1 deletion config/src/discovery/powershell_discovery.rs
Original file line number Diff line number Diff line change
@@ -1 +1,40 @@
// use `Get-DscResource` to convert to config resources
use crate::discovery::discovery_trait::{ResourceDiscovery};
use crate::dscresources::dscresource::{DscResource, ImplementedAs};

pub struct PowerShellDiscovery {
pub resources: Vec<DscResource>,
}

impl PowerShellDiscovery {
pub fn new() -> PowerShellDiscovery {
PowerShellDiscovery {
resources: Vec::new(),
}
}
}

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

impl ResourceDiscovery for PowerShellDiscovery {
fn discover(&self) -> Box<dyn Iterator<Item = DscResource>> {
// use `Get-DscResource` to convert to config resources
// these are just test resources
let mut file_resource = DscResource::new();
file_resource.name = "File".to_string();
file_resource.implemented_as = ImplementedAs::PowerShell;
let mut registry_resource = DscResource::new();
registry_resource.name = "PSGet".to_string();
registry_resource.implemented_as = ImplementedAs::PowerShell;

let resources = vec![
file_resource,
registry_resource,
];

Box::new(resources.into_iter())
}
}
4 changes: 2 additions & 2 deletions config/src/dscresources/dscresource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use dscerror::DscError;
use serde::Serialize;
use super::*;

#[derive(Debug, Serialize)]
#[derive(Clone, Debug, Serialize)]
pub struct DscResource {
#[serde(rename="ImplementationDetail")]
pub implementation_detail: String,
Expand Down Expand Up @@ -31,7 +31,7 @@ pub struct DscResource {
command_line: String,
}

#[derive(Debug, Serialize)]
#[derive(Clone, Debug, Serialize)]
pub enum ImplementedAs {
PowerShell,
PowerShellScript, // .ps1
Expand Down
5 changes: 4 additions & 1 deletion config/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ fn main() {

match args.subcommand {
SubCommand::List { resource_name } => {
println!("List {}", resource_name.unwrap_or_default());
let discovery = discovery::Discovery::new();
for resource in discovery.find_resource(&resource_name.unwrap_or_default()) {
println!("{} = {:?}", resource.name, resource.implemented_as);
}
}
SubCommand::Get { resource_name } => {
println!("Get {}: {}", resource_name, stdin.unwrap_or_default());
Expand Down