11//! This module allows application of settings from URIs or stdin. The inputs are expected to be
22//! TOML settings files, in the same format as user data, or the JSON equivalent. The inputs are
33//! pulled and applied to the API server in a single transaction.
4- use aws_sdk_secretsmanager :: config :: http :: HttpResponse as SdkHttpResponse ;
4+ use crate :: apply :: error :: ResolverFailureSnafu ;
55use crate :: rando;
66use futures:: future:: { join, ready} ;
77use futures:: stream:: { self , StreamExt } ;
@@ -11,7 +11,6 @@ use snafu::{OptionExt, ResultExt};
1111use std:: convert:: TryFrom ;
1212use std:: path:: Path ;
1313
14-
1514/// Reads settings in TOML or JSON format from files at the requested URIs (or from stdin, if given
1615/// "-"), then commits them in a single transaction and applies them to the system.
1716pub async fn apply < P > ( socket_path : P , input_sources : Vec < String > ) -> Result < ( ) >
@@ -67,53 +66,65 @@ where
6766 Ok ( ( ) )
6867}
6968
69+ /// Holds the raw input string and (if it parses) the URL.
70+ pub struct SettingsInput {
71+ pub input : String ,
72+ pub parsed_url : Option < Url > ,
73+ }
74+ impl SettingsInput {
75+ pub ( crate ) fn new ( input : impl Into < String > ) -> Self {
76+ let input = input. into ( ) ;
77+ let parsed_url = Url :: parse ( & input) . ok ( ) ;
78+ SettingsInput { input, parsed_url }
79+ }
80+ }
81+
7082/// Retrieves the given source location and returns the result in a String.
7183async fn get < S > ( input_source : S ) -> Result < String >
7284where
7385 S : AsRef < str > ,
7486{
75- let resolver = select_resolver ( input_source. as_ref ( ) ) ?;
76- resolver. resolve ( ) . await
87+ let settings = SettingsInput :: new ( input_source. as_ref ( ) ) ;
88+ let resolver = select_resolver ( & settings) ?;
89+ resolver. resolve ( ) . await . context ( ResolverFailureSnafu )
7790}
7891
92+ /// Choose which UriResolver applies to `input` (stdin, file://, http(s)://, s3://, secretsmanager://, and ssm://).
93+ fn select_resolver ( input : & SettingsInput ) -> Result < Box < dyn crate :: uri_resolver:: UriResolver > > {
94+ use crate :: uri_resolver;
7995
80- /// Choose which UriResolver applies to `input` (stdin, file://, http(s):// or s3://).
81- fn select_resolver ( input : & str ) -> Result < Box < dyn crate :: uri_resolver:: UriResolver > > {
82- // "-" → stdin
83- if let Ok ( r) = crate :: uri_resolver:: StdinUri :: try_from ( input) {
96+ // stdin ("-")
97+ if let Ok ( r) = uri_resolver:: StdinUri :: try_from ( input) {
8498 return Ok ( Box :: new ( r) ) ;
8599 }
86100
87- // parse as a URL
88- let url = Url :: parse ( input) . context ( error:: UriSnafu { input_source : input. to_string ( ) } ) ?;
89-
90101 // file://
91- if let Ok ( r) = crate :: uri_resolver:: FileUri :: try_from ( & url ) {
102+ if let Ok ( r) = uri_resolver:: FileUri :: try_from ( input ) {
92103 return Ok ( Box :: new ( r) ) ;
93104 }
94105
95106 // http(s)://
96- if let Ok ( r) = crate :: uri_resolver:: HttpUri :: try_from ( url . clone ( ) ) {
107+ if let Ok ( r) = uri_resolver:: HttpUri :: try_from ( input ) {
97108 return Ok ( Box :: new ( r) ) ;
98109 }
99110
100111 // s3://
101- if let Ok ( r) = crate :: uri_resolver:: S3Uri :: try_from ( url . clone ( ) ) {
112+ if let Ok ( r) = uri_resolver:: S3Uri :: try_from ( input ) {
102113 return Ok ( Box :: new ( r) ) ;
103114 }
104115
105116 // secretsmanager://
106- if let Ok ( r) = crate :: uri_resolver:: SecretsManagerUri :: try_from ( input) {
117+ if let Ok ( r) = uri_resolver:: SecretsManagerUri :: try_from ( input) {
107118 return Ok ( Box :: new ( r) ) ;
108119 }
109120
110121 // ssm://
111- if let Ok ( r) = crate :: uri_resolver:: SsmUri :: try_from ( input) {
122+ if let Ok ( r) = uri_resolver:: SsmUri :: try_from ( input) {
112123 return Ok ( Box :: new ( r) ) ;
113124 }
114125
115126 error:: NoResolverSnafu {
116- input_source : input. to_string ( ) ,
127+ input_source : input. input . clone ( ) ,
117128 }
118129 . fail ( )
119130}
@@ -152,12 +163,6 @@ fn format_change(input: &str, input_source: &str) -> Result<String> {
152163}
153164
154165pub ( crate ) mod error {
155- use aws_sdk_secretsmanager:: operation:: get_secret_value:: GetSecretValueError ;
156- use aws_sdk_ssm:: operation:: get_parameter:: GetParameterError ;
157- use crate :: apply:: SdkHttpResponse ;
158- use aws_smithy_runtime_api:: client:: result:: SdkError ;
159- use aws_sdk_s3:: operation:: get_object:: GetObjectError ;
160- //use aws_smithy_http::result::SdkHttpResponse;
161166 use snafu:: Snafu ;
162167
163168 #[ derive( Debug , Snafu ) ]
@@ -171,15 +176,6 @@ pub(crate) mod error {
171176 source : Box < crate :: Error > ,
172177 } ,
173178
174- #[ snafu( display( "Failed to read given file '{}': {}" , input_source, source) ) ]
175- FileRead {
176- input_source : String ,
177- source : std:: io:: Error ,
178- } ,
179-
180- #[ snafu( display( "Given invalid file URI '{}'" , input_source) ) ]
181- FileUri { input_source : String } ,
182-
183179 #[ snafu( display( "No URI resolver found for '{}'" , input_source) ) ]
184180 NoResolver { input_source : String } ,
185181
@@ -237,77 +233,9 @@ pub(crate) mod error {
237233 source : reqwest:: Error ,
238234 } ,
239235
240- #[ snafu( display( "Invalid S3 URI '{}': missing bucket name" , input_source) ) ]
241- S3UriMissingBucket { input_source : String } ,
242-
243- #[ snafu( display( "Failed to perform HTTP GET to '{}': {}" , uri, source) ) ]
244- HttpRequest {
245- uri : String ,
246- source : reqwest:: Error ,
247- } ,
248-
249- #[ snafu( display( "Non-success HTTP status from '{}': {}" , uri, status) ) ]
250- HttpStatus {
251- uri : String ,
252- status : reqwest:: StatusCode ,
253- } ,
254-
255- #[ snafu( display( "Failed to read HTTP response body from '{}': {}" , uri, source) ) ]
256- HttpBody {
257- uri : String ,
258- source : reqwest:: Error ,
259- } ,
260-
261236 #[ snafu( display( "Given invalid file URI '{}'" , input_source) ) ]
262237 InvalidFileUri { input_source : String } ,
263238
264- #[ snafu( display( "Given HTTP(S) URI '{}'" , input_source) ) ]
265- InvalidHTTPUri { input_source : String } ,
266-
267- #[ snafu( display( "Failed to read standard input: {}" , source) ) ]
268- StdinRead { source : std:: io:: Error } ,
269-
270- #[ snafu( display( "Failed to read S3 object body '{bucket}/{key}': {}" , source) ) ]
271- S3Body {
272- bucket : String ,
273- key : String ,
274- source : aws_sdk_s3:: primitives:: ByteStreamError ,
275- } ,
276-
277- #[ snafu( display( "Failed to fetch S3 object '{bucket}/{key}': {}" , source) ) ]
278- S3Get {
279- bucket : String ,
280- key : String ,
281- source : SdkError < GetObjectError , SdkHttpResponse > ,
282- } ,
283-
284- #[ snafu( display( "Invalid S3 URI scheme for '{}', expected s3://" , input_source) ) ]
285- S3UriScheme { input_source : String } ,
286-
287- #[ snafu( display( "Invalid Secrets Manager URI scheme for '{}', expected secretsmanager://" , input_source) ) ]
288- SecretsManagerUri { input_source : String } ,
289-
290- #[ snafu( display( "Invalid SSM URI scheme for '{}', expected ssm://" , input_source) ) ]
291- SsmUri { input_source : String } ,
292-
293- #[ snafu( display( "Failed to fetch secret '{}' from Secrets Manager: {}" , secret_id, source) ) ]
294- SecretsManagerGet {
295- secret_id : String ,
296- source : aws_sdk_secretsmanager:: error:: SdkError < GetSecretValueError > ,
297- } ,
298-
299- #[ snafu( display( "Secrets Manager secret '{}' did not return a string value" , secret_id) ) ]
300- SecretsManagerStringMissing { secret_id : String } ,
301-
302- #[ snafu( display( "Failed to fetch parameter '{}' from SSM: {}" , parameter_name, source) ) ]
303- SsmGetParameter {
304- parameter_name : String ,
305- source : aws_sdk_ssm:: error:: SdkError < GetParameterError > ,
306- } ,
307-
308- #[ snafu( display( "SSM parameter '{}' did not return a string value" , parameter_name) ) ]
309- SsmParameterMissing { parameter_name : String } ,
310-
311239 #[ snafu( display(
312240 "Failed to translate TOML from '{}' to JSON for API: {}" ,
313241 input_source,
@@ -323,7 +251,13 @@ pub(crate) mod error {
323251 input_source : String ,
324252 source : url:: ParseError ,
325253 } ,
254+
255+ #[ snafu( display( "Resolver failed: {}" , source) ) ]
256+ ResolverFailure { source : crate :: uri_resolver:: ResolverError } ,
257+
326258 }
259+
327260}
328261pub use error:: Error ;
329262pub type Result < T > = std:: result:: Result < T , error:: Error > ;
263+
0 commit comments