@@ -11,7 +11,11 @@ use crate::{Error, Result};
1111use clap:: builder:: styling:: { AnsiColor , Effects } ;
1212use clap:: builder:: Styles ;
1313use clap:: Parser ;
14- use redis:: ConnectionInfo ;
14+ use nextcloud_config_parser:: {
15+ RedisClusterConnectionInfo , RedisConfig , RedisConnectionAddr , RedisConnectionInfo ,
16+ RedisTlsParams ,
17+ } ;
18+ use redis:: { ConnectionAddr , ConnectionInfo } ;
1519use sqlx:: any:: AnyConnectOptions ;
1620use std:: convert:: { TryFrom , TryInto } ;
1721use std:: env:: var;
@@ -37,6 +41,21 @@ pub struct Opt {
3741 /// The redis connect url
3842 #[ clap( long) ]
3943 pub redis_url : Vec < ConnectionInfo > ,
44+ /// The client certificate to use when connecting to redis over TLS
45+ #[ clap( long) ]
46+ pub redis_tls_cert : Option < PathBuf > ,
47+ /// The client key to use when connecting to redis over TLS
48+ #[ clap( long) ]
49+ pub redis_tls_key : Option < PathBuf > ,
50+ /// The CA certificate to use when connecting to redis over TLS
51+ #[ clap( long) ]
52+ pub redis_tls_ca : Option < PathBuf > ,
53+ /// Don't validate the server's hostname when connecting to redis over TLS
54+ #[ clap( long) ]
55+ pub redis_tls_dont_validate_hostname : bool ,
56+ /// Don't validate the server's certificate when connecting to redis over TLS
57+ #[ clap( long) ]
58+ pub redis_tls_insecure : bool ,
4059 /// The table prefix for Nextcloud's database tables
4160 #[ clap( long) ]
4261 pub database_prefix : Option < String > ,
@@ -100,7 +119,7 @@ pub struct Opt {
100119pub struct Config {
101120 pub database : AnyConnectOptions ,
102121 pub database_prefix : String ,
103- pub redis : Vec < ConnectionInfo > ,
122+ pub redis : RedisConfig ,
104123 pub nextcloud_url : String ,
105124 pub metrics_bind : Option < Bind > ,
106125 pub log_level : String ,
@@ -195,7 +214,7 @@ impl TryFrom<PartialConfig> for Config {
195214 database_prefix : config
196215 . database_prefix
197216 . unwrap_or_else ( || String :: from ( "oc_" ) ) ,
198- redis : config. redis ,
217+ redis : config. redis . ok_or ( ConfigError :: NoRedis ) ? ,
199218 nextcloud_url,
200219 metrics_bind,
201220 log_level : config. log_level . unwrap_or_else ( || String :: from ( "warn" ) ) ,
@@ -228,7 +247,7 @@ impl Config {
228247struct PartialConfig {
229248 pub database : Option < AnyConnectOptions > ,
230249 pub database_prefix : Option < String > ,
231- pub redis : Vec < ConnectionInfo > ,
250+ pub redis : Option < RedisConfig > ,
232251 pub nextcloud_url : Option < String > ,
233252 pub port : Option < u16 > ,
234253 pub metrics_port : Option < u16 > ,
@@ -248,7 +267,13 @@ impl PartialConfig {
248267 fn from_env ( ) -> Result < Self > {
249268 let database = parse_var ( "DATABASE_URL" ) ?;
250269 let database_prefix = var ( "DATABASE_PREFIX" ) . ok ( ) ;
251- let redis = parse_var ( "REDIS_URL" ) ?;
270+ let redis: Option < ConnectionInfo > = parse_var ( "REDIS_URL" ) ?;
271+ let redis_tls_cert = parse_var ( "REDIS_TLS_CERT" ) ?;
272+ let redis_tls_key = parse_var ( "REDIS_TLS_KEY" ) ?;
273+ let redis_tls_ca = parse_var ( "REDIS_TLS_CA" ) ?;
274+ let redis_tls_dont_validate_hostname: Option < u8 > =
275+ parse_var ( "REDIS_TLS_DONT_VALIDATE_HOSTNAME" ) ?;
276+ let redis_tls_insecure: Option < u8 > = parse_var ( "REDIS_TLS_INSECURE" ) ?;
252277 let nextcloud_url = var ( "NEXTCLOUD_URL" ) . ok ( ) ;
253278 let port = parse_var ( "PORT" ) ?;
254279 let metrics_port = parse_var ( "METRICS_PORT" ) ?;
@@ -271,10 +296,36 @@ impl PartialConfig {
271296 let max_debounce_time = parse_var ( "MAX_DEBOUNCE_TIME" ) ?;
272297 let max_connection_time = parse_var ( "MAX_CONNECTION_TIME" ) ?;
273298
299+ let redis = redis. map ( |redis| {
300+ let addr = map_redis_addr ( redis. addr ) ;
301+
302+ let accept_invalid_hostname = redis_tls_dont_validate_hostname
303+ . filter ( |b| * b != 0 )
304+ . is_some ( ) ;
305+ let redis_tls = matches ! ( addr, RedisConnectionAddr :: Tcp { tls: true , .. } ) ;
306+ let redis_tls_insecure = redis_tls_insecure. filter ( |b| * b != 0 ) . is_some ( ) ;
307+
308+ let tls_params = redis_tls. then_some ( RedisTlsParams {
309+ local_cert : redis_tls_cert,
310+ local_pk : redis_tls_key,
311+ ca_file : redis_tls_ca,
312+ accept_invalid_hostname,
313+ insecure : redis_tls_insecure,
314+ } ) ;
315+
316+ RedisConfig :: Single ( RedisConnectionInfo {
317+ addr,
318+ db : redis. redis . db ,
319+ username : redis. redis . username ,
320+ password : redis. redis . password ,
321+ tls_params,
322+ } )
323+ } ) ;
324+
274325 Ok ( PartialConfig {
275326 database,
276327 database_prefix,
277- redis : redis . into_iter ( ) . collect ( ) ,
328+ redis,
278329 nextcloud_url,
279330 port,
280331 metrics_port,
@@ -302,10 +353,65 @@ impl PartialConfig {
302353 None
303354 } ;
304355
356+ let redis = match opt. redis_url . len ( ) {
357+ 0 => None ,
358+ 1 => {
359+ let redis = opt. redis_url . into_iter ( ) . next ( ) . unwrap ( ) ;
360+ let addr = map_redis_addr ( redis. addr ) ;
361+
362+ let redis_tls = matches ! ( addr, RedisConnectionAddr :: Tcp { tls: true , .. } ) ;
363+
364+ let tls_params = redis_tls. then_some ( RedisTlsParams {
365+ local_cert : opt. redis_tls_cert ,
366+ local_pk : opt. redis_tls_key ,
367+ ca_file : opt. redis_tls_ca ,
368+ accept_invalid_hostname : opt. redis_tls_dont_validate_hostname ,
369+ insecure : opt. redis_tls_insecure ,
370+ } ) ;
371+
372+ Some ( RedisConfig :: Single ( RedisConnectionInfo {
373+ addr,
374+ db : redis. redis . db ,
375+ username : redis. redis . username ,
376+ password : redis. redis . password ,
377+ tls_params,
378+ } ) )
379+ }
380+ _ => {
381+ let addr: Vec < _ > = opt
382+ . redis_url
383+ . iter ( )
384+ . map ( |redis| map_redis_addr ( redis. addr . clone ( ) ) )
385+ . collect ( ) ;
386+
387+ let redis_tls = matches ! (
388+ addr. first( ) ,
389+ Some ( RedisConnectionAddr :: Tcp { tls: true , .. } )
390+ ) ;
391+
392+ let tls_params = redis_tls. then_some ( RedisTlsParams {
393+ local_cert : opt. redis_tls_cert ,
394+ local_pk : opt. redis_tls_key ,
395+ ca_file : opt. redis_tls_ca ,
396+ accept_invalid_hostname : opt. redis_tls_dont_validate_hostname ,
397+ insecure : opt. redis_tls_insecure ,
398+ } ) ;
399+
400+ let redis = opt. redis_url . into_iter ( ) . next ( ) . unwrap ( ) . redis ;
401+ Some ( RedisConfig :: Cluster ( RedisClusterConnectionInfo {
402+ addr,
403+ db : redis. db ,
404+ username : redis. username ,
405+ password : redis. password ,
406+ tls_params,
407+ } ) )
408+ }
409+ } ;
410+
305411 PartialConfig {
306412 database : opt. database_url ,
307413 database_prefix : opt. database_prefix ,
308- redis : opt . redis_url ,
414+ redis,
309415 nextcloud_url : opt. nextcloud_url ,
310416 port : opt. port ,
311417 metrics_port : opt. metrics_port ,
@@ -330,10 +436,10 @@ impl PartialConfig {
330436 PartialConfig {
331437 database : self . database . or ( fallback. database ) ,
332438 database_prefix : self . database_prefix . or ( fallback. database_prefix ) ,
333- redis : if self . redis . is_empty ( ) {
334- fallback. redis
335- } else {
439+ redis : if self . redis . is_some ( ) {
336440 self . redis
441+ } else {
442+ fallback. redis
337443 } ,
338444 nextcloud_url : self . nextcloud_url . or ( fallback. nextcloud_url ) ,
339445 port : self . port . or ( fallback. port ) ,
@@ -363,3 +469,19 @@ where
363469 . transpose ( )
364470 . map_err ( |e| ConfigError :: Env ( name, Box :: new ( e) ) . into ( ) )
365471}
472+
473+ fn map_redis_addr ( addr : ConnectionAddr ) -> RedisConnectionAddr {
474+ match addr {
475+ ConnectionAddr :: Tcp ( host, port) => RedisConnectionAddr :: Tcp {
476+ host,
477+ port,
478+ tls : false ,
479+ } ,
480+ ConnectionAddr :: TcpTls { host, port, .. } => RedisConnectionAddr :: Tcp {
481+ host,
482+ port,
483+ tls : true ,
484+ } ,
485+ ConnectionAddr :: Unix ( path) => RedisConnectionAddr :: Unix { path } ,
486+ }
487+ }
0 commit comments