@@ -16,17 +16,17 @@ use crate::conf::CliConf;
1616use crate :: conf:: { ClientConf , FuseConf , JobConf , JournalConf , MasterConf , WorkerConf } ;
1717use crate :: rocksdb:: DBConf ;
1818use crate :: version;
19+ use config:: { Config , Environment , File , FileFormat } ;
1920use log:: info;
2021use orpc:: client:: { ClientConf as RpcConf , ClientFactory , SyncClient } ;
2122use orpc:: common:: { LogConf , Utils } ;
2223use orpc:: io:: net:: { InetAddr , NodeAddr } ;
2324use orpc:: io:: retry:: TimeBondedRetryBuilder ;
2425use orpc:: server:: ServerConf ;
25- use orpc:: { err_box, try_err , CommonResult } ;
26+ use orpc:: { err_box, CommonResult } ;
2627use serde:: { Deserialize , Serialize } ;
27- use std :: env ;
28+ use serde_json :: { json , Value } ;
2829use std:: fmt:: { Display , Formatter } ;
29- use std:: fs:: read_to_string;
3030use std:: time:: Duration ;
3131
3232// Cluster configuration files.
@@ -75,37 +75,110 @@ impl ClusterConf {
7575 pub const ENV_CLIENT_HOSTNAME : & ' static str = "CURVINE_CLIENT_HOSTNAME" ;
7676 pub const ENV_CONF_FILE : & ' static str = "CURVINE_CONF_FILE" ;
7777
78- pub fn from < T : AsRef < str > > ( path : T ) -> CommonResult < Self > {
79- let str = try_err ! ( read_to_string( path. as_ref( ) ) ) ;
80- let mut conf = try_err ! ( toml:: from_str:: <Self >( & str ) ) ;
81-
82- if let Ok ( v) = env:: var ( Self :: ENV_MASTER_HOSTNAME ) {
83- conf. master . hostname = v. to_owned ( ) ;
84- conf. journal . hostname = v;
85- }
78+ pub fn argstostr < U : Serialize > ( args_name : & str , args : & U ) -> String {
79+ let args_value: Value = serde_json:: to_value ( args) . unwrap ( ) ;
80+
81+ let result = if let Some ( master_addrs_str) =
82+ args_value. get ( "master_addrs" ) . and_then ( |v| v. as_str ( ) )
83+ {
84+ let addrs: Vec < Value > = master_addrs_str
85+ . split ( ',' )
86+ . filter ( |s| !s. trim ( ) . is_empty ( ) )
87+ . map ( |addr| {
88+ let addr = addr. trim ( ) ;
89+ let parts: Vec < & str > = addr. split ( ':' ) . collect ( ) ;
90+
91+ if parts. len ( ) == 2 {
92+ let hostname = parts[ 0 ] ;
93+ let port = parts[ 1 ]
94+ . parse :: < u16 > ( )
95+ . map_err ( |_| format ! ( "Invalid port: {}" , parts[ 1 ] ) ) ?;
96+
97+ Ok ( json ! ( {
98+ "hostname" : hostname,
99+ "port" : port
100+ } ) )
101+ } else {
102+ Err ( format ! ( "Invalid address format: {}" , addr) )
103+ }
104+ } )
105+ . collect :: < Result < Vec < _ > , _ > > ( )
106+ . unwrap ( ) ;
107+
108+ json ! ( {
109+ args_name: args_value,
110+ "client" : {
111+ "master_addrs" : addrs
112+ }
113+ } )
114+ } else {
115+ json ! ( {
116+ args_name: args_value
117+ } )
118+ } ;
86119
87- // Apply worker hostname from environment variable (used by worker process)
88- if let Ok ( v) = env:: var ( Self :: ENV_WORKER_HOSTNAME ) {
89- conf. worker . hostname = v;
90- }
120+ serde_json:: to_string_pretty ( & result) . unwrap ( )
121+ }
91122
92- // Apply client hostname from environment variable
93- if let Ok ( v) = env:: var ( Self :: ENV_CLIENT_HOSTNAME ) {
94- conf. client . hostname = v;
123+ pub fn from < T : AsRef < str > , U : Serialize > (
124+ path : T ,
125+ args : Option < & U > ,
126+ args_name : Option < & str > ,
127+ ) -> CommonResult < Self > {
128+ let cli_source = if let ( Some ( name) , Some ( args_value) ) = ( args_name, args) {
129+ ClusterConf :: argstostr ( name, args_value)
130+ } else {
131+ "{}" . to_string ( )
132+ } ;
133+
134+ // Get cluster configuration with priority: CLI args > env vars > config file > defaults
135+ let config = Config :: builder ( )
136+ . add_source ( File :: new ( path. as_ref ( ) , FileFormat :: Toml ) )
137+ . add_source ( Environment :: with_prefix ( "CURVINE" ) . separator ( "_" ) )
138+ . add_source ( File :: from_str ( & cli_source, FileFormat :: Json ) ) ;
139+
140+ let mut conf;
141+ match config. build ( ) {
142+ Ok ( config) => {
143+ conf = Self {
144+ format_master : true ,
145+ format_worker : true ,
146+ testing : false ,
147+ cluster_id : "curvine" . to_string ( ) ,
148+ master : config. get :: < MasterConf > ( "master" ) . unwrap_or_default ( ) ,
149+ journal : config. get :: < JournalConf > ( "journal" ) . unwrap_or_default ( ) ,
150+ worker : config. get :: < WorkerConf > ( "worker" ) . unwrap_or_default ( ) ,
151+ log : config. get :: < LogConf > ( "log" ) . unwrap_or_default ( ) ,
152+ client : config. get :: < ClientConf > ( "client" ) . unwrap_or_default ( ) ,
153+ fuse : config. get :: < FuseConf > ( "fuse" ) . unwrap_or_default ( ) ,
154+ s3_gateway : config
155+ . get :: < S3GatewayConf > ( "s3_gateway" )
156+ . unwrap_or_default ( ) ,
157+ job : config. get :: < JobConf > ( "job" ) . unwrap_or_default ( ) ,
158+ cli : config. get :: < CliConf > ( "cli" ) . unwrap_or_default ( ) ,
159+ } ;
160+ }
161+ Err ( e) => {
162+ eprintln ! (
163+ "Warning: Failed to load config file '{}': {}" ,
164+ path. as_ref( ) ,
165+ e
166+ ) ;
167+ eprintln ! ( "Using default configuration" ) ;
168+ conf = ClusterConf :: default ( ) ;
169+ }
95170 }
96171
97172 conf. master . init ( ) ?;
98173 conf. client . init ( ) ?;
99174 conf. fuse . init ( ) ?;
100175 conf. job . init ( ) ?;
101-
102176 if conf. client . master_addrs . is_empty ( ) {
103177 for peer in & mut conf. journal . journal_addrs {
104178 let node = InetAddr :: new ( & peer. hostname , conf. master . rpc_port ) ;
105179 conf. client . master_addrs . push ( node) ;
106180 }
107181 }
108-
109182 Ok ( conf)
110183 }
111184
@@ -268,7 +341,7 @@ impl ClusterConf {
268341
269342impl Default for ClusterConf {
270343 fn default ( ) -> Self {
271- Self {
344+ let mut conf = Self {
272345 format_master : true ,
273346 format_worker : true ,
274347 testing : false ,
@@ -282,7 +355,14 @@ impl Default for ClusterConf {
282355 s3_gateway : Default :: default ( ) ,
283356 job : Default :: default ( ) ,
284357 cli : Default :: default ( ) ,
285- }
358+ } ;
359+
360+ conf. master . init ( ) . unwrap ( ) ;
361+ conf. client . init ( ) . unwrap ( ) ;
362+ conf. fuse . init ( ) . unwrap ( ) ;
363+ conf. job . init ( ) . unwrap ( ) ;
364+
365+ conf
286366 }
287367}
288368
0 commit comments