3
3
4
4
use jsonschema:: JSONSchema ;
5
5
use serde_json:: Value ;
6
- use std:: { collections:: HashMap , env, process :: Command , io:: { Write , Read } , process:: Stdio } ;
6
+ use std:: { collections:: HashMap , env, io:: { Read , Write } , process:: { Command , Stdio } } ;
7
7
use crate :: { dscerror:: DscError , dscresources:: invoke_result:: { ResourceGetResponse , ResourceSetResponse , ResourceTestResponse } } ;
8
8
use crate :: configure:: config_result:: ResourceGetResult ;
9
- use super :: { dscresource:: get_diff, resource_manifest :: { Kind , ResourceManifest , InputKind , ReturnKind , SchemaKind } , invoke_result :: { GetResult , SetResult , TestResult , ValidateResult , ExportResult } } ;
9
+ use super :: { dscresource:: get_diff, invoke_result :: { ExportResult , GetResult , SetResult , TestResult , ValidateResult } , resource_manifest :: { ArgKind , InputKind , Kind , ResourceManifest , ReturnKind , SchemaKind } } ;
10
10
use tracing:: { error, warn, info, debug, trace} ;
11
11
12
12
pub const EXIT_PROCESS_TERMINATED : i32 = 0x102 ;
@@ -54,7 +54,7 @@ pub fn invoke_get(resource: &ResourceManifest, cwd: &str, filter: &str) -> Resul
54
54
55
55
let mut env: Option < HashMap < String , String > > = None ;
56
56
let mut input_filter: Option < & str > = None ;
57
- let mut get_args = resource . get . args . clone ( ) ;
57
+ let mut args : Option < Vec < String > > = None ;
58
58
if !filter. is_empty ( ) {
59
59
verify_json ( resource, cwd, filter) ?;
60
60
@@ -65,14 +65,14 @@ pub fn invoke_get(resource: &ResourceManifest, cwd: &str, filter: &str) -> Resul
65
65
InputKind :: Stdin => {
66
66
input_filter = Some ( filter) ;
67
67
} ,
68
- InputKind :: Arg ( arg_name ) => {
69
- replace_token ( & mut get_args , & arg_name , filter) ? ;
68
+ InputKind :: Arg => {
69
+ args = process_args ( & resource . get . args , filter) ;
70
70
} ,
71
71
}
72
72
}
73
73
74
74
info ! ( "Invoking get '{}' using '{}'" , & resource. resource_type, & resource. get. executable) ;
75
- let ( exit_code, stdout, stderr) = invoke_command ( & resource. get . executable , get_args , input_filter, Some ( cwd) , env) ?;
75
+ let ( exit_code, stdout, stderr) = invoke_command ( & resource. get . executable , args , input_filter, Some ( cwd) , env) ?;
76
76
log_resource_traces ( & stderr) ;
77
77
if exit_code != 0 {
78
78
return Err ( DscError :: Command ( resource. resource_type . clone ( ) , exit_code, stderr) ) ;
@@ -114,7 +114,7 @@ pub fn invoke_get(resource: &ResourceManifest, cwd: &str, filter: &str) -> Resul
114
114
/// Error returned if the resource does not successfully set the desired state
115
115
#[ allow( clippy:: too_many_lines) ]
116
116
pub fn invoke_set ( resource : & ResourceManifest , cwd : & str , desired : & str , skip_test : bool ) -> Result < SetResult , DscError > {
117
- let Some ( set) = resource. set . as_ref ( ) else {
117
+ let Some ( set) = & resource. set else {
118
118
return Err ( DscError :: NotImplemented ( "set" . to_string ( ) ) ) ;
119
119
} ;
120
120
verify_json ( resource, cwd, desired) ?;
@@ -146,24 +146,24 @@ pub fn invoke_set(resource: &ResourceManifest, cwd: &str, desired: &str, skip_te
146
146
147
147
let mut get_env: Option < HashMap < String , String > > = None ;
148
148
let mut get_input: Option < & str > = None ;
149
- let mut get_args = resource . get . args . clone ( ) ;
149
+ let mut args : Option < Vec < String > > = None ;
150
150
match & resource. get . input {
151
151
Some ( InputKind :: Env ) => {
152
152
get_env = Some ( json_to_hashmap ( desired) ?) ;
153
153
} ,
154
154
Some ( InputKind :: Stdin ) => {
155
155
get_input = Some ( desired) ;
156
156
} ,
157
- Some ( InputKind :: Arg ( arg_token ) ) => {
158
- replace_token ( & mut get_args , arg_token , desired) ? ;
157
+ Some ( InputKind :: Arg ) => {
158
+ args = process_args ( & resource . get . args , desired) ;
159
159
} ,
160
160
None => {
161
161
// leave input as none
162
162
} ,
163
163
}
164
164
165
165
info ! ( "Getting current state for set by invoking get {} using {}" , & resource. resource_type, & resource. get. executable) ;
166
- let ( exit_code, stdout, stderr) = invoke_command ( & resource. get . executable , get_args , get_input, Some ( cwd) , get_env) ?;
166
+ let ( exit_code, stdout, stderr) = invoke_command ( & resource. get . executable , args , get_input, Some ( cwd) , get_env) ?;
167
167
log_resource_traces ( & stderr) ;
168
168
if exit_code != 0 {
169
169
return Err ( DscError :: Command ( resource. resource_type . clone ( ) , exit_code, stderr) ) ;
@@ -183,16 +183,16 @@ pub fn invoke_set(resource: &ResourceManifest, cwd: &str, desired: &str, skip_te
183
183
184
184
let mut env: Option < HashMap < String , String > > = None ;
185
185
let mut input_desired: Option < & str > = None ;
186
- let mut args = set . args . clone ( ) ;
186
+ let mut args: Option < Vec < String > > = None ;
187
187
match & set. input {
188
188
InputKind :: Env => {
189
189
env = Some ( json_to_hashmap ( desired) ?) ;
190
190
} ,
191
191
InputKind :: Stdin => {
192
192
input_desired = Some ( desired) ;
193
193
} ,
194
- InputKind :: Arg ( arg_token ) => {
195
- replace_token ( & mut args, arg_token , desired) ? ;
194
+ InputKind :: Arg => {
195
+ args = process_args ( & set . args , desired) ;
196
196
} ,
197
197
}
198
198
@@ -290,16 +290,16 @@ pub fn invoke_test(resource: &ResourceManifest, cwd: &str, expected: &str) -> Re
290
290
291
291
let mut env: Option < HashMap < String , String > > = None ;
292
292
let mut input_expected: Option < & str > = None ;
293
- let mut args = test . args . clone ( ) ;
293
+ let mut args: Option < Vec < String > > = None ;
294
294
match & test. input {
295
295
InputKind :: Env => {
296
296
env = Some ( json_to_hashmap ( expected) ?) ;
297
297
} ,
298
298
InputKind :: Stdin => {
299
299
input_expected = Some ( expected) ;
300
300
} ,
301
- InputKind :: Arg ( arg_token ) => {
302
- replace_token ( & mut args, arg_token , expected) ? ;
301
+ InputKind :: Arg => {
302
+ args = process_args ( & test . args , expected) ;
303
303
} ,
304
304
}
305
305
@@ -401,15 +401,15 @@ fn invoke_synthetic_test(resource: &ResourceManifest, cwd: &str, expected: &str)
401
401
}
402
402
403
403
/// Invoke the delete operation against a command resource.
404
- ///
404
+ ///
405
405
/// # Arguments
406
- ///
406
+ ///
407
407
/// * `resource` - The resource manifest for the command resource.
408
408
/// * `cwd` - The current working directory.
409
409
/// * `filter` - The filter to apply to the resource in JSON.
410
- ///
410
+ ///
411
411
/// # Errors
412
- ///
412
+ ///
413
413
/// Error is returned if the underlying command returns a non-zero exit code.
414
414
pub fn invoke_delete ( resource : & ResourceManifest , cwd : & str , filter : & str ) -> Result < ( ) , DscError > {
415
415
let Some ( delete) = & resource. delete else {
@@ -418,7 +418,7 @@ pub fn invoke_delete(resource: &ResourceManifest, cwd: &str, filter: &str) -> Re
418
418
419
419
let mut env: Option < HashMap < String , String > > = None ;
420
420
let mut input_filter: Option < & str > = None ;
421
- let mut delete_args = delete . args . clone ( ) ;
421
+ let mut args : Option < Vec < String > > = None ;
422
422
verify_json ( resource, cwd, filter) ?;
423
423
match & delete. input {
424
424
InputKind :: Env => {
@@ -427,13 +427,13 @@ pub fn invoke_delete(resource: &ResourceManifest, cwd: &str, filter: &str) -> Re
427
427
InputKind :: Stdin => {
428
428
input_filter = Some ( filter) ;
429
429
} ,
430
- InputKind :: Arg ( arg_name ) => {
431
- replace_token ( & mut delete_args , arg_name , filter) ? ;
430
+ InputKind :: Arg => {
431
+ args = process_args ( & delete . args , filter) ;
432
432
} ,
433
433
}
434
434
435
435
info ! ( "Invoking delete '{}' using '{}'" , & resource. resource_type, & delete. executable) ;
436
- let ( exit_code, _stdout, stderr) = invoke_command ( & delete. executable , delete_args , input_filter, Some ( cwd) , env) ?;
436
+ let ( exit_code, _stdout, stderr) = invoke_command ( & delete. executable , args , input_filter, Some ( cwd) , env) ?;
437
437
log_resource_traces ( & stderr) ;
438
438
if exit_code != 0 {
439
439
return Err ( DscError :: Command ( resource. resource_type . clone ( ) , exit_code, stderr) ) ;
@@ -464,7 +464,22 @@ pub fn invoke_validate(resource: &ResourceManifest, cwd: &str, config: &str) ->
464
464
return Err ( DscError :: NotImplemented ( "validate" . to_string ( ) ) ) ;
465
465
} ;
466
466
467
- let ( exit_code, stdout, stderr) = invoke_command ( & validate. executable , validate. args . clone ( ) , Some ( config) , Some ( cwd) , None ) ?;
467
+ let mut env: Option < HashMap < String , String > > = None ;
468
+ let mut input_config: Option < & str > = None ;
469
+ let mut args: Option < Vec < String > > = None ;
470
+ match & validate. input {
471
+ InputKind :: Env => {
472
+ env = Some ( json_to_hashmap ( config) ?) ;
473
+ } ,
474
+ InputKind :: Stdin => {
475
+ input_config = Some ( config) ;
476
+ } ,
477
+ InputKind :: Arg => {
478
+ args = process_args ( & validate. args , config) ;
479
+ } ,
480
+ }
481
+
482
+ let ( exit_code, stdout, stderr) = invoke_command ( & validate. executable , args, input_config, Some ( cwd) , env) ?;
468
483
log_resource_traces ( & stderr) ;
469
484
if exit_code != 0 {
470
485
return Err ( DscError :: Command ( resource. resource_type . clone ( ) , exit_code, stderr) ) ;
@@ -536,7 +551,27 @@ pub fn invoke_export(resource: &ResourceManifest, cwd: &str, input: Option<&str>
536
551
return Err ( DscError :: Operation ( format ! ( "Export is not supported by resource {}" , & resource. resource_type) ) )
537
552
} ;
538
553
539
- let ( exit_code, stdout, stderr) = invoke_command ( & export. executable , export. args . clone ( ) , input, Some ( cwd) , None ) ?;
554
+ let mut env: Option < HashMap < String , String > > = None ;
555
+ let mut export_input: Option < & str > = None ;
556
+ let mut args: Option < Vec < String > > = None ;
557
+ if let Some ( input) = input {
558
+ match & export. input {
559
+ Some ( InputKind :: Env ) => {
560
+ env = Some ( json_to_hashmap ( input) ?) ;
561
+ } ,
562
+ Some ( InputKind :: Stdin ) => {
563
+ export_input = Some ( input) ;
564
+ } ,
565
+ Some ( InputKind :: Arg ) => {
566
+ args = process_args ( & export. args , input) ;
567
+ } ,
568
+ None => {
569
+ // leave input as none
570
+ } ,
571
+ }
572
+ }
573
+
574
+ let ( exit_code, stdout, stderr) = invoke_command ( & export. executable , args, export_input, Some ( cwd) , env) ?;
540
575
log_resource_traces ( & stderr) ;
541
576
if exit_code != 0 {
542
577
return Err ( DscError :: Command ( resource. resource_type . clone ( ) , exit_code, stderr) ) ;
@@ -634,24 +669,30 @@ pub fn invoke_command(executable: &str, args: Option<Vec<String>>, input: Option
634
669
Ok ( ( exit_code, stdout, stderr) )
635
670
}
636
671
637
- fn replace_token ( args : & mut Option < Vec < String > > , token : & str , value : & str ) -> Result < ( ) , DscError > {
672
+ fn process_args ( args : & Option < Vec < ArgKind > > , value : & str ) -> Option < Vec < String > > {
638
673
let Some ( arg_values) = args else {
639
- return Err ( DscError :: Operation ( "No args to replace" . to_string ( ) ) ) ;
674
+ debug ! ( "No args to process" ) ;
675
+ return None ;
640
676
} ;
641
677
642
- let mut found = false ;
678
+ let mut processed_args = Vec :: < String > :: new ( ) ;
643
679
for arg in arg_values {
644
- if arg == token {
645
- found = true ;
646
- * arg = value. to_string ( ) ;
647
- }
648
- }
680
+ match arg {
681
+ ArgKind :: String ( s) => {
682
+ processed_args. push ( s. clone ( ) ) ;
683
+ } ,
684
+ ArgKind :: Json { json_input_arg, mandatory } => {
685
+ if value. is_empty ( ) && * mandatory == Some ( true ) {
686
+ continue ;
687
+ }
649
688
650
- if !found {
651
- return Err ( DscError :: Operation ( format ! ( "Token {token} not found in args" ) ) ) ;
689
+ processed_args. push ( json_input_arg. clone ( ) ) ;
690
+ processed_args. push ( value. to_string ( ) ) ;
691
+ } ,
692
+ }
652
693
}
653
694
654
- Ok ( ( ) )
695
+ Some ( processed_args )
655
696
}
656
697
657
698
fn verify_json ( resource : & ResourceManifest , cwd : & str , json : & str ) -> Result < ( ) , DscError > {
0 commit comments