2
package My::ConfigFactory;
16
# Rules to run first of all
23
my @share_locations= ("share/mysql", "sql/share", "share");
27
my ($self, $group)= @_;
28
my $basedir= $group->if_exist('basedir') ||
29
$self->{ARGS}->{basedir};
35
my ($self, $config, $group_name, $group)= @_;
36
return my_find_dir($self->get_basedir($group),
37
\@share_locations, "charsets");
41
my ($self, $config, $group_name, $group)= @_;
42
return my_find_dir($self->get_basedir($group),
43
\@share_locations, "english");
47
my ($self, $config, $group_name)= @_;
48
my $vardir= $self->{ARGS}->{vardir};
49
return "$vardir/$group_name/data";
53
my ($self, $config, $group_name, $group)= @_;
54
my $vardir= $self->{ARGS}->{vardir};
55
return "$vardir/run/$group_name.pid";
59
my ($self, $config, $group_name, $group)= @_;
60
my $hostname= $group->value('#host');
61
return $self->{HOSTS}->{$hostname}++;
66
# Get next host from HOSTS array
67
my @hosts= keys(%{$self->{HOSTS}});;
68
my $host_no= $self->{NEXT_HOST}++ % @hosts;
69
return $hosts[$host_no];
73
my ($config, $name, $value)= @_;
75
foreach my $group ( $config->groups() ) {
76
if ($group->option($name)) {
77
if ($group->value($name) eq $value){
86
my ($self, $config, $group_name, $group)= @_;
87
#define in the order that mysqlds are listed in my.cnf
89
my $server_id= $group->if_exist('server-id');
90
if (defined $server_id){
91
if (!is_unique($config, 'server-id', $server_id)) {
92
croak "The server-id($server_id) for '$group_name' is not unique";
98
$server_id= $self->{SERVER_ID}++;
99
} while(!is_unique($config, 'server-id', $server_id));
101
#print "$group_name: server_id: $server_id\n";
106
my ($self, $config, $group_name, $group)= @_;
107
# Put socket file in tmpdir
108
my $dir= $self->{ARGS}->{tmpdir};
109
return "$dir/$group_name.sock";
113
my ($self, $config, $group_name, $group)= @_;
114
my $dir= $self->{ARGS}->{tmpdir};
115
return "$dir/$group_name";
119
my ($self, $config, $group_name, $group)= @_;
120
my $dir= $self->{ARGS}->{vardir};
121
return "$dir/log/$group_name.err";
125
my ($self, $config, $group_name, $group)= @_;
126
my $dir= dirname($group->value('datadir'));
127
return "$dir/mysqld.log";
130
sub fix_log_slow_queries {
131
my ($self, $config, $group_name, $group)= @_;
132
my $dir= dirname($group->value('datadir'));
133
return "$dir/mysqld-slow.log";
136
sub fix_secure_file_priv {
138
my $vardir= $self->{ARGS}->{vardir};
139
# By default, prevent the started mysqld to access files outside of vardir
144
my ($self, $config, $group_name, $group)= @_;
145
my $basedir= $self->get_basedir($group);
146
return "$basedir/mysql-test/std_data";
151
return $self->{ARGS}->{ssl};
155
return if !ssl_supported(@_);
156
# Add skip-ssl if ssl is supported to avoid
157
# that mysqltest connects with SSL by default
162
return if !ssl_supported(@_);
163
my $std_data= fix_std_data(@_);
164
return "$std_data/cacert.pem"
167
sub fix_ssl_server_cert {
168
return if !ssl_supported(@_);
169
my $std_data= fix_std_data(@_);
170
return "$std_data/server-cert.pem"
173
sub fix_ssl_client_cert {
174
return if !ssl_supported(@_);
175
my $std_data= fix_std_data(@_);
176
return "$std_data/client-cert.pem"
179
sub fix_ssl_server_key {
180
return if !ssl_supported(@_);
181
my $std_data= fix_std_data(@_);
182
return "$std_data/server-key.pem"
185
sub fix_ssl_client_key {
186
return if !ssl_supported(@_);
187
my $std_data= fix_std_data(@_);
188
return "$std_data/client-key.pem"
193
# Rules to run for each mysqld in the config
194
# - will be run in order listed here
198
{ 'basedir' => sub { return shift->{ARGS}->{basedir}; } },
199
{ 'tmpdir' => \&fix_tmpdir },
200
{ 'character-sets-dir' => \&fix_charset_dir },
201
{ 'language' => \&fix_language },
202
{ 'datadir' => \&fix_datadir },
203
{ 'pid-file' => \&fix_pidfile },
204
{ '#host' => \&fix_host },
205
{ 'port' => \&fix_port },
206
{ 'socket' => \&fix_socket },
207
{ '#log-error' => \&fix_log_error },
208
{ 'general_log' => 1 },
209
{ 'general_log_file' => \&fix_log },
210
{ 'slow_query_log' => 1 },
211
{ 'slow_query_log_file' => \&fix_log_slow_queries },
212
{ '#user' => sub { return shift->{ARGS}->{user} || ""; } },
213
{ '#password' => sub { return shift->{ARGS}->{password} || ""; } },
214
{ 'server-id' => \&fix_server_id, },
215
# By default, prevent the started mysqld to access files outside of vardir
216
{ 'secure-file-priv' => sub { return shift->{ARGS}->{vardir}; } },
217
{ 'ssl-ca' => \&fix_ssl_ca },
218
{ 'ssl-cert' => \&fix_ssl_server_cert },
219
{ 'ssl-key' => \&fix_ssl_server_key },
224
# For simplicity, we use the same names for shared memory and
226
push(@mysqld_rules, {'shared-memory-base-name' => \&fix_socket});
229
sub fix_ndb_mgmd_port {
230
my ($self, $config, $group_name, $group)= @_;
231
my $hostname= $group->value('HostName');
232
return $self->{HOSTS}->{$hostname}++;
236
sub fix_cluster_dir {
237
my ($self, $config, $group_name, $group)= @_;
238
my $vardir= $self->{ARGS}->{vardir};
239
my (undef, $process_type, $idx, $suffix)= split(/\./, $group_name);
240
return "$vardir/mysql_cluster.$suffix/$process_type.$idx";
244
sub fix_cluster_backup_dir {
245
my ($self, $config, $group_name, $group)= @_;
246
my $vardir= $self->{ARGS}->{vardir};
247
my (undef, $process_type, $idx, $suffix)= split(/\./, $group_name);
248
return "$vardir/mysql_cluster.$suffix/";
253
# Rules to run for each ndb_mgmd in the config
254
# - will be run in order listed here
258
{ 'PortNumber' => \&fix_ndb_mgmd_port },
259
{ 'DataDir' => \&fix_cluster_dir },
264
# Rules to run for each ndbd in the config
265
# - will be run in order listed here
269
{ 'HostName' => \&fix_host },
270
{ 'DataDir' => \&fix_cluster_dir },
271
{ 'BackupDataDir' => \&fix_cluster_backup_dir },
276
# Rules to run for each cluster_config section
277
# - will be run in order listed here
279
my @cluster_config_rules=
281
{ 'ndb_mgmd' => \&fix_host },
282
{ 'ndbd' => \&fix_host },
283
{ 'mysqld' => \&fix_host },
284
{ 'ndbapi' => \&fix_host },
289
# Rules to run for [client] section
290
# - will be run in order listed here
298
# Rules to run for [mysqltest] section
299
# - will be run in order listed here
303
{ 'ssl-ca' => \&fix_ssl_ca },
304
{ 'ssl-cert' => \&fix_ssl_client_cert },
305
{ 'ssl-key' => \&fix_ssl_client_key },
306
{ 'skip-ssl' => \&fix_skip_ssl },
311
# Rules to run for [mysqlbinlog] section
312
# - will be run in order listed here
314
my @mysqlbinlog_rules=
316
{ 'character-sets-dir' => \&fix_charset_dir },
321
# Rules to run for [mysql_upgrade] section
322
# - will be run in order listed here
324
my @mysql_upgrade_rules=
326
{ 'tmpdir' => sub { return shift->{ARGS}->{tmpdir}; } },
331
# Generate a [client.<suffix>] group to be
332
# used for connecting to [mysqld.<suffix>]
334
sub post_check_client_group {
335
my ($self, $config, $client_group_name, $mysqld_group_name)= @_;
337
# Settings needed for client, copied from its "mysqld"
344
password => '#password',
347
my $group_to_copy_from= $config->group($mysqld_group_name);
348
while (my ($name_to, $name_from)= each( %client_needs )) {
349
my $option= $group_to_copy_from->option($name_from);
351
if (! defined $option){
353
croak "Could not get value for '$name_from'";
355
$config->insert($client_group_name, $name_to, $option->value())
360
if (! $self->{ARGS}->{embedded})
362
# Shared memory base may or may not be defined (e.g not defined in embedded)
363
my $shm = $group_to_copy_from->option("shared-memory-base-name");
366
$config->insert($client_group_name,"shared-memory-base-name", $shm->value());
373
sub post_check_client_groups {
374
my ($self, $config)= @_;
376
my $first_mysqld= $config->first_like('mysqld.');
378
return unless $first_mysqld;
380
# Always generate [client] pointing to the first
382
$self->post_check_client_group($config,
384
$first_mysqld->name());
386
# Then generate [client.<suffix>] for each [mysqld.<suffix>]
387
foreach my $mysqld ( $config->like('mysqld.') ) {
388
$self->post_check_client_group($config,
389
'client'.$mysqld->after('mysqld'),
397
# Generate [embedded] by copying the values
398
# needed from the default [mysqld] section
399
# and from first [mysqld.<suffix>]
401
sub post_check_embedded_group {
402
my ($self, $config)= @_;
404
return unless $self->{ARGS}->{embedded};
406
my $mysqld= $config->group('mysqld') or
407
croak "Can't run with embedded, config has no default mysqld section";
409
my $first_mysqld= $config->first_like('mysqld.') or
410
croak "Can't run with embedded, config has no mysqld";
414
'#log-error', # Embedded server writes stderr to mysqltest's log file
415
'slave-net-timeout', # Embedded server are not build with replication
416
'shared-memory-base-name', # No shared memory for embedded
419
foreach my $option ( $mysqld->options(), $first_mysqld->options() ) {
420
# Don't copy options whose name is in "no_copy" list
421
next if grep ( $option->name() eq $_, @no_copy);
423
$config->insert('embedded', $option->name(), $option->value())
429
sub resolve_at_variable {
430
my ($self, $config, $group, $option)= @_;
432
# Split the options value on last .
433
my @parts= split(/\./, $option->value());
434
my $option_name= pop(@parts);
435
my $group_name= join('.', @parts);
437
$group_name =~ s/^\@//; # Remove at
439
my $from_group= $config->group($group_name)
440
or croak "There is no group named '$group_name' that ",
441
"can be used to resolve '$option_name'";
443
my $from= $from_group->value($option_name);
444
$config->insert($group->name(), $option->name(), $from)
448
sub post_fix_resolve_at_variables {
449
my ($self, $config)= @_;
451
foreach my $group ( $config->groups() ) {
452
foreach my $option ( $group->options()) {
453
next unless defined $option->value();
455
$self->resolve_at_variable($config, $group, $option)
456
if ($option->value() =~ /^\@/);
461
sub post_fix_mysql_cluster_section {
462
my ($self, $config)= @_;
464
# Add a [mysl_cluster.<suffix>] section for each
465
# defined [cluster_config.<suffix>] section
466
foreach my $group ( $config->like('cluster_config\.\w*$') )
469
# Generate ndb_connectstring for this cluster
470
foreach my $ndb_mgmd ( $config->like('cluster_config.ndb_mgmd.')) {
471
if ($ndb_mgmd->suffix() eq $group->suffix()) {
472
my $host= $ndb_mgmd->value('HostName');
473
my $port= $ndb_mgmd->value('PortNumber');
474
push(@urls, "$host:$port");
477
croak "Could not generate valid ndb_connectstring for '$group'"
479
my $ndb_connectstring= join(";", @urls);
481
# Add ndb_connectstring to [mysql_cluster.<suffix>]
482
$config->insert('mysql_cluster'.$group->suffix(),
483
'ndb_connectstring', $ndb_connectstring);
485
# Add ndb_connectstring to each mysqld connected to this
487
foreach my $mysqld ( $config->like('cluster_config.mysqld.')) {
488
if ($mysqld->suffix() eq $group->suffix()) {
489
my $after= $mysqld->after('cluster_config.mysqld');
490
$config->insert("mysqld$after",
491
'ndb_connectstring', $ndb_connectstring);
498
# Rules to run last of all
502
\&post_check_client_groups,
503
\&post_fix_mysql_cluster_section,
504
\&post_fix_resolve_at_variables,
505
\&post_check_embedded_group,
509
sub run_rules_for_group {
510
my ($self, $config, $group, @rules)= @_;
511
foreach my $hash ( @rules ) {
512
while (my ($option, $rule)= each( %{$hash} )) {
513
# Only run this rule if the value is not already defined
514
if (!$config->exists($group->name(), $option)) {
516
if (ref $rule eq "CODE") {
517
# Call the rule function
518
$value= &$rule($self, $config, $group->name(),
519
$config->group($group->name()));
523
if (defined $value) {
524
$config->insert($group->name(), $option, $value, 1);
532
sub run_section_rules {
533
my ($self, $config, $name, @rules)= @_;
535
foreach my $group ( $config->like($name) ) {
536
$self->run_rules_for_group($config, $group, @rules);
541
sub run_generate_sections_from_cluster_config {
542
my ($self, $config)= @_;
544
my @options= ('ndb_mgmd', 'ndbd',
547
foreach my $group ( $config->like('cluster_config\.\w*$') ) {
549
# Keep track of current index per process type
551
map { $idxes{$_}= 1; } @options;
553
foreach my $option_name ( @options ) {
554
my $value= $group->value($option_name);
555
my @hosts= split(/,/, $value, -1); # -1 => return also empty strings
557
# Add at least one host
558
push(@hosts, undef) unless scalar(@hosts);
560
# Assign hosts unless already fixed
561
@hosts= map { $self->fix_host() unless $_; } @hosts;
563
# Write the hosts value back
564
$group->insert($option_name, join(",", @hosts));
566
# Generate sections for each host
567
foreach my $host ( @hosts ){
568
my $idx= $idxes{$option_name}++;
570
my $suffix= $group->suffix();
571
# Generate a section for ndb_mgmd to read
572
$config->insert("cluster_config.$option_name.$idx$suffix",
575
if ($option_name eq 'mysqld'){
577
$self->fix_cluster_dir($config,
578
"cluster_config.mysqld.$idx$suffix",
580
$config->insert("mysqld.$idx$suffix",
581
'datadir', "$datadir/data");
590
my ($class, $args)= @_;
592
my @required_args= ('basedir', 'baseport', 'vardir', 'template_path');
594
foreach my $required ( @required_args ) {
595
croak "you must pass '$required'" unless defined $args->{$required};
598
# Fill in hosts/port hash
600
my $baseport= $args->{baseport};
601
$args->{hosts}= [ 'localhost' ] unless exists($args->{hosts});
602
foreach my $host ( @{$args->{hosts}} ) {
603
$hosts->{$host}= $baseport;
606
# Open the config template
607
my $config= My::Config->new($args->{'template_path'});
608
my $extra_template_path= $args->{'extra_template_path'};
609
if ($extra_template_path){
610
$config->append(My::Config->new($extra_template_path));
623
foreach my $rule ( @pre_rules ) {
624
&$rule($self, $config);
629
$self->run_section_rules($config,
630
'cluster_config\.\w*$',
631
@cluster_config_rules);
632
$self->run_generate_sections_from_cluster_config($config);
634
$self->run_section_rules($config,
635
'cluster_config.ndb_mgmd.',
637
$self->run_section_rules($config,
638
'cluster_config.ndbd',
641
$self->run_section_rules($config,
645
# [mysqlbinlog] need additional settings
646
$self->run_rules_for_group($config,
647
$config->insert('mysqlbinlog'),
650
# [mysql_upgrade] need additional settings
651
$self->run_rules_for_group($config,
652
$config->insert('mysql_upgrade'),
653
@mysql_upgrade_rules);
655
# Additional rules required for [client]
656
$self->run_rules_for_group($config,
657
$config->insert('client'),
661
# Additional rules required for [mysqltest]
662
$self->run_rules_for_group($config,
663
$config->insert('mysqltest'),
668
foreach my $rule ( @post_rules ) {
669
&$rule($self, $config);