mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / mysql-test / lib / My / ConfigFactory.pm
blob521b337fefea0dae9560ae2d8d19f5a52ddfbdcf
1 # -*- cperl -*-
2 # Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Library General Public
6 # License as published by the Free Software Foundation; version 2
7 # of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Library General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 package My::ConfigFactory;
20 use strict;
21 use warnings;
22 use Carp;
24 use My::Config;
25 use My::Find;
26 use My::Platform;
28 use File::Basename;
32 # Rules to run first of all
34 my @pre_rules=
39 my @share_locations= ("share/mysql", "sql/share", "share");
42 sub get_basedir {
43 my ($self, $group)= @_;
44 my $basedir= $group->if_exist('basedir') ||
45 $self->{ARGS}->{basedir};
46 return $basedir;
49 sub get_testdir {
50 my ($self, $group)= @_;
51 my $testdir= $group->if_exist('testdir') ||
52 $self->{ARGS}->{testdir};
53 return $testdir;
57 sub fix_charset_dir {
58 my ($self, $config, $group_name, $group)= @_;
59 return my_find_dir($self->get_basedir($group),
60 \@share_locations, "charsets");
63 sub fix_language {
64 my ($self, $config, $group_name, $group)= @_;
65 return my_find_dir($self->get_basedir($group),
66 \@share_locations, "english");
69 sub fix_datadir {
70 my ($self, $config, $group_name)= @_;
71 my $vardir= $self->{ARGS}->{vardir};
72 return "$vardir/$group_name/data";
75 sub fix_pidfile {
76 my ($self, $config, $group_name, $group)= @_;
77 my $vardir= $self->{ARGS}->{vardir};
78 return "$vardir/run/$group_name.pid";
81 sub fix_port {
82 my ($self, $config, $group_name, $group)= @_;
83 my $hostname= $group->value('#host');
84 return $self->{HOSTS}->{$hostname}++;
87 sub fix_host {
88 my ($self)= @_;
89 # Get next host from HOSTS array
90 my @hosts= keys(%{$self->{HOSTS}});;
91 my $host_no= $self->{NEXT_HOST}++ % @hosts;
92 return $hosts[$host_no];
95 sub is_unique {
96 my ($config, $name, $value)= @_;
98 foreach my $group ( $config->groups() ) {
99 if ($group->option($name)) {
100 if ($group->value($name) eq $value){
101 return 0;
105 return 1;
108 sub fix_server_id {
109 my ($self, $config, $group_name, $group)= @_;
110 #define in the order that mysqlds are listed in my.cnf
112 my $server_id= $group->if_exist('server-id');
113 if (defined $server_id){
114 if (!is_unique($config, 'server-id', $server_id)) {
115 croak "The server-id($server_id) for '$group_name' is not unique";
117 return $server_id;
120 do {
121 $server_id= $self->{SERVER_ID}++;
122 } while(!is_unique($config, 'server-id', $server_id));
124 #print "$group_name: server_id: $server_id\n";
125 return $server_id;
128 sub fix_socket {
129 my ($self, $config, $group_name, $group)= @_;
130 # Put socket file in tmpdir
131 my $dir= $self->{ARGS}->{tmpdir};
132 return "$dir/$group_name.sock";
135 sub fix_tmpdir {
136 my ($self, $config, $group_name, $group)= @_;
137 my $dir= $self->{ARGS}->{tmpdir};
138 return "$dir/$group_name";
141 sub fix_log_error {
142 my ($self, $config, $group_name, $group)= @_;
143 my $dir= $self->{ARGS}->{vardir};
144 if ( $::opt_valgrind and $::opt_debug ) {
145 return "$dir/log/$group_name.trace";
146 } else {
147 return "$dir/log/$group_name.err";
151 sub fix_log {
152 my ($self, $config, $group_name, $group)= @_;
153 my $dir= dirname($group->value('datadir'));
154 return "$dir/mysqld.log";
157 sub fix_log_slow_queries {
158 my ($self, $config, $group_name, $group)= @_;
159 my $dir= dirname($group->value('datadir'));
160 return "$dir/mysqld-slow.log";
163 sub fix_secure_file_priv {
164 my ($self)= @_;
165 my $vardir= $self->{ARGS}->{vardir};
166 # By default, prevent the started mysqld to access files outside of vardir
167 return $vardir;
170 sub fix_std_data {
171 my ($self, $config, $group_name, $group)= @_;
172 my $testdir= $self->get_testdir($group);
173 return "$testdir/std_data";
176 sub ssl_supported {
177 my ($self)= @_;
178 return $self->{ARGS}->{ssl};
181 sub fix_skip_ssl {
182 return if !ssl_supported(@_);
183 # Add skip-ssl if ssl is supported to avoid
184 # that mysqltest connects with SSL by default
185 return 1;
188 sub fix_ssl_ca {
189 return if !ssl_supported(@_);
190 my $std_data= fix_std_data(@_);
191 return "$std_data/cacert.pem"
194 sub fix_ssl_server_cert {
195 return if !ssl_supported(@_);
196 my $std_data= fix_std_data(@_);
197 return "$std_data/server-cert.pem"
200 sub fix_ssl_client_cert {
201 return if !ssl_supported(@_);
202 my $std_data= fix_std_data(@_);
203 return "$std_data/client-cert.pem"
206 sub fix_ssl_server_key {
207 return if !ssl_supported(@_);
208 my $std_data= fix_std_data(@_);
209 return "$std_data/server-key.pem"
212 sub fix_ssl_client_key {
213 return if !ssl_supported(@_);
214 my $std_data= fix_std_data(@_);
215 return "$std_data/client-key.pem"
220 # Rules to run for each mysqld in the config
221 # - will be run in order listed here
223 my @mysqld_rules=
225 { 'basedir' => sub { return shift->{ARGS}->{basedir}; } },
226 { 'tmpdir' => \&fix_tmpdir },
227 { 'character-sets-dir' => \&fix_charset_dir },
228 { 'language' => \&fix_language },
229 { 'datadir' => \&fix_datadir },
230 { 'pid-file' => \&fix_pidfile },
231 { '#host' => \&fix_host },
232 { 'port' => \&fix_port },
233 { 'socket' => \&fix_socket },
234 { '#log-error' => \&fix_log_error },
235 { 'general_log' => 1 },
236 { 'general_log_file' => \&fix_log },
237 { 'slow_query_log' => 1 },
238 { 'slow_query_log_file' => \&fix_log_slow_queries },
239 { '#user' => sub { return shift->{ARGS}->{user} || ""; } },
240 { '#password' => sub { return shift->{ARGS}->{password} || ""; } },
241 { 'server-id' => \&fix_server_id, },
242 # By default, prevent the started mysqld to access files outside of vardir
243 { 'secure-file-priv' => sub { return shift->{ARGS}->{vardir}; } },
244 { 'ssl-ca' => \&fix_ssl_ca },
245 { 'ssl-cert' => \&fix_ssl_server_cert },
246 { 'ssl-key' => \&fix_ssl_server_key },
249 if (IS_WINDOWS)
251 # For simplicity, we use the same names for shared memory and
252 # named pipes.
253 push(@mysqld_rules, {'shared-memory-base-name' => \&fix_socket});
256 sub fix_ndb_mgmd_port {
257 my ($self, $config, $group_name, $group)= @_;
258 my $hostname= $group->value('HostName');
259 return $self->{HOSTS}->{$hostname}++;
263 sub fix_cluster_dir {
264 my ($self, $config, $group_name, $group)= @_;
265 my $vardir= $self->{ARGS}->{vardir};
266 my (undef, $process_type, $idx, $suffix)= split(/\./, $group_name);
267 return "$vardir/mysql_cluster.$suffix/$process_type.$idx";
271 sub fix_cluster_backup_dir {
272 my ($self, $config, $group_name, $group)= @_;
273 my $vardir= $self->{ARGS}->{vardir};
274 my (undef, $process_type, $idx, $suffix)= split(/\./, $group_name);
275 return "$vardir/mysql_cluster.$suffix/";
280 # Rules to run for each ndb_mgmd in the config
281 # - will be run in order listed here
283 my @ndb_mgmd_rules=
285 { 'PortNumber' => \&fix_ndb_mgmd_port },
286 { 'DataDir' => \&fix_cluster_dir },
291 # Rules to run for each ndbd in the config
292 # - will be run in order listed here
294 my @ndbd_rules=
296 { 'HostName' => \&fix_host },
297 { 'DataDir' => \&fix_cluster_dir },
298 { 'BackupDataDir' => \&fix_cluster_backup_dir },
303 # Rules to run for each cluster_config section
304 # - will be run in order listed here
306 my @cluster_config_rules=
308 { 'ndb_mgmd' => \&fix_host },
309 { 'ndbd' => \&fix_host },
310 { 'mysqld' => \&fix_host },
311 { 'ndbapi' => \&fix_host },
316 # Rules to run for [client] section
317 # - will be run in order listed here
319 my @client_rules=
325 # Rules to run for [mysqltest] section
326 # - will be run in order listed here
328 my @mysqltest_rules=
330 { 'ssl-ca' => \&fix_ssl_ca },
331 { 'ssl-cert' => \&fix_ssl_client_cert },
332 { 'ssl-key' => \&fix_ssl_client_key },
333 { 'skip-ssl' => \&fix_skip_ssl },
338 # Rules to run for [mysqlbinlog] section
339 # - will be run in order listed here
341 my @mysqlbinlog_rules=
343 { 'character-sets-dir' => \&fix_charset_dir },
348 # Rules to run for [mysql_upgrade] section
349 # - will be run in order listed here
351 my @mysql_upgrade_rules=
353 { 'tmpdir' => sub { return shift->{ARGS}->{tmpdir}; } },
358 # Generate a [client.<suffix>] group to be
359 # used for connecting to [mysqld.<suffix>]
361 sub post_check_client_group {
362 my ($self, $config, $client_group_name, $mysqld_group_name)= @_;
364 # Settings needed for client, copied from its "mysqld"
365 my %client_needs=
367 port => 'port',
368 socket => 'socket',
369 host => '#host',
370 user => '#user',
371 password => '#password',
374 my $group_to_copy_from= $config->group($mysqld_group_name);
375 while (my ($name_to, $name_from)= each( %client_needs )) {
376 my $option= $group_to_copy_from->option($name_from);
378 if (! defined $option){
379 #print $config;
380 croak "Could not get value for '$name_from'";
382 $config->insert($client_group_name, $name_to, $option->value())
385 if (IS_WINDOWS)
387 if (! $self->{ARGS}->{embedded})
389 # Shared memory base may or may not be defined (e.g not defined in embedded)
390 my $shm = $group_to_copy_from->option("shared-memory-base-name");
391 if (defined $shm)
393 $config->insert($client_group_name,"shared-memory-base-name", $shm->value());
400 sub post_check_client_groups {
401 my ($self, $config)= @_;
403 my $first_mysqld= $config->first_like('mysqld.');
405 return unless $first_mysqld;
407 # Always generate [client] pointing to the first
408 # [mysqld.<suffix>]
409 $self->post_check_client_group($config,
410 'client',
411 $first_mysqld->name());
413 # Then generate [client.<suffix>] for each [mysqld.<suffix>]
414 foreach my $mysqld ( $config->like('mysqld.') ) {
415 $self->post_check_client_group($config,
416 'client'.$mysqld->after('mysqld'),
417 $mysqld->name())
424 # Generate [embedded] by copying the values
425 # needed from the default [mysqld] section
426 # and from first [mysqld.<suffix>]
428 sub post_check_embedded_group {
429 my ($self, $config)= @_;
431 return unless $self->{ARGS}->{embedded};
433 my $mysqld= $config->group('mysqld') or
434 croak "Can't run with embedded, config has no default mysqld section";
436 my $first_mysqld= $config->first_like('mysqld.') or
437 croak "Can't run with embedded, config has no mysqld";
439 my @no_copy =
441 '#log-error', # Embedded server writes stderr to mysqltest's log file
442 'slave-net-timeout', # Embedded server are not build with replication
443 'shared-memory-base-name', # No shared memory for embedded
446 foreach my $option ( $mysqld->options(), $first_mysqld->options() ) {
447 # Don't copy options whose name is in "no_copy" list
448 next if grep ( $option->name() eq $_, @no_copy);
450 $config->insert('embedded', $option->name(), $option->value())
456 sub resolve_at_variable {
457 my ($self, $config, $group, $option)= @_;
459 # Split the options value on last .
460 my @parts= split(/\./, $option->value());
461 my $option_name= pop(@parts);
462 my $group_name= join('.', @parts);
464 $group_name =~ s/^\@//; # Remove at
466 my $from_group= $config->group($group_name)
467 or croak "There is no group named '$group_name' that ",
468 "can be used to resolve '$option_name'";
470 my $from= $from_group->value($option_name);
471 $config->insert($group->name(), $option->name(), $from)
475 sub post_fix_resolve_at_variables {
476 my ($self, $config)= @_;
478 foreach my $group ( $config->groups() ) {
479 foreach my $option ( $group->options()) {
480 next unless defined $option->value();
482 $self->resolve_at_variable($config, $group, $option)
483 if ($option->value() =~ /^\@/);
488 sub post_fix_mysql_cluster_section {
489 my ($self, $config)= @_;
491 # Add a [mysl_cluster.<suffix>] section for each
492 # defined [cluster_config.<suffix>] section
493 foreach my $group ( $config->like('cluster_config\.\w*$') )
495 my @urls;
496 # Generate ndb_connectstring for this cluster
497 foreach my $ndb_mgmd ( $config->like('cluster_config.ndb_mgmd.')) {
498 if ($ndb_mgmd->suffix() eq $group->suffix()) {
499 my $host= $ndb_mgmd->value('HostName');
500 my $port= $ndb_mgmd->value('PortNumber');
501 push(@urls, "$host:$port");
504 croak "Could not generate valid ndb_connectstring for '$group'"
505 unless @urls > 0;
506 my $ndb_connectstring= join(";", @urls);
508 # Add ndb_connectstring to [mysql_cluster.<suffix>]
509 $config->insert('mysql_cluster'.$group->suffix(),
510 'ndb_connectstring', $ndb_connectstring);
512 # Add ndb_connectstring to each mysqld connected to this
513 # cluster
514 foreach my $mysqld ( $config->like('cluster_config.mysqld.')) {
515 if ($mysqld->suffix() eq $group->suffix()) {
516 my $after= $mysqld->after('cluster_config.mysqld');
517 $config->insert("mysqld$after",
518 'ndb_connectstring', $ndb_connectstring);
525 # Rules to run last of all
527 my @post_rules=
529 \&post_check_client_groups,
530 \&post_fix_mysql_cluster_section,
531 \&post_fix_resolve_at_variables,
532 \&post_check_embedded_group,
536 sub run_rules_for_group {
537 my ($self, $config, $group, @rules)= @_;
538 foreach my $hash ( @rules ) {
539 while (my ($option, $rule)= each( %{$hash} )) {
540 # Only run this rule if the value is not already defined
541 if (!$config->exists($group->name(), $option)) {
542 my $value;
543 if (ref $rule eq "CODE") {
544 # Call the rule function
545 $value= &$rule($self, $config, $group->name(),
546 $config->group($group->name()));
547 } else {
548 $value= $rule;
550 if (defined $value) {
551 $config->insert($group->name(), $option, $value, 1);
559 sub run_section_rules {
560 my ($self, $config, $name, @rules)= @_;
562 foreach my $group ( $config->like($name) ) {
563 $self->run_rules_for_group($config, $group, @rules);
568 sub run_generate_sections_from_cluster_config {
569 my ($self, $config)= @_;
571 my @options= ('ndb_mgmd', 'ndbd',
572 'mysqld', 'ndbapi');
574 foreach my $group ( $config->like('cluster_config\.\w*$') ) {
576 # Keep track of current index per process type
577 my %idxes;
578 map { $idxes{$_}= 1; } @options;
580 foreach my $option_name ( @options ) {
581 my $value= $group->value($option_name);
582 my @hosts= split(/,/, $value, -1); # -1 => return also empty strings
584 # Add at least one host
585 push(@hosts, undef) unless scalar(@hosts);
587 # Assign hosts unless already fixed
588 @hosts= map { $self->fix_host() unless $_; } @hosts;
590 # Write the hosts value back
591 $group->insert($option_name, join(",", @hosts));
593 # Generate sections for each host
594 foreach my $host ( @hosts ){
595 my $idx= $idxes{$option_name}++;
597 my $suffix= $group->suffix();
598 # Generate a section for ndb_mgmd to read
599 $config->insert("cluster_config.$option_name.$idx$suffix",
600 "HostName", $host);
602 if ($option_name eq 'mysqld'){
603 my $datadir=
604 $self->fix_cluster_dir($config,
605 "cluster_config.mysqld.$idx$suffix",
606 $group);
607 $config->insert("mysqld.$idx$suffix",
608 'datadir', "$datadir/data");
616 sub new_config {
617 my ($class, $args)= @_;
619 my @required_args= ('basedir', 'baseport', 'vardir', 'template_path');
621 foreach my $required ( @required_args ) {
622 croak "you must pass '$required'" unless defined $args->{$required};
625 # Fill in hosts/port hash
626 my $hosts= {};
627 my $baseport= $args->{baseport};
628 $args->{hosts}= [ 'localhost' ] unless exists($args->{hosts});
629 foreach my $host ( @{$args->{hosts}} ) {
630 $hosts->{$host}= $baseport;
633 # Open the config template
634 my $config= My::Config->new($args->{'template_path'});
635 my $extra_template_path= $args->{'extra_template_path'};
636 if ($extra_template_path){
637 $config->append(My::Config->new($extra_template_path));
639 my $self= bless {
640 CONFIG => $config,
641 ARGS => $args,
642 HOSTS => $hosts,
643 NEXT_HOST => 0,
644 SERVER_ID => 1,
645 }, $class;
649 # Run pre rules
650 foreach my $rule ( @pre_rules ) {
651 &$rule($self, $config);
656 $self->run_section_rules($config,
657 'cluster_config\.\w*$',
658 @cluster_config_rules);
659 $self->run_generate_sections_from_cluster_config($config);
661 $self->run_section_rules($config,
662 'cluster_config.ndb_mgmd.',
663 @ndb_mgmd_rules);
664 $self->run_section_rules($config,
665 'cluster_config.ndbd',
666 @ndbd_rules);
668 $self->run_section_rules($config,
669 'mysqld.',
670 @mysqld_rules);
672 # [mysqlbinlog] need additional settings
673 $self->run_rules_for_group($config,
674 $config->insert('mysqlbinlog'),
675 @mysqlbinlog_rules);
677 # [mysql_upgrade] need additional settings
678 $self->run_rules_for_group($config,
679 $config->insert('mysql_upgrade'),
680 @mysql_upgrade_rules);
682 # Additional rules required for [client]
683 $self->run_rules_for_group($config,
684 $config->insert('client'),
685 @client_rules);
688 # Additional rules required for [mysqltest]
689 $self->run_rules_for_group($config,
690 $config->insert('mysqltest'),
691 @mysqltest_rules);
694 # Run post rules
695 foreach my $rule ( @post_rules ) {
696 &$rule($self, $config);
700 return $config;