File Coverage

blib/lib/MogileFS/Config.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package MogileFS::Config;
2 7     7   38 use strict;
  7         14  
  7         308  
3             require Exporter;
4 7     7   8690 use MogileFS::ProcManager;
  7         25  
  7         271  
5 7     7   11402 use Getopt::Long;
  7         102736  
  7         51  
6 7     7   7569 use MogileFS::Store;
  0            
  0            
7             use Sys::Hostname ();
8              
9             our @ISA = qw(Exporter);
10             our @EXPORT = qw($DEBUG config set_config);
11             our @EXPORT_OK = qw(DEVICE_SUMMARY_CACHE_TIMEOUT);
12              
13             our ($DEFAULT_CONFIG, $DEFAULT_MOG_ROOT, $MOG_ROOT, $MOGSTORED_STREAM_PORT, $DEBUG);
14             $DEBUG = 0;
15             $DEFAULT_CONFIG = "/etc/mogilefs/mogilefsd.conf";
16             $DEFAULT_MOG_ROOT = "/mnt/mogilefs";
17             $MOGSTORED_STREAM_PORT = 7501;
18              
19             use constant DEVICE_SUMMARY_CACHE_TIMEOUT => 15;
20              
21             my %conf;
22             sub set_config {
23             shift if @_ == 3;
24             my ($k, $v) = @_;
25              
26             # if a child, propogate to parent
27             if (my $worker = MogileFS::ProcManager->is_child) {
28             $worker->send_to_parent(":set_config_from_child $k $v");
29             } else {
30             MogileFS::ProcManager->send_to_all_children(":set_config_from_parent $k $v");
31             }
32              
33             return set_config_no_broadcast($k, $v);
34             }
35              
36             sub set_config_no_broadcast {
37             shift if @_ == 3;
38             my ($k, $v) = @_;
39             return $conf{$k} = $v;
40             }
41              
42             set_config("mogstored_stream_port" => $MOGSTORED_STREAM_PORT);
43             set_config('default_mindevcount', 2);
44              
45             our (
46             %cmdline,
47             %cfgfile,
48             $config,
49             $skipconfig,
50             $daemonize,
51             $db_dsn,
52             $db_user,
53             $db_pass,
54             $conf_port,
55             $listen,
56             $query_jobs,
57             $delete_jobs,
58             $replicate_jobs,
59             $reaper_jobs,
60             $monitor_jobs,
61             $mog_root,
62             $min_free_space,
63             $max_disk_age,
64             $node_timeout, # time in seconds to wait for storage node responses
65             $old_repl_compat,
66             $pidfile,
67             );
68              
69             my $default_mindevcount;
70              
71             sub load_config {
72             my $dummy_workerport;
73              
74             # Command-line options will override
75             Getopt::Long::Configure( "bundling" );
76             Getopt::Long::GetOptions(
77             'c|config=s' => \$config,
78             's|skipconfig' => \$skipconfig,
79             'd|debug+' => \$cmdline{debug},
80             'D|daemonize' => \$cmdline{daemonize},
81             'dsn=s' => \$cmdline{db_dsn},
82             'dbuser=s' => \$cmdline{db_user},
83             'dbpass:s' => \$cmdline{db_pass},
84             'user=s' => \$cmdline{user},
85             'r|mogroot=s' => \$cmdline{mog_root},
86             'p|confport=i' => \$cmdline{conf_port},
87             'l|listen=s@' => \$cmdline{listen},
88             'w|workers=i' => \$cmdline{query_jobs},
89             'no_http' => \$cmdline{no_http}, # OLD, we just eat it to shut it up.
90             'workerport=i' => \$dummy_workerport, # eat it for backwards compat
91             'maxdiskage=i' => \$cmdline{max_disk_age},
92             'minfreespace=i' => \$cmdline{min_free_space},
93             'default_mindevcount=i' => \$cmdline{default_mindevcount},
94             'node_timeout=i' => \$cmdline{node_timeout},
95             'pidfile=s' => \$cmdline{pidfile},
96             'no_schema_check' => \$cmdline{no_schema_check},
97             'old_repl_compat=i' => \$cmdline{old_repl_compat},
98             'plugins=s@' => \$cmdline{plugins},
99             );
100              
101             # warn of old/deprecated options
102             warn "The command line option --workerport is no longer needed (and has no necessary replacement)\n"
103             if $dummy_workerport;
104              
105             $config = $DEFAULT_CONFIG if !$config && -r $DEFAULT_CONFIG;
106              
107             # Read the config file if one was specified
108             if ($config && !$skipconfig) {
109             open my $cf, "<$config" or die "open: $config: $!";
110              
111             my $configLine = qr{
112             ^\s* # Leading space
113             ([\w.]+) # Key
114             \s+ =? \s* # space + optional equal + optional space
115             (.+?) # Value
116             \s*$ # Trailing space
117             }x;
118              
119             my $linecount = 0;
120             while (defined( my $line = <$cf> )) {
121             $linecount++;
122             next if $line =~ m!^\s*(\#.*)?$!;
123             die "Malformed config file (line $linecount)" unless $line =~ $configLine;
124              
125             my ( $key, $value ) = ( $1, $2 );
126             print STDERR "Setting '$key' to '$value'\n" if $cmdline{debug};
127             $cfgfile{$key} = $value;
128             }
129              
130             close $cf;
131             }
132              
133             # Fill in defaults for those values which were either loaded from config or
134             # specified on the command line. Command line takes precendence, then values in
135             # the config file, then the defaults.
136             $daemonize = choose_value( 'daemonize', 0 );
137             $db_dsn = choose_value( 'db_dsn', "DBI:mysql:mogilefs" );
138             $db_user = choose_value( 'db_user', "mogile" );
139             $db_pass = choose_value( 'db_pass', "", 1 );
140             $conf_port = choose_value( 'conf_port', 7001 );
141             $MOG_ROOT = set_config('root',
142             choose_value( 'mog_root', $DEFAULT_MOG_ROOT )
143             );
144             $query_jobs = set_config("query_jobs",
145             choose_value( 'listener_jobs', undef) || # undef if not present, then we
146             choose_value( 'query_jobs', 20 )); # fall back to query_jobs, new name
147             $delete_jobs = choose_value( 'delete_jobs', 1 );
148             $replicate_jobs = choose_value( 'replicate_jobs', 1 );
149             $reaper_jobs = choose_value( 'reaper_jobs', 1 );
150             $monitor_jobs = choose_value( 'monitor_jobs', 1 );
151             $min_free_space = choose_value( 'min_free_space', 100 );
152             $max_disk_age = choose_value( 'max_disk_age', 5 );
153             $DEBUG = choose_value( 'debug', $ENV{DEBUG} || 0 );
154             $pidfile = choose_value( 'pidfile', "" );
155              
156             choose_value( 'default_mindevcount', 2 );
157             $node_timeout = choose_value( 'node_timeout', 2 );
158              
159             $old_repl_compat = choose_value( 'old_repl_compat', 1 );
160              
161             choose_value( 'no_schema_check', 0 );
162              
163             # now load plugins
164             my @plugins;
165             push @plugins, $cfgfile{plugins} if $cfgfile{plugins};
166             push @plugins, @{$cmdline{plugins}} if $cmdline{plugins};
167              
168             foreach my $plugin (@plugins) {
169             load_plugins($plugin);
170             }
171              
172             choose_value('user', '');
173              
174             # fix up config file listen option
175             $cfgfile{listen} = [ split(/\s*,\s*/, $cfgfile{listen}) ] if defined $cfgfile{listen};
176              
177             # now let's fix up the listen option to include the port if it doesn't already; we can't use
178             # choose_value as that uses set_config and that sends to children; this option doesn't apply
179             my $temp_listen = $cmdline{listen} || $cfgfile{listen} || [ '0.0.0.0' ];
180             $conf{listen} = $listen = [ map { /:/ ? $_ : "$_:$conf{conf_port}" } @$temp_listen ];
181             }
182              
183             ### FUNCTION: choose_value( $name, $default )
184             sub choose_value {
185             my ( $name, $default ) = @_;
186             return set_config($name, $cmdline{$name}) if defined $cmdline{$name};
187             return set_config($name, $cfgfile{$name}) if defined $cfgfile{$name};
188             return set_config($name, $default);
189             }
190              
191             sub load_plugins {
192             my $plugins = shift;
193             foreach my $plugin (split(/\s*,\s*/, $plugins)) {
194             my $rv = eval "use MogileFS::Plugin::$plugin; MogileFS::Plugin::$plugin->load; 1;";
195             die "Unable to load $plugin: $@\n" unless $rv;
196             }
197             }
198              
199             sub config {
200             shift if @_ == 2;
201             my $k = shift;
202             die "No config variable '$k'" unless defined $conf{$k};
203             return $conf{$k};
204             }
205              
206             sub check_database {
207             my $sto = eval { Mgd::get_store() };
208             unless ($sto && $sto->ping) {
209             die qq{
210             Error: unable to establish connection with your MogileFS database.
211              
212             Please verify that you have correctly setup a configuration file or are
213             providing the correct information in order to reach the database and try
214             running the MogileFS server again. If you haven\'t setup your database yet,
215             run 'mogdbsetup'.
216              
217             Details: [sto=$sto, err=$@]
218             }
219             }
220              
221             my $sversion = MogileFS::Config->server_setting('schema_version') || 0;
222             my $expect_ver = MogileFS::Store->latest_schema_version;
223             unless ($sversion == $expect_ver || MogileFS::Config->config('no_schema_check')) {
224             die "Server's database schema version of $sversion doesn't match expected value of $expect_ver. Halting.\n\n".
225             "Please run mogdbsetup to upgrade your schema.\n";
226             }
227              
228             $sto->pre_daemonize_checks;
229             }
230              
231             # set_server_setting( key, value )
232             # set value to undef to remove whatever is presently stored; returns 1 on success or
233             # undef on error
234             sub set_server_setting {
235             my ($class, $key, $val) = @_;
236             return unless $key;
237              
238             my $sto = Mgd::get_store();
239             $sto->set_server_setting($key, $val);
240             return 1;
241             }
242              
243             # get_server_setting( key )
244             # get value of server setting, undef on error (or no result)
245             sub server_setting {
246             my ($class, $key) = @_;
247             return Mgd::get_store()->server_setting($key);
248             }
249              
250              
251             my $memc;
252             my $last_memc_server_fetch = 0;
253             my $have_memc_module = eval "use Cache::Memcached; 1;";
254             sub memcache_client {
255             return undef unless $have_memc_module;
256             $memc ||= Cache::Memcached->new;
257              
258             # only reload the server list every 30 seconds
259             my $now = time();
260             return $memc if $last_memc_server_fetch > $now - 30;
261              
262             my @servers = split(/\s*,\s*/, MogileFS::Config->server_setting("memcache_servers") || "");
263             $memc->set_servers(\@servers);
264             $last_memc_server_fetch = $now;
265              
266             return $memc;
267             }
268              
269             my $cache_hostname;
270             sub hostname {
271             return $cache_hostname ||= Sys::Hostname::hostname();
272             }
273              
274             sub server_setting_is_readable {
275             my ($class, $key) = @_;
276             return 0 if $key =~ /^fsck_/;
277             return 1;
278             }
279              
280             # returns subref which cleans (canonicalizes) the value, or dies if invalid format.
281             # my $cleanval = $code->($val);
282             sub server_setting_is_writable {
283             my ($class, $key) = @_;
284              
285             # common formats:
286             my $any = sub { $_[0]; };
287             my $del_if_blank = sub { $_[0] || undef };
288             my $bool = sub {
289             my $v = shift;
290             return "0" unless $v;
291             return "0" if $v =~ /^(0|f|off|n)/i;
292             return "1" if $v =~ /^(1|t|on|y)/i;
293             die "Unknown format";
294             };
295             my $matchre = sub {
296             my $re = shift;
297             return sub {
298             my $v = shift;
299             return $v if $v =~ /$re/;
300             die "Doesn't match acceptable format.";
301             };
302             };
303              
304             # let slave settings go through unmodified, for now.
305             if ($key =~ /^slave_/) { return $del_if_blank };
306             if ($key eq "enable_rebalance") { return $bool };
307             if ($key eq "memcache_servers") { return $any };
308              
309             if ($key eq "rebalance_policy") { return sub {
310             my $v = shift;
311             return undef unless $v;
312             # TODO: actually load the provided class and test if it loads?
313             die "Doesn't match acceptable format" unless
314             $v =~ /^[\w:\-]+$/;
315             return $v;
316             }}
317              
318             return 0;
319             }
320              
321             1;
322              
323             # Local Variables:
324             # mode: perl
325             # c-basic-indent: 4
326             # indent-tabs-mode: nil
327             # End: