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
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
;
32 # Rules to run first of all
39 my @share_locations= ("share/mysql", "sql/share", "share");
43 my ($self, $group)= @_;
44 my $basedir= $group->if_exist('basedir') ||
45 $self->{ARGS
}->{basedir
};
50 my ($self, $group)= @_;
51 my $testdir= $group->if_exist('testdir') ||
52 $self->{ARGS
}->{testdir
};
58 my ($self, $config, $group_name, $group)= @_;
59 return my_find_dir
($self->get_basedir($group),
60 \
@share_locations, "charsets");
64 my ($self, $config, $group_name, $group)= @_;
65 return my_find_dir
($self->get_basedir($group),
66 \
@share_locations, "english");
70 my ($self, $config, $group_name)= @_;
71 my $vardir= $self->{ARGS
}->{vardir
};
72 return "$vardir/$group_name/data";
76 my ($self, $config, $group_name, $group)= @_;
77 my $vardir= $self->{ARGS
}->{vardir
};
78 return "$vardir/run/$group_name.pid";
82 my ($self, $config, $group_name, $group)= @_;
83 my $hostname= $group->value('#host');
84 return $self->{HOSTS
}->{$hostname}++;
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];
96 my ($config, $name, $value)= @_;
98 foreach my $group ( $config->groups() ) {
99 if ($group->option($name)) {
100 if ($group->value($name) eq $value){
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";
121 $server_id= $self->{SERVER_ID
}++;
122 } while(!is_unique
($config, 'server-id', $server_id));
124 #print "$group_name: server_id: $server_id\n";
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";
136 my ($self, $config, $group_name, $group)= @_;
137 my $dir= $self->{ARGS
}->{tmpdir
};
138 return "$dir/$group_name";
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";
147 return "$dir/log/$group_name.err";
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
{
165 my $vardir= $self->{ARGS
}->{vardir
};
166 # By default, prevent the started mysqld to access files outside of vardir
171 my ($self, $config, $group_name, $group)= @_;
172 my $testdir= $self->get_testdir($group);
173 return "$testdir/std_data";
178 return $self->{ARGS
}->{ssl
};
182 return if !ssl_supported
(@_);
183 # Add skip-ssl if ssl is supported to avoid
184 # that mysqltest connects with SSL by default
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
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
},
251 # For simplicity, we use the same names for shared memory and
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
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
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
325 # Rules to run for [mysqltest] section
326 # - will be run in order listed here
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"
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){
380 croak
"Could not get value for '$name_from'";
382 $config->insert($client_group_name, $name_to, $option->value())
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");
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
409 $self->post_check_client_group($config,
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'),
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";
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*$') )
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'"
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
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
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)) {
543 if (ref $rule eq "CODE") {
544 # Call the rule function
545 $value= &$rule($self, $config, $group->name(),
546 $config->group($group->name()));
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',
574 foreach my $group ( $config->like('cluster_config\.\w*$') ) {
576 # Keep track of current index per process type
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",
602 if ($option_name eq 'mysqld'){
604 $self->fix_cluster_dir($config,
605 "cluster_config.mysqld.$idx$suffix",
607 $config->insert("mysqld.$idx$suffix",
608 'datadir', "$datadir/data");
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
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));
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.',
664 $self->run_section_rules($config,
665 'cluster_config.ndbd',
668 $self->run_section_rules($config,
672 # [mysqlbinlog] need additional settings
673 $self->run_rules_for_group($config,
674 $config->insert('mysqlbinlog'),
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'),
688 # Additional rules required for [mysqltest]
689 $self->run_rules_for_group($config,
690 $config->insert('mysqltest'),
695 foreach my $rule ( @post_rules ) {
696 &$rule($self, $config);