forked from PowerShell/DSC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresource_manifest.rs
302 lines (280 loc) · 11.6 KB
/
resource_manifest.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use schemars::JsonSchema;
use semver::Version;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use crate::dscerror::DscError;
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub enum Kind {
Adapter,
Group,
Import,
Resource,
}
#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ResourceManifest {
/// The version of the resource manifest schema.
#[serde(rename = "$schema")]
pub schema_version: ManifestSchemaUri,
/// The namespaced name of the resource.
#[serde(rename = "type")]
pub resource_type: String,
/// The kind of resource.
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<Kind>,
/// The version of the resource using semantic versioning.
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: Option<GetMethod>,
/// Details how to call the Set method of the resource.
#[serde(skip_serializing_if = "Option::is_none")]
pub set: Option<SetMethod>,
/// Details how to call the Test method of the resource.
#[serde(skip_serializing_if = "Option::is_none")]
pub test: Option<TestMethod>,
/// Details how to call the Delete method of the resource.
#[serde(skip_serializing_if = "Option::is_none")]
pub delete: Option<DeleteMethod>,
/// Details how to call the Export method of the resource.
#[serde(skip_serializing_if = "Option::is_none")]
pub export: Option<ExportMethod>,
/// Details how to call the Resolve method of the resource.
#[serde(skip_serializing_if = "Option::is_none")]
pub resolve: Option<ResolveMethod>,
/// Details how to call the Validate method of the resource.
#[serde(skip_serializing_if = "Option::is_none")]
pub validate: Option<ValidateMethod>,
/// Indicates the resource is a adapter of other resources.
#[serde(skip_serializing_if = "Option::is_none")]
pub adapter: Option<Adapter>,
/// Mapping of exit codes to descriptions. Zero is always success and non-zero is always failure.
#[serde(rename = "exitCodes", skip_serializing_if = "Option::is_none")]
pub exit_codes: Option<HashMap<i32, String>>,
/// Details how to get the schema of the resource.
#[serde(skip_serializing_if = "Option::is_none")]
pub schema: Option<SchemaKind>,
}
// Defines the valid and recognized canonical URIs for the manifest schema
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq, Deserialize, Serialize, JsonSchema)]
pub enum ManifestSchemaUri {
#[default]
#[serde(rename = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.json")]
Version2024_04,
#[serde(rename = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/bundled/resource/manifest.json")]
Bundled2024_04,
#[serde(rename = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/bundled/resource/manifest.vscode.json")]
VSCode2024_04,
#[serde(rename = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/resource/manifest.json")]
Version2023_10,
#[serde(rename = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/bundled/resource/manifest.json")]
Bundled2023_10,
#[serde(rename = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/bundled/resource/manifest.vscode.json")]
VSCode2023_10,
#[serde(rename = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/resource/manifest.json")]
Version2023_08,
#[serde(rename = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json")]
Bundled2023_08,
#[serde(rename = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.vscode.json")]
VSCode2023_08,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
#[serde(untagged)]
pub enum ArgKind {
/// The argument is a string.
String(String),
/// The argument accepts the JSON input object.
Json {
/// The argument that accepts the JSON input object.
#[serde(rename = "jsonInputArg")]
json_input_arg: String,
/// Indicates if argument is mandatory which will pass an empty string if no JSON input is provided. Default is false.
mandatory: Option<bool>,
},
WhatIf {
/// The argument that serves as the what-if switch.
#[serde(rename = "whatIfSwitchArg")]
what_if_input_arg: String,
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub enum InputKind {
/// The input is accepted as environmental variables.
#[serde(rename = "env")]
Env,
/// The input is accepted as a JSON object via STDIN.
#[serde(rename = "stdin")]
Stdin,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub enum SchemaKind {
/// The schema is returned by running a command.
#[serde(rename = "command")]
Command(SchemaCommand),
/// The schema is embedded in the manifest.
#[serde(rename = "embedded")]
Embedded(Value),
/// The schema is retrieved from a URL. Required for intellisense support.
#[serde(rename = "url")]
Url(String),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct SchemaCommand {
/// The command to run to get the schema.
pub executable: String,
/// The arguments to pass to the command.
pub args: Option<Vec<String>>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub enum ReturnKind {
/// The return JSON is the state of the resource.
#[serde(rename = "state")]
State,
/// The return JSON is the state of the resource and the diff.
#[serde(rename = "stateAndDiff")]
StateAndDiff,
}
#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct GetMethod {
/// The command to run to get the state of the resource.
pub executable: String,
/// The arguments to pass to the command to perform a Get.
pub args: Option<Vec<ArgKind>>,
/// How to pass optional input for a Get.
#[serde(skip_serializing_if = "Option::is_none")]
pub input: Option<InputKind>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct SetMethod {
/// The command to run to set the state of the resource.
pub executable: String,
/// The arguments to pass to the command to perform a Set.
pub args: Option<Vec<ArgKind>>,
/// How to pass required input for a Set.
pub input: Option<InputKind>,
/// Whether to run the Test method before the Set method. True means the resource will perform its own test before running the Set method.
#[serde(rename = "implementsPretest", skip_serializing_if = "Option::is_none")]
pub pre_test: Option<bool>,
/// Indicates that the resource directly handles `_exist` as a property.
#[serde(rename = "handlesExist", skip_serializing_if = "Option::is_none")]
pub handles_exist: Option<bool>,
/// The type of return value expected from the Set method.
#[serde(rename = "return", skip_serializing_if = "Option::is_none")]
pub returns: Option<ReturnKind>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct TestMethod {
/// The command to run to test the state of the resource.
pub executable: String,
/// The arguments to pass to the command to perform a Test.
pub args: Option<Vec<ArgKind>>,
/// How to pass required input for a Test.
pub input: Option<InputKind>,
/// The type of return value expected from the Test method.
#[serde(rename = "return", skip_serializing_if = "Option::is_none")]
pub returns: Option<ReturnKind>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct DeleteMethod {
/// The command to run to delete the state of the resource.
pub executable: String,
/// The arguments to pass to the command to perform a Delete.
pub args: Option<Vec<ArgKind>>,
/// How to pass required input for a Delete.
pub input: Option<InputKind>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct ValidateMethod { // TODO: enable validation via schema or command
/// The command to run to validate the state of the resource.
pub executable: String,
/// The arguments to pass to the command to perform a Validate.
pub args: Option<Vec<ArgKind>>,
/// How to pass required input for a Validate.
pub input: Option<InputKind>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct ExportMethod {
/// The command to run to enumerate instances of the resource.
pub executable: String,
/// The arguments to pass to the command to perform a Export.
pub args: Option<Vec<ArgKind>>,
/// How to pass input for a Export.
pub input: Option<InputKind>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct ResolveMethod {
/// The command to run to enumerate instances of the resource.
pub executable: String,
/// The arguments to pass to the command to perform a Export.
pub args: Option<Vec<ArgKind>>,
/// How to pass input for a Export.
pub input: Option<InputKind>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct Adapter {
/// The way to list adapter supported resources.
pub list: ListMethod,
/// Defines how the adapter supports accepting configuraiton.
pub config: ConfigKind,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub enum ConfigKind {
/// The adapter accepts full unprocessed configuration.
#[serde(rename = "full")]
Full,
/// The adapter accepts configuration as a sequence.
#[serde(rename = "sequence")]
Sequence,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct ListMethod {
/// The command to run to list resources supported by a group resource.
pub executable: String,
/// 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> {
// TODO: enable schema version validation, if not provided, use the latest
// const MANIFEST_SCHEMA_VERSION: &str = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/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)
}
/// Validate a semantic version string.
///
/// # Arguments
///
/// * `version` - The semantic version string to validate.
///
/// # Returns
///
/// * `Result<(), Error>` - The result of the validation.
///
/// # Errors
///
/// * `Error` - The version string is not a valid semantic version.
pub fn validate_semver(version: &str) -> Result<(), semver::Error> {
Version::parse(version)?;
Ok(())
}