File Coverage

blib/lib/MogileFS/Config.pm
Criterion Covered Total %
statement 37 202 18.3
branch 8 112 7.1
condition 0 32 0.0
subroutine 12 32 37.5
pod 0 15 0.0
total 57 393 14.5


line stmt bran cond sub pod time code
1             package MogileFS::Config;
2 21     21   120 use strict;
  21         42  
  21         1546  
3             require Exporter;
4 21     21   16625 use MogileFS::ProcManager;
  21         76  
  21         2666  
5 21     21   57659 use Getopt::Long;
  21         375667  
  21         243  
6 21     21   26361 use MogileFS::Store;
  21         102  
  21         810  
7 21     21   24752 use Sys::Hostname ();
  21         36185  
  21         3888  
8              
9             our @ISA = qw(Exporter);
10             our @EXPORT = qw($DEBUG config set_config FSCK_QUEUE REBAL_QUEUE);
11             our @EXPORT_OK = qw(DEVICE_SUMMARY_CACHE_TIMEOUT);
12              
13             our ($DEFAULT_CONFIG, $MOGSTORED_STREAM_PORT, $DEBUG);
14             $DEBUG = 0;
15             $DEFAULT_CONFIG = "/etc/mogilefs/mogilefsd.conf";
16             $MOGSTORED_STREAM_PORT = 7501;
17              
18 21     21   177 use constant FSCK_QUEUE => 1;
  21         43  
  21         1615  
19 21     21   159 use constant REBAL_QUEUE => 2;
  21         51  
  21         1027  
20 21     21   114 use constant DEVICE_SUMMARY_CACHE_TIMEOUT => 15;
  21         96  
  21         125132  
21              
22             my %conf;
23             my %server_settings;
24             my $has_cached_settings = 0;
25             sub set_config {
26 47 100   47 0 4239 shift if @_ == 3;
27 47         179 my ($k, $v) = @_;
28              
29             # if a child, propagate to parent
30 47 50       491 if (my $worker = MogileFS::ProcManager->is_child) {
    50          
31 0         0 $worker->send_to_parent(":set_config_from_child $k $v");
32             } elsif (defined $v) {
33 47         319 MogileFS::ProcManager->send_to_all_children(":set_config_from_parent $k $v");
34             }
35              
36 47         159 return set_config_no_broadcast($k, $v);
37             }
38              
39             sub set_config_no_broadcast {
40 77 100   77 0 285 shift if @_ == 3;
41 77         144 my ($k, $v) = @_;
42 77         380 return $conf{$k} = $v;
43             }
44              
45             set_config('default_mindevcount', 2);
46             set_config('min_fidid', 0);
47              
48             our (
49             %cmdline,
50             %cfgfile,
51             $config,
52             $skipconfig,
53             $daemonize,
54             $db_dsn,
55             $db_user,
56             $db_pass,
57             $conf_port,
58             $listen,
59             $query_jobs,
60             $delete_jobs,
61             $replicate_jobs,
62             $fsck_jobs,
63             $reaper_jobs,
64             $monitor_jobs,
65             $job_master, # boolean
66             $max_handles,
67             $min_free_space,
68             $max_disk_age,
69             $node_timeout, # time in seconds to wait for storage node responses
70             $conn_timeout, # time in seconds to wait for connection to storage node
71             $pidfile,
72             $repl_use_get_port,
73             $local_network,
74             );
75              
76             my $default_mindevcount;
77              
78             sub load_config {
79 0     0 0 0 my $dummy_workerport;
80              
81             # Command-line options will override
82 0         0 Getopt::Long::Configure( "bundling" );
83 0         0 Getopt::Long::GetOptions(
84             'c|config=s' => \$config,
85             's|skipconfig' => \$skipconfig,
86             'd|debug+' => \$cmdline{debug},
87             'D|daemonize' => \$cmdline{daemonize},
88             'dsn=s' => \$cmdline{db_dsn},
89             'dbuser=s' => \$cmdline{db_user},
90             'dbpass:s' => \$cmdline{db_pass},
91             'user=s' => \$cmdline{user},
92             'p|confport=i' => \$cmdline{conf_port},
93             'l|listen=s@' => \$cmdline{listen},
94             'w|workers=i' => \$cmdline{query_jobs},
95             'no_http' => \$cmdline{no_http}, # OLD, we just eat it to shut it up.
96             'workerport=i' => \$dummy_workerport, # eat it for backwards compat
97             'max_disk_age=i' => \$cmdline{max_disk_age},
98             'min_free_space=i' => \$cmdline{min_free_space},
99             'default_mindevcount=i' => \$cmdline{default_mindevcount},
100             'node_timeout=i' => \$cmdline{node_timeout},
101             'conn_timeout=i' => \$cmdline{conn_timeout},
102             'max_handles=i' => \$cmdline{max_handles},
103             'pidfile=s' => \$cmdline{pidfile},
104             'no_schema_check' => \$cmdline{no_schema_check},
105             'plugins=s@' => \$cmdline{plugins},
106             'repl_use_get_port=i' => \$cmdline{repl_use_get_port},
107             'local_network=s' => \$cmdline{local_network},
108             'mogstored_stream_port' => \$cmdline{mogstored_stream_port},
109             'job_master!' => \$cmdline{job_master},
110             );
111              
112             # warn of old/deprecated options
113 0 0       0 warn "The command line option --workerport is no longer needed (and has no necessary replacement)\n"
114             if $dummy_workerport;
115              
116 0 0 0     0 $config = $DEFAULT_CONFIG if !$config && -r $DEFAULT_CONFIG;
117              
118             # Read the config file if one was specified
119 0 0 0     0 if ($config && !$skipconfig) {
120 0 0       0 open my $cf, "<$config" or die "open: $config: $!";
121              
122 0         0 my $configLine = qr{
123             ^\s* # Leading space
124             ([\w.]+) # Key
125             \s+ =? \s* # space + optional equal + optional space
126             (.+?) # Value
127             \s*$ # Trailing space
128             }x;
129              
130 0         0 my $linecount = 0;
131 0         0 while (defined( my $line = <$cf> )) {
132 0         0 $linecount++;
133 0 0       0 next if $line =~ m!^\s*(\#.*)?$!;
134 0 0       0 die "Malformed config file (line $linecount)" unless $line =~ $configLine;
135              
136 0         0 my ( $key, $value ) = ( $1, $2 );
137 0 0       0 print STDERR "Setting '$key' to '$value'\n" if $cmdline{debug};
138 0         0 $cfgfile{$key} = $value;
139             }
140              
141 0         0 close $cf;
142             }
143              
144             # Fill in defaults for those values which were either loaded from config or
145             # specified on the command line. Command line takes precedence, then values in
146             # the config file, then the defaults.
147 0         0 $daemonize = choose_value( 'daemonize', 0 );
148 0         0 $db_dsn = choose_value( 'db_dsn', "DBI:mysql:mogilefs" );
149 0         0 $db_user = choose_value( 'db_user', "mogile" );
150 0         0 $db_pass = choose_value( 'db_pass', "", 1 );
151 0         0 $conf_port = choose_value( 'conf_port', 7001 );
152 0   0     0 $query_jobs = set_config("query_jobs",
153             choose_value( 'listener_jobs', undef) || # undef if not present, then we
154             choose_value( 'query_jobs', 20 )); # fall back to query_jobs, new name
155 0         0 $delete_jobs = choose_value( 'delete_jobs', 1 );
156 0         0 $replicate_jobs = choose_value( 'replicate_jobs', 1 );
157 0         0 $fsck_jobs = choose_value( 'fsck_jobs', 1 );
158 0         0 $reaper_jobs = choose_value( 'reaper_jobs', 1 );
159 0         0 $job_master = choose_value( 'job_master', 1 );
160 0         0 $monitor_jobs = choose_value( 'monitor_jobs', 1 );
161 0         0 $min_free_space = choose_value( 'min_free_space', 100 );
162 0         0 $max_disk_age = choose_value( 'max_disk_age', 5 );
163 0         0 $max_handles = choose_value( 'max_handles', 0 );
164 0   0     0 $DEBUG = choose_value( 'debug', $ENV{DEBUG} || 0 );
165 0         0 $pidfile = choose_value( 'pidfile', "" );
166              
167 0         0 choose_value( 'mogstored_stream_port', $MOGSTORED_STREAM_PORT );
168 0         0 choose_value( 'default_mindevcount', 2 );
169 0         0 $node_timeout = choose_value( 'node_timeout', 2 );
170 0         0 $conn_timeout = choose_value( 'conn_timeout', 2 );
171              
172 0         0 choose_value( 'rebalance_ignore_missing', 0 );
173 0         0 $repl_use_get_port = choose_value( 'repl_use_get_port', 0 );
174 0         0 $local_network = choose_value( 'local_network', '' );
175              
176 0         0 choose_value( 'no_schema_check', 0 );
177              
178             # now load plugins
179 0         0 my @plugins;
180 0 0       0 push @plugins, $cfgfile{plugins} if $cfgfile{plugins};
181 0 0       0 push @plugins, @{$cmdline{plugins}} if $cmdline{plugins};
  0         0  
182              
183 0         0 foreach my $plugin (@plugins) {
184 0         0 load_plugins($plugin);
185             }
186              
187 0         0 choose_value('user', '');
188              
189             # fix up config file listen option
190 0 0       0 $cfgfile{listen} = [ split(/\s*,\s*/, $cfgfile{listen}) ] if defined $cfgfile{listen};
191              
192             # now let's fix up the listen option to include the port if it doesn't already; we can't use
193             # choose_value as that uses set_config and that sends to children; this option doesn't apply
194 0   0     0 my $temp_listen = $cmdline{listen} || $cfgfile{listen} || [ '0.0.0.0' ];
195 0 0       0 $conf{listen} = $listen = [ map { /:/ ? $_ : "$_:$conf{conf_port}" } @$temp_listen ];
  0         0  
196             }
197              
198             ### FUNCTION: choose_value( $name, $default )
199             sub choose_value {
200 0     0 0 0 my ( $name, $default ) = @_;
201 0 0       0 return set_config($name, $cmdline{$name}) if defined $cmdline{$name};
202 0 0       0 return set_config($name, $cfgfile{$name}) if defined $cfgfile{$name};
203 0         0 return set_config($name, $default);
204             }
205              
206             sub load_plugins {
207 0     0 0 0 my $plugins = shift;
208 0         0 foreach my $plugin (split(/\s*,\s*/, $plugins)) {
209 0         0 my $rv = eval "use MogileFS::Plugin::$plugin; MogileFS::Plugin::$plugin->load; 1;";
210 0 0       0 die "Unable to load $plugin: $@\n" unless $rv;
211             }
212             }
213              
214             sub config {
215 77 50   77 0 236 shift if @_ == 2;
216 77         104 my $k = shift;
217 77 50       271 die "No config variable '$k'" unless defined $conf{$k};
218 77         285 return $conf{$k};
219             }
220              
221             sub check_database {
222 0     0 0   my $sto = eval { Mgd::get_store() };
  0            
223 0 0 0       unless ($sto && $sto->ping) {
224 0           die qq{
225             Error: unable to establish connection with your MogileFS database.
226              
227             Please verify that you have correctly setup a configuration file or are
228             providing the correct information in order to reach the database and try
229             running the MogileFS server again. If you haven\'t setup your database yet,
230             run 'mogdbsetup'.
231              
232             Details: [sto=$sto, err=$@]
233             }
234             }
235              
236 0   0       my $sversion = MogileFS::Config->server_setting('schema_version') || 0;
237 0           my $expect_ver = MogileFS::Store->latest_schema_version;
238 0 0 0       unless ($sversion == $expect_ver || MogileFS::Config->config('no_schema_check')) {
239 0           die "Server's database schema version of $sversion doesn't match expected value of $expect_ver. Halting.\n\n".
240             "Please run mogdbsetup to upgrade your schema.\n";
241             }
242              
243 0           $sto->pre_daemonize_checks;
244              
245             # If MySQL gets restarted InnoDB may reset its auto_increment counter. If
246             # the first few fids have been deleted, the "reset to max on duplicate"
247             # code won't fire immediately.
248             # Instead, we also trigger it if a configured "min_fidid" is higher than
249             # what we got from innodb.
250             # For bonus points: This value should be periodically updated, in case the
251             # trackers don't go down as often as the database.
252 0           my $min_fidid = $sto->max_fidid;
253 0 0         $min_fidid = 0 unless $min_fidid;
254 0           set_config('min_fidid', $min_fidid);
255             }
256              
257             # set_server_setting( key, value )
258             # set value to undef to remove whatever is presently stored; returns 1 on success or
259             # undef on error
260             sub set_server_setting {
261 0     0 0   my ($class, $key, $val) = @_;
262 0 0         return unless $key;
263              
264 0           my $sto = Mgd::get_store();
265 0           $sto->set_server_setting($key, $val);
266 0           return 1;
267             }
268              
269             # get_server_setting( key )
270             # get value of server setting, undef on error (or no result)
271             sub server_setting {
272 0     0 0   my ($class, $key) = @_;
273 0           return Mgd::get_store()->server_setting($key);
274             }
275              
276             sub cache_server_setting {
277 0     0 0   my ($class, $key, $val) = @_;
278 0 0         $has_cached_settings++ unless $has_cached_settings;
279 0 0         if (! defined $val) {
280 0 0         delete $server_settings{$key}
281             if exists $server_settings{$key};
282             }
283 0           $server_settings{$key} = $val;
284             }
285              
286             sub server_setting_cached {
287 0     0 0   my ($class, $key, $fallback) = @_;
288 0 0         $fallback = 1 unless (defined $fallback);
289 0 0 0       if (!$has_cached_settings && $fallback) {
290 0           return MogileFS::Config->server_setting($key);
291             }
292 0           return $server_settings{$key};
293             }
294              
295             my $memc;
296             my $last_memc_server_fetch = 0;
297 21     21   10361 my $have_memc_module = eval "use Cache::Memcached; 1;";
  0         0  
  0         0  
298             sub memcache_client {
299 0 0   0 0   return undef unless $have_memc_module;
300              
301             # only reload the server list every 30 seconds
302 0           my $now = time();
303 0 0         return $memc if $last_memc_server_fetch > $now - 30;
304              
305 0   0       my @servers = grep(/:\d+$/, split(/\s*,\s*/, MogileFS::Config->server_setting_cached("memcache_servers") || ""));
306 0           $last_memc_server_fetch = $now;
307              
308 0 0         return ($memc = undef) unless @servers;
309              
310 0   0       $memc ||= Cache::Memcached->new;
311 0           $memc->set_servers(\@servers);
312              
313 0           return $memc;
314             }
315              
316             my $cache_hostname;
317             sub hostname {
318 0   0 0 0   return $cache_hostname ||= Sys::Hostname::hostname();
319             }
320              
321             sub server_setting_is_readable {
322 0     0 0   my ($class, $key) = @_;
323 0 0         return 1 if $key eq 'fsck_checksum';
324 0 0         return 0 if $key =~ /^fsck_/;
325 0           return 1;
326             }
327              
328             # returns subref which cleans (canonicalizes) the value, or dies if invalid format.
329             # my $cleanval = $code->($val);
330             sub server_setting_is_writable {
331 0     0 0   my ($class, $key) = @_;
332              
333             # common formats:
334 0     0     my $any = sub { $_[0]; };
  0            
335 0 0   0     my $del_if_blank = sub { $_[0] || undef };
  0            
336             my $bool = sub {
337 0     0     my $v = shift;
338 0 0         return "0" unless $v;
339 0 0         return "0" if $v =~ /^(0|f|off|n)/i;
340 0 0         return "1" if $v =~ /^(1|t|on|y)/i;
341 0           die "Unknown format";
342 0           };
343             my $num = sub {
344 0     0     my $v = shift;
345 0 0         return "0" unless $v;
346 0 0         return $v if $v =~ /^\d+$/;
347 0           die "Must be numeric";
348 0           };
349             my $matchre = sub {
350 0     0     my $re = shift;
351             return sub {
352 0           my $v = shift;
353 0 0         return $v if $v =~ /$re/;
354 0           die "Doesn't match acceptable format.";
355 0           };
356 0           };
357             my $valid_netmask = sub {
358 0     0     my $n = Net::Netmask->new2($_[0]);
359 0 0         die "Doesn't match an acceptable netmask" unless $n;
360 0           };
361             my $valid_netmask_list = sub {
362 0     0     my @ns = split /[,\s]+/, $_[0];
363 0           foreach my $n (@ns) {
364 0           $valid_netmask->($n);
365             }
366 0           return $_[0];
367 0           };
368              
369             # let slave settings go through unmodified, for now.
370 0 0         if ($key =~ /^slave_/) { return $del_if_blank };
  0            
371 0 0         if ($key eq "skip_devcount") { return $bool };
  0            
372 0 0         if ($key eq "skip_mkcol") { return $bool };
  0            
373 0 0         if ($key eq "case_sensitive_list_keys") { return $bool };
  0            
374 0 0         if ($key eq "memcache_servers") { return $any };
  0            
375 0 0         if ($key eq "memcache_ttl") { return $num };
  0            
376 0 0         if ($key eq "internal_queue_limit") { return $num };
  0            
377              
378             # ReplicationPolicy::MultipleNetworks
379 0 0         if ($key eq 'network_zones') { return $any };
  0            
380 0 0         if ($key =~ /^zone_/) { return $valid_netmask_list };
  0            
381              
382             # should probably restrict to (\d+)
383 0 0         if ($key =~ /^queue_/) { return $any };
  0            
384              
385 0 0         if ($key eq "fsck_checksum") {
386             return sub {
387 0     0     my $v = shift;
388 0 0         return "off" if $v eq "off";
389 0 0         return undef if $v eq "class";
390 0 0         return $v if MogileFS::Checksum->valid_alg($v);
391 0           die "Not a valid checksum algorithm";
392             }
393 0           }
394              
395 0           return 0;
396             }
397              
398             1;
399              
400             # Local Variables:
401             # mode: perl
402             # c-basic-indent: 4
403             # indent-tabs-mode: nil
404             # End: