Skip to content

Commit

Permalink
Merge pull request #199 from SteveL-MSFT/manifest-version
Browse files Browse the repository at this point in the history
change ManifestVersion to $schema and validate
  • Loading branch information
SteveL-MSFT authored Sep 21, 2023
2 parents 57f2e89 + af2d284 commit c2fa7da
Show file tree
Hide file tree
Showing 17 changed files with 69 additions and 42 deletions.
2 changes: 1 addition & 1 deletion dsc/assertion.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"manifestVersion": "1.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "DSC/AssertionGroup",
"version": "0.1.0",
"description": "`test` will be invoked for all resources in the supplied configuration.",
Expand Down
2 changes: 1 addition & 1 deletion dsc/group.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"manifestVersion": "1.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "DSC/Group",
"version": "0.1.0",
"description": "All resources in the supplied configuration is treated as a group.",
Expand Down
2 changes: 1 addition & 1 deletion dsc/parallel.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"manifestVersion": "1.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "DSC/ParallelGroup",
"version": "0.1.0",
"description": "All resources in the supplied configuration run concurrently.",
Expand Down
4 changes: 2 additions & 2 deletions dsc/src/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use dsc_lib::{
configure::{Configurator, ErrorAction},
DscManager,
dscresources::dscresource::{ImplementedAs, Invoke},
dscresources::resource_manifest::ResourceManifest,
dscresources::resource_manifest::{import_manifest, ResourceManifest},
};
use jsonschema::{JSONSchema, ValidationError};
use serde_yaml::Value;
Expand Down Expand Up @@ -321,7 +321,7 @@ pub fn resource(subcommand: &ResourceSubCommand, format: &Option<OutputFormat>,
let Some(ref resource_manifest) = resource.manifest else {
continue;
};
let manifest = match serde_json::from_value::<ResourceManifest>(resource_manifest.clone()) {
let manifest = match import_manifest(resource_manifest.clone()) {
Ok(resource_manifest) => resource_manifest,
Err(err) => {
eprintln!("Error in manifest for {0}: {err}", resource.type_name);
Expand Down
2 changes: 1 addition & 1 deletion dsc/tests/dsc_discovery.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Describe 'tests for resource discovery' {
It 'Use DSC_RESOURCE_PATH instead of PATH when defined' {
$resourceJson = @'
{
"manifestVersion": "1.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "DSC/TestPathResource",
"version": "0.1.0",
"get": {
Expand Down
2 changes: 1 addition & 1 deletion dsc/tests/dsc_resource_input.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Describe 'tests for resource input' {
BeforeAll {
$manifest = @'
{
"manifestVersion": "1.0.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "Test/EnvVarInput",
"version": "0.1.0",
"get": {
Expand Down
2 changes: 1 addition & 1 deletion dsc/tests/dsc_set.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Describe 'config set tests' {
It 'set can be used on a resource that does not implement test' {
$manifest = @'
{
"manifestVersion": "1.0.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "Test/SetNoTest",
"version": "0.1.0",
"get": {
Expand Down
12 changes: 6 additions & 6 deletions dsc_lib/src/discovery/command_discovery.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use crate::discovery::discovery_trait::{ResourceDiscovery};
use crate::discovery::discovery_trait::ResourceDiscovery;
use crate::dscresources::dscresource::{DscResource, ImplementedAs};
use crate::dscresources::resource_manifest::ResourceManifest;
use crate::dscresources::resource_manifest::{ResourceManifest, import_manifest};
use crate::dscresources::command_resource::invoke_command;
use crate::dscerror::{DscError, StreamMessage, StreamMessageType};
use std::collections::BTreeMap;
Expand Down Expand Up @@ -71,9 +71,9 @@ impl ResourceDiscovery for CommandDiscovery {
if path.is_file() {
let file_name = path.file_name().unwrap().to_str().unwrap();
if file_name.to_lowercase().ends_with(".dsc.resource.json") {
let resource = import_manifest(&path)?;
let resource = load_manifest(&path)?;
if resource.manifest.is_some() {
let manifest = serde_json::from_value::<ResourceManifest>(resource.manifest.clone().unwrap())?;
let manifest = import_manifest(resource.manifest.clone().unwrap())?;
if manifest.provider.is_some() {
self.provider_resources.push(resource.type_name.clone());
}
Expand All @@ -90,7 +90,7 @@ impl ResourceDiscovery for CommandDiscovery {
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())?;
let manifest = import_manifest(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), None)
Expand Down Expand Up @@ -151,7 +151,7 @@ impl ResourceDiscovery for CommandDiscovery {
}
}

fn import_manifest(path: &Path) -> Result<DscResource, DscError> {
fn load_manifest(path: &Path) -> Result<DscResource, DscError> {
let file = File::open(path)?;
let reader = BufReader::new(file);
let manifest: ResourceManifest = match serde_json::from_reader(reader) {
Expand Down
27 changes: 15 additions & 12 deletions dsc_lib/src/dscerror.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub enum DscError {
#[error("Invalid configuration:\n{0}")]
InvalidConfiguration(String),

#[error("Unsupported manifest version: {0}. Must be: {1}")]
InvalidManifestSchemaVersion(String, String),

#[error("IO: {0}")]
Io(#[from] std::io::Error),

Expand Down Expand Up @@ -107,15 +110,15 @@ impl StreamMessage {
}

/// Create a new error message
///
///
/// # Arguments
///
///
/// * `message` - The message to display
/// * `resource_type_name` - The name of the resource type
/// * `resource_path` - The path to the resource
///
///
/// # Returns
///
///
/// * `StreamMessage` - The new message
#[must_use]
pub fn new_error(message: String, resource_type_name: Option<String>, resource_path: Option<String>) -> StreamMessage {
Expand All @@ -129,15 +132,15 @@ impl StreamMessage {
}

/// Create a new warning message
///
///
/// # Arguments
///
///
/// * `message` - The message to display
/// * `resource_type_name` - The name of the resource type
/// * `resource_path` - The path to the resource
///
///
/// # Returns
///
///
/// * `StreamMessage` - The new message
#[must_use]
pub fn new_warning(message: String, resource_type_name: Option<String>, resource_path: Option<String>) -> StreamMessage {
Expand All @@ -151,14 +154,14 @@ impl StreamMessage {
}

/// Print the message to the console
///
///
/// # Arguments
///
///
/// * `error_format` - The format to use for error messages
/// * `warning_format` - The format to use for warning messages
///
///
/// # Errors
///
///
/// * `DscError` - If there is an error writing to the console
pub fn print(&self, error_format:&StreamMessageType, warning_format:&StreamMessageType) -> Result<(), DscError>{
if self.message_type == StreamMessageType::Error
Expand Down
15 changes: 7 additions & 8 deletions dsc_lib/src/dscresources/dscresource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
// Licensed under the MIT License.

use dscerror::DscError;
use resource_manifest::ResourceManifest;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use super::{command_resource, dscerror, resource_manifest, invoke_result::{GetResult, SetResult, TestResult, ValidateResult, ExportResult}};
use super::{command_resource, dscerror, resource_manifest::import_manifest, invoke_result::{GetResult, SetResult, TestResult, ValidateResult, ExportResult}};

#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields)]
Expand Down Expand Up @@ -140,7 +139,7 @@ impl Invoke for DscResource {
let Some(manifest) = &self.manifest else {
return Err(DscError::MissingManifest(self.type_name.clone()));
};
let resource_manifest = serde_json::from_value::<ResourceManifest>(manifest.clone())?;
let resource_manifest = import_manifest(manifest.clone())?;
command_resource::invoke_get(&resource_manifest, &self.directory, filter)
},
}
Expand All @@ -155,7 +154,7 @@ impl Invoke for DscResource {
let Some(manifest) = &self.manifest else {
return Err(DscError::MissingManifest(self.type_name.clone()));
};
let resource_manifest = serde_json::from_value::<ResourceManifest>(manifest.clone())?;
let resource_manifest = import_manifest(manifest.clone())?;
command_resource::invoke_set(&resource_manifest, &self.directory, desired, skip_test)
},
}
Expand All @@ -172,7 +171,7 @@ impl Invoke for DscResource {
};

// if test is not directly implemented, then we need to handle it here
let resource_manifest = serde_json::from_value::<ResourceManifest>(manifest.clone())?;
let resource_manifest = import_manifest(manifest.clone())?;
if resource_manifest.test.is_none() {
let get_result = self.get(expected)?;
let desired_state = serde_json::from_str(expected)?;
Expand Down Expand Up @@ -201,7 +200,7 @@ impl Invoke for DscResource {
let Some(manifest) = &self.manifest else {
return Err(DscError::MissingManifest(self.type_name.clone()));
};
let resource_manifest = serde_json::from_value::<ResourceManifest>(manifest.clone())?;
let resource_manifest = import_manifest(manifest.clone())?;
command_resource::invoke_validate(&resource_manifest, &self.directory, config)
},
}
Expand All @@ -216,7 +215,7 @@ impl Invoke for DscResource {
let Some(manifest) = &self.manifest else {
return Err(DscError::MissingManifest(self.type_name.clone()));
};
let resource_manifest = serde_json::from_value::<ResourceManifest>(manifest.clone())?;
let resource_manifest = import_manifest(manifest.clone())?;
command_resource::get_schema(&resource_manifest, &self.directory)
},
}
Expand All @@ -231,7 +230,7 @@ impl Invoke for DscResource {
let Some(manifest) = &self.manifest else {
return Err(DscError::MissingManifest(self.type_name.clone()));
};
let resource_manifest = serde_json::from_value::<ResourceManifest>(manifest.clone())?;
let resource_manifest = import_manifest(manifest.clone())?;
command_resource::invoke_export(&resource_manifest, &self.directory)
},
}
Expand Down
29 changes: 27 additions & 2 deletions dsc_lib/src/dscresources/resource_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;

use crate::dscerror::DscError;

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ResourceManifest {
/// The version of the resource manifest schema.
#[serde(rename = "manifestVersion")]
pub manifest_version: String,
#[serde(rename = "$schema")]
pub schema_version: String,
/// The namespaced name of the resource.
#[serde(rename = "type")]
pub resource_type: String,
Expand Down Expand Up @@ -168,3 +170,26 @@ pub struct ListMethod {
/// The arguments to pass to the command to perform a List.
pub args: Option<Vec<String>>,
}

/// Import a resource manifest from a JSON value.
///
/// # Arguments
///
/// * `manifest` - The JSON value to import.
///
/// # Returns
///
/// * `Result<ResourceManifest, DscError>` - The imported resource manifest.
///
/// # Errors
///
/// * `DscError` - The JSON value is invalid or the schema version is not supported.
pub fn import_manifest(manifest: Value) -> Result<ResourceManifest, DscError> {
const MANIFEST_SCHEMA_VERSION: &str = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json";
let manifest = serde_json::from_value::<ResourceManifest>(manifest)?;
if !manifest.schema_version.eq(MANIFEST_SCHEMA_VERSION) {
return Err(DscError::InvalidManifestSchemaVersion(manifest.schema_version, MANIFEST_SCHEMA_VERSION.to_string()));
}

Ok(manifest)
}
2 changes: 1 addition & 1 deletion osinfo/osinfo.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"manifestVersion": "1.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"description": "Returns information about the operating system.",
"tags": [
"os",
Expand Down
2 changes: 1 addition & 1 deletion powershellgroup/powershellgroup.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"manifestVersion": "1.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "DSC/PowerShellGroup",
"version": "0.1.0",
"description": "Resource provider to classic DSC Powershell resources.",
Expand Down
2 changes: 1 addition & 1 deletion process/process.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"manifestVersion": "1.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"description": "Returns information about running processes.",
"type": "Microsoft/Process",
"version": "0.1.0",
Expand Down
2 changes: 1 addition & 1 deletion registry/registry.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"manifestVersion": "1.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "Microsoft.Windows/Registry",
"description": "Registry configuration provider for the Windows Registry",
"tags": [
Expand Down
2 changes: 1 addition & 1 deletion test_group_resource/testGroup.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"manifestVersion": "1.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "Test/TestGroup",
"version": "0.1.0",
"get": {
Expand Down
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 @@ -22,7 +22,7 @@ Describe 'Resource provider tests' {
It 'Error if provider resource is missing "requires" member' {
$invalid_manifest = @'
{
"manifestVersion": "1.0",
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "Test/InvalidTestGroup",
"version": "0.1.0",
"get": {
Expand Down

0 comments on commit c2fa7da

Please sign in to comment.