Skip to content
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
4 changes: 4 additions & 0 deletions dsc/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ pub enum ResourceSubCommand {
List {
/// Optional filter to apply to the list of resources
resource_name: Option<String>,
#[clap(short, long, help = "Description keyword to search for in the resource description")]
description: Option<String>,
#[clap(short, long, help = "Tag to search for in the resource tags")]
tags: Option<Vec<String>>,
},
#[clap(name = "get", about = "Invoke the get operation to a resource", arg_required_else_help = true)]
Get {
Expand Down
47 changes: 46 additions & 1 deletion dsc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ fn handle_resource_subcommand(subcommand: &ResourceSubCommand, format: &Option<O
};

match subcommand {
ResourceSubCommand::List { resource_name } => {
ResourceSubCommand::List { resource_name, description, tags } => {
match dsc.initialize_discovery() {
Ok(_) => (),
Err(err) => {
Expand All @@ -357,6 +357,51 @@ fn handle_resource_subcommand(subcommand: &ResourceSubCommand, format: &Option<O
write_table = true;
}
for resource in dsc.find_resource(&resource_name.clone().unwrap_or_default()) {
// if description is specified, skip if resource description does not contain it
if description.is_some() || tags.is_some() {
if resource.manifest.is_none() {
continue;
}

let resource_manifest = match serde_json::from_value::<ResourceManifest>(resource.clone().manifest.unwrap().clone()) {
Ok(resource_manifest) => resource_manifest,
Err(err) => {
eprintln!("Error in manifest for {0}: {err}", resource.type_name);
continue;
}
};

if description.is_some() {
if resource_manifest.description.is_none() {
continue;
}

if !resource_manifest.description.unwrap().to_lowercase().contains(&description.as_ref().unwrap().to_lowercase()) {
continue;
}
}

// if tags is specified, skip if resource tags do not contain the tags
if tags.is_some() {
if resource_manifest.tags.is_none() {
continue;
}

let mut found = false;
for tag_to_find in tags.clone().unwrap() {
for tag in resource_manifest.tags.clone().unwrap() {
if tag.to_lowercase() == tag_to_find.to_lowercase() {
found = true;
break;
}
}
}
if !found {
continue;
}
}
}

if write_table {
table.add_row(vec![
resource.type_name,
Expand Down
42 changes: 42 additions & 0 deletions dsc/tests/dsc_resource_list.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Describe 'Tests for listing resources' {
It 'dsc resource list' {
$resources = dsc resource list | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0
$resources | Should -Not -BeNullOrEmpty
$resources.Count | Should -BeGreaterThan 0
$resources.type | Should -Contain 'DSC/AssertionGroup'
$resources.type | Should -Contain 'DSC/Group'
$resources.type | Should -Contain 'DSC/ParallelGroup'
$resources.type | Should -Contain 'Microsoft/OSInfo'
}

It 'dsc resource list --tags "<tags>" and --description "<description> work' -TestCases @(
@{ tags = 'linux'; description = $null; expectedCount = 1; expectedType = 'Microsoft/OSInfo' }
@{ tags = $null; description = 'operating system'; expectedCount = 1; expectedType = 'Microsoft/OSInfo' }
@{ tags = 'linux'; description = 'operating system'; expectedCount = 1; expectedType = 'Microsoft/OSInfo' }
@{ tags = 'notfound'; description = 'operating system'; expectedCount = 0; expectedType = $null }
@{ tags = 'linux'; description = 'notfound'; expectedCount = 0; expectedType = $null }
@{ tags = 'notfound'; description = 'notfound'; expectedCount = 0; expectedType = $null }
) {
param($tags, $description, $expectedCount, $expectedType)

if ($tags -and $description) {
$resources = dsc resource list --tags $tags --description $description | ConvertFrom-Json
}
elseif ($tags) {
$resources = dsc resource list --tags $tags | ConvertFrom-Json
}
else {
$resources = dsc resource list --description $description | ConvertFrom-Json
}

$LASTEXITCODE | Should -Be 0
$resources.Count | Should -Be $expectedCount
if ($expectedCount -gt 0) {
$resources.type | Should -BeExactly $expectedType
}
}
}
2 changes: 2 additions & 0 deletions dsc_lib/src/dscresources/resource_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ pub struct ResourceManifest {
pub version: String,
/// The description of the resource.
pub description: Option<String>,
/// Tags for the resource.
pub tags: Option<Vec<String>>,
/// Details how to call the Get method of the resource.
pub get: GetMethod,
/// Details how to call the Set method of the resource.
Expand Down
7 changes: 7 additions & 0 deletions osinfo/osinfo.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"manifestVersion": "1.0",
"description": "Returns information about the operating system.",
"tags": [
"os",
"linux",
"windows",
"macos"
],
"type": "Microsoft/OSInfo",
"version": "0.1.0",
"get": {
Expand Down
4 changes: 3 additions & 1 deletion powershellgroup/powershellgroup.dsc.resource.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"type": "DSC/PowerShellGroup",
"version": "0.1.0",
"description": "Resource provider to classic DSC Powershell resources.",
"tags": [
"PowerShell"
],
"provider": {
"list": {
"executable": "pwsh",
Expand Down Expand Up @@ -56,4 +59,3 @@
"1": "Error"
}
}

5 changes: 5 additions & 0 deletions registry/registry.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"manifestVersion": "1.0",
"type": "Microsoft.Windows/Registry",
"description": "Registry configuration provider for the Windows Registry",
"tags": [
"Windows",
"NT"
],
"version": "0.1.0",
"get": {
"executable": "registry",
Expand Down