88#![ cfg_attr( not( test) , deny( clippy:: print_stdout, clippy:: print_stderr) ) ]
99
1010use std:: io;
11- use std:: net:: IpAddr ;
12- use std:: path:: PathBuf ;
13- use std:: sync:: atomic:: AtomicBool ;
1411
15- use anyhow:: { Context as _ , Result } ;
12+ use anyhow:: Result ;
1613use async_trait:: async_trait;
17- use base64:: Engine ;
1814use cli_builder:: NewCli ;
1915use context:: Context ;
20- use generated_cli:: CliConfig ;
21- use oxide:: {
22- types:: {
23- AllowedSourceIps , DerEncodedKeyPair , IdpMetadataSource , IpRange , Ipv4Range , Ipv6Range ,
24- } ,
25- Client ,
26- } ;
16+ use oxide:: Client ;
2717use url:: Url ;
2818
2919mod cmd_api;
@@ -40,6 +30,7 @@ mod cmd_version;
4030
4131mod cli_builder;
4232mod context;
33+ mod oxide_override;
4334#[ macro_use]
4435mod print;
4536mod util;
@@ -135,212 +126,6 @@ async fn main() {
135126 }
136127}
137128
138- #[ derive( Default ) ]
139- struct OxideOverride {
140- needs_comma : AtomicBool ,
141- }
142-
143- impl OxideOverride {
144- fn ip_range ( matches : & clap:: ArgMatches ) -> anyhow:: Result < IpRange > {
145- let first = matches. get_one :: < IpAddr > ( "first" ) . unwrap ( ) ;
146- let last = matches. get_one :: < IpAddr > ( "last" ) . unwrap ( ) ;
147-
148- match ( first, last) {
149- ( IpAddr :: V4 ( first) , IpAddr :: V4 ( last) ) => {
150- let range = Ipv4Range :: try_from ( Ipv4Range :: builder ( ) . first ( * first) . last ( * last) ) ?;
151- Ok ( range. into ( ) )
152- }
153- ( IpAddr :: V6 ( first) , IpAddr :: V6 ( last) ) => {
154- let range = Ipv6Range :: try_from ( Ipv6Range :: builder ( ) . first ( * first) . last ( * last) ) ?;
155- Ok ( range. into ( ) )
156- }
157- _ => anyhow:: bail!(
158- "first and last must either both be ipv4 or ipv6 addresses" . to_string( )
159- ) ,
160- }
161- }
162- }
163-
164- impl CliConfig for OxideOverride {
165- fn success_item < T > ( & self , value : & oxide:: ResponseValue < T > )
166- where
167- T : schemars:: JsonSchema + serde:: Serialize + std:: fmt:: Debug ,
168- {
169- let s = serde_json:: to_string_pretty ( std:: ops:: Deref :: deref ( value) )
170- . expect ( "failed to serialize return to json" ) ;
171- println_nopipe ! ( "{}" , s) ;
172- }
173-
174- fn success_no_item ( & self , _: & oxide:: ResponseValue < ( ) > ) { }
175-
176- fn error < T > ( & self , _value : & oxide:: Error < T > )
177- where
178- T : schemars:: JsonSchema + serde:: Serialize + std:: fmt:: Debug ,
179- {
180- eprintln_nopipe ! ( "error" ) ;
181- }
182-
183- fn list_start < T > ( & self )
184- where
185- T : schemars:: JsonSchema + serde:: Serialize + std:: fmt:: Debug ,
186- {
187- self . needs_comma
188- . store ( false , std:: sync:: atomic:: Ordering :: Relaxed ) ;
189- print_nopipe ! ( "[" ) ;
190- }
191-
192- fn list_item < T > ( & self , value : & T )
193- where
194- T : schemars:: JsonSchema + serde:: Serialize + std:: fmt:: Debug ,
195- {
196- let s = serde_json:: to_string_pretty ( & [ value] ) . expect ( "failed to serialize result to json" ) ;
197- if self . needs_comma . load ( std:: sync:: atomic:: Ordering :: Relaxed ) {
198- print_nopipe ! ( ", {}" , & s[ 4 ..s. len( ) - 2 ] ) ;
199- } else {
200- print_nopipe ! ( "\n {}" , & s[ 2 ..s. len( ) - 2 ] ) ;
201- } ;
202- self . needs_comma
203- . store ( true , std:: sync:: atomic:: Ordering :: Relaxed ) ;
204- }
205-
206- fn list_end_success < T > ( & self )
207- where
208- T : schemars:: JsonSchema + serde:: Serialize + std:: fmt:: Debug ,
209- {
210- if self . needs_comma . load ( std:: sync:: atomic:: Ordering :: Relaxed ) {
211- println_nopipe ! ( "\n ]" ) ;
212- } else {
213- println_nopipe ! ( "]" ) ;
214- }
215- }
216-
217- fn list_end_error < T > ( & self , _value : & oxide:: Error < T > )
218- where
219- T : schemars:: JsonSchema + serde:: Serialize + std:: fmt:: Debug ,
220- {
221- self . list_end_success :: < T > ( )
222- }
223-
224- // Deal with all the operations that require an `IpPool` as input
225- fn execute_ip_pool_range_add (
226- & self ,
227- matches : & clap:: ArgMatches ,
228- request : & mut oxide:: builder:: IpPoolRangeAdd ,
229- ) -> anyhow:: Result < ( ) > {
230- * request = request. to_owned ( ) . body ( Self :: ip_range ( matches) ?) ;
231- Ok ( ( ) )
232- }
233- fn execute_ip_pool_range_remove (
234- & self ,
235- matches : & clap:: ArgMatches ,
236- request : & mut oxide:: builder:: IpPoolRangeRemove ,
237- ) -> anyhow:: Result < ( ) > {
238- * request = request. to_owned ( ) . body ( Self :: ip_range ( matches) ?) ;
239- Ok ( ( ) )
240- }
241- fn execute_ip_pool_service_range_add (
242- & self ,
243- matches : & clap:: ArgMatches ,
244- request : & mut oxide:: builder:: IpPoolServiceRangeAdd ,
245- ) -> anyhow:: Result < ( ) > {
246- * request = request. to_owned ( ) . body ( Self :: ip_range ( matches) ?) ;
247- Ok ( ( ) )
248- }
249- fn execute_ip_pool_service_range_remove (
250- & self ,
251- matches : & clap:: ArgMatches ,
252- request : & mut oxide:: builder:: IpPoolServiceRangeRemove ,
253- ) -> anyhow:: Result < ( ) > {
254- * request = request. to_owned ( ) . body ( Self :: ip_range ( matches) ?) ;
255- Ok ( ( ) )
256- }
257-
258- fn execute_saml_identity_provider_create (
259- & self ,
260- matches : & clap:: ArgMatches ,
261- request : & mut oxide:: builder:: SamlIdentityProviderCreate ,
262- ) -> anyhow:: Result < ( ) > {
263- match matches
264- . get_one :: < clap:: Id > ( "idp_metadata_source" )
265- . map ( clap:: Id :: as_str)
266- {
267- Some ( "metadata-url" ) => {
268- let value = matches. get_one :: < String > ( "metadata-url" ) . unwrap ( ) ;
269- * request = request. to_owned ( ) . body_map ( |body| {
270- body. idp_metadata_source ( IdpMetadataSource :: Url { url : value. clone ( ) } )
271- } ) ;
272- Ok :: < _ , anyhow:: Error > ( ( ) )
273- }
274- Some ( "metadata-value" ) => {
275- let xml_path = matches. get_one :: < PathBuf > ( "metadata-value" ) . unwrap ( ) ;
276- let xml_bytes = std:: fs:: read ( xml_path) . with_context ( || {
277- format ! ( "failed to read metadata XML file {}" , xml_path. display( ) )
278- } ) ?;
279- let encoded_xml = base64:: engine:: general_purpose:: STANDARD . encode ( xml_bytes) ;
280- * request = request. to_owned ( ) . body_map ( |body| {
281- body. idp_metadata_source ( IdpMetadataSource :: Base64EncodedXml {
282- data : encoded_xml,
283- } )
284- } ) ;
285- Ok ( ( ) )
286- }
287- _ => unreachable ! ( "invalid value for idp_metadata_source group" ) ,
288- } ?;
289-
290- if matches. get_one :: < clap:: Id > ( "signing_keypair" ) . is_some ( ) {
291- let privkey_path = matches. get_one :: < PathBuf > ( "private-key" ) . unwrap ( ) ;
292- let privkey_bytes = std:: fs:: read ( privkey_path) . with_context ( || {
293- format ! ( "failed to read private key file {}" , privkey_path. display( ) )
294- } ) ?;
295- let encoded_privkey = base64:: engine:: general_purpose:: STANDARD . encode ( & privkey_bytes) ;
296-
297- let cert_path = matches. get_one :: < PathBuf > ( "public-cert" ) . unwrap ( ) ;
298- let cert_bytes = std:: fs:: read ( cert_path) . with_context ( || {
299- format ! ( "failed to read public cert file {}" , cert_path. display( ) )
300- } ) ?;
301- let encoded_cert = base64:: engine:: general_purpose:: STANDARD . encode ( & cert_bytes) ;
302-
303- * request = request. to_owned ( ) . body_map ( |body| {
304- body. signing_keypair ( DerEncodedKeyPair {
305- private_key : encoded_privkey,
306- public_cert : encoded_cert,
307- } )
308- } ) ;
309- }
310- Ok ( ( ) )
311- }
312-
313- fn execute_networking_allow_list_update (
314- & self ,
315- matches : & clap:: ArgMatches ,
316- request : & mut oxide:: builder:: NetworkingAllowListUpdate ,
317- ) -> anyhow:: Result < ( ) > {
318- match matches
319- . get_one :: < clap:: Id > ( "allow-list" )
320- . map ( clap:: Id :: as_str)
321- {
322- Some ( "any" ) => {
323- let value = matches. get_one :: < bool > ( "any" ) . unwrap ( ) ;
324- assert ! ( value) ;
325- * request = request
326- . to_owned ( )
327- . body_map ( |body| body. allowed_ips ( AllowedSourceIps :: Any ) ) ;
328- }
329- Some ( "ips" ) => {
330- let values: Vec < IpOrNet > = matches. get_many ( "ips" ) . unwrap ( ) . cloned ( ) . collect ( ) ;
331- * request = request. to_owned ( ) . body_map ( |body| {
332- body. allowed_ips ( AllowedSourceIps :: List (
333- values. into_iter ( ) . map ( IpOrNet :: into_ip_net) . collect ( ) ,
334- ) )
335- } ) ;
336- }
337- _ => unreachable ! ( "invalid value for allow-list group" ) ,
338- }
339-
340- Ok ( ( ) )
341- }
342- }
343-
344129#[ cfg( test) ]
345130mod tests {
346131 use clap:: Command ;
0 commit comments