2
package My::ConfigFactory;
15
# Rules to run first of all
22
my @share_locations= ("share/mysql", "sql/share", "share");
26
my ($self, $group)= @_;
27
my $basedir= $group->if_exist('basedir') ||
28
$self->{ARGS}->{basedir};
34
my ($self, $config, $group_name, $group)= @_;
35
return my_find_dir($self->get_basedir($group),
36
\@share_locations, "charsets");
40
my ($self, $config, $group_name, $group)= @_;
41
return my_find_dir($self->get_basedir($group),
42
\@share_locations, "english");
46
my ($self, $config, $group_name)= @_;
47
my $vardir= $self->{ARGS}->{vardir};
48
return "$vardir/$group_name/data";
52
my ($self, $config, $group_name, $group)= @_;
53
my $vardir= $self->{ARGS}->{vardir};
54
return "$vardir/run/$group_name.pid";
58
my ($self, $config, $group_name, $group)= @_;
59
my $hostname= $group->value('#host');
60
return $self->{HOSTS}->{$hostname}++;
65
# Get next host from HOSTS array
66
my @hosts= keys(%{$self->{HOSTS}});;
67
my $host_no= $self->{NEXT_HOST}++ % @hosts;
68
return $hosts[$host_no];
72
my ($config, $name, $value)= @_;
74
foreach my $group ( $config->groups() ) {
75
if ($group->option($name)) {
76
if ($group->value($name) eq $value){
85
my ($self, $config, $group_name, $group)= @_;
86
#define in the order that mysqlds are listed in my.cnf
88
my $server_id= $group->if_exist('server-id');
89
if (defined $server_id){
90
if (!is_unique($config, 'server-id', $server_id)) {
91
croak "The server-id($server_id) for '$group_name' is not unique";
97
$server_id= $self->{SERVER_ID}++;
98
} while(!is_unique($config, 'server-id', $server_id));
100
#print "$group_name: server_id: $server_id\n";
105
my ($self, $config, $group_name, $group)= @_;
106
# Put socket file in tmpdir
107
my $dir= $self->{ARGS}->{tmpdir};
108
return "$dir/$group_name.sock";
112
my ($self, $config, $group_name, $group)= @_;
113
my $dir= $self->{ARGS}->{tmpdir};
114
return "$dir/$group_name";
118
my ($self, $config, $group_name, $group)= @_;
119
my $dir= $self->{ARGS}->{vardir};
120
return "$dir/log/$group_name.err";
124
my ($self, $config, $group_name, $group)= @_;
125
my $dir= dirname($group->value('datadir'));
126
return "$dir/mysqld.log";
129
sub fix_log_slow_queries {
130
my ($self, $config, $group_name, $group)= @_;
131
my $dir= dirname($group->value('datadir'));
132
return "$dir/mysqld-slow.log";
135
sub fix_secure_file_priv {
137
my $vardir= $self->{ARGS}->{vardir};
138
# By default, prevent the started mysqld to access files outside of vardir
143
my ($self, $config, $group_name, $group)= @_;
144
my $basedir= $self->get_basedir($group);
145
return "$basedir/mysql-test/std_data";
150
return $self->{ARGS}->{ssl};
154
return if !ssl_supported(@_);
155
# Add skip-ssl if ssl is supported to avoid
156
# that mysqltest connects with SSL by default
161
return if !ssl_supported(@_);
162
my $std_data= fix_std_data(@_);
163
return "$std_data/cacert.pem"
166
sub fix_ssl_server_cert {
167
return if !ssl_supported(@_);
168
my $std_data= fix_std_data(@_);
169
return "$std_data/server-cert.pem"
172
sub fix_ssl_client_cert {
173
return if !ssl_supported(@_);
174
my $std_data= fix_std_data(@_);
175
return "$std_data/client-cert.pem"
178
sub fix_ssl_server_key {
179
return if !ssl_supported(@_);
180
my $std_data= fix_std_data(@_);
181
return "$std_data/server-key.pem"
184
sub fix_ssl_client_key {
185
return if !ssl_supported(@_);
186
my $std_data= fix_std_data(@_);
187
return "$std_data/client-key.pem"
192
# Rules to run for each mysqld in the config
193
# - will be run in order listed here
197
{ 'basedir' => sub { return shift->{ARGS}->{basedir}; } },
198
{ 'tmpdir' => \&fix_tmpdir },
199
{ 'character-sets-dir' => \&fix_charset_dir },
200
{ 'language' => \&fix_language },
201
{ 'datadir' => \&fix_datadir },
202
{ 'pid-file' => \&fix_pidfile },
203
{ '#host' => \&fix_host },
204
{ 'port' => \&fix_port },
205
{ 'socket' => \&fix_socket },
206
{ '#log-error' => \&fix_log_error },
207
{ 'log' => \&fix_log },
208
{ 'log-slow-queries' => \&fix_log_slow_queries },
209
{ '#user' => sub { return shift->{ARGS}->{user} || ""; } },
210
{ '#password' => sub { return shift->{ARGS}->{password} || ""; } },
211
{ 'server-id' => \&fix_server_id, },
212
# By default, prevent the started mysqld to access files outside of vardir
213
{ 'secure-file-priv' => sub { return shift->{ARGS}->{vardir}; } },
214
{ 'ssl-ca' => \&fix_ssl_ca },
215
{ 'ssl-cert' => \&fix_ssl_server_cert },
216
{ 'ssl-key' => \&fix_ssl_server_key },
220
sub fix_ndb_mgmd_port {
221
my ($self, $config, $group_name, $group)= @_;
222
my $hostname= $group->value('HostName');
223
return $self->{HOSTS}->{$hostname}++;
227
sub fix_cluster_dir {
228
my ($self, $config, $group_name, $group)= @_;
229
my $vardir= $self->{ARGS}->{vardir};
230
my (undef, $process_type, $idx, $suffix)= split(/\./, $group_name);
231
return "$vardir/mysql_cluster.$suffix/$process_type.$idx";
235
sub fix_cluster_backup_dir {
236
my ($self, $config, $group_name, $group)= @_;
237
my $vardir= $self->{ARGS}->{vardir};
238
my (undef, $process_type, $idx, $suffix)= split(/\./, $group_name);
239
return "$vardir/mysql_cluster.$suffix/";
244
# Rules to run for each ndb_mgmd in the config
245
# - will be run in order listed here
249
{ 'PortNumber' => \&fix_ndb_mgmd_port },
250
{ 'DataDir' => \&fix_cluster_dir },
255
# Rules to run for each ndbd in the config
256
# - will be run in order listed here
260
{ 'HostName' => \&fix_host },
261
{ 'DataDir' => \&fix_cluster_dir },
262
{ 'BackupDataDir' => \&fix_cluster_backup_dir },
267
# Rules to run for each cluster_config section
268
# - will be run in order listed here
270
my @cluster_config_rules=
272
{ 'ndb_mgmd' => \&fix_host },
273
{ 'ndbd' => \&fix_host },
274
{ 'mysqld' => \&fix_host },
275
{ 'ndbapi' => \&fix_host },
280
# Rules to run for [client] section
281
# - will be run in order listed here
289
# Rules to run for [mysqltest] section
290
# - will be run in order listed here
294
{ 'ssl-ca' => \&fix_ssl_ca },
295
{ 'ssl-cert' => \&fix_ssl_client_cert },
296
{ 'ssl-key' => \&fix_ssl_client_key },
297
{ 'skip-ssl' => \&fix_skip_ssl },
302
# Rules to run for [mysqlbinlog] section
303
# - will be run in order listed here
305
my @mysqlbinlog_rules=
307
{ 'character-sets-dir' => \&fix_charset_dir },
312
# Rules to run for [mysql_upgrade] section
313
# - will be run in order listed here
315
my @mysql_upgrade_rules=
317
{ 'tmpdir' => sub { return shift->{ARGS}->{tmpdir}; } },
322
# Generate a [client.<suffix>] group to be
323
# used for connecting to [mysqld.<suffix>]
325
sub post_check_client_group {
326
my ($self, $config, $client_group_name, $mysqld_group_name)= @_;
328
# Settings needed for client, copied from its "mysqld"
335
password => '#password',
338
my $group_to_copy_from= $config->group($mysqld_group_name);
339
while (my ($name_to, $name_from)= each( %client_needs )) {
340
my $option= $group_to_copy_from->option($name_from);
342
if (! defined $option){
344
croak "Could not get value for '$name_from'";
346
$config->insert($client_group_name, $name_to, $option->value())
351
sub post_check_client_groups {
352
my ($self, $config)= @_;
354
my $first_mysqld= $config->first_like('mysqld.');
356
return unless $first_mysqld;
358
# Always generate [client] pointing to the first
360
$self->post_check_client_group($config,
362
$first_mysqld->name());
364
# Then generate [client.<suffix>] for each [mysqld.<suffix>]
365
foreach my $mysqld ( $config->like('mysqld.') ) {
366
$self->post_check_client_group($config,
367
'client'.$mysqld->after('mysqld'),
375
# Generate [embedded] by copying the values
376
# needed from the default [mysqld] section
377
# and from first [mysqld.<suffix>]
379
sub post_check_embedded_group {
380
my ($self, $config)= @_;
382
return unless $self->{ARGS}->{embedded};
384
my $mysqld= $config->group('mysqld') or
385
croak "Can't run with embedded, config has no default mysqld section";
387
my $first_mysqld= $config->first_like('mysqld.') or
388
croak "Can't run with embedded, config has no mysqld";
392
'#log-error', # Embedded server writes stderr to mysqltest's log file
393
'slave-net-timeout', # Embedded server are not build with replication
396
foreach my $option ( $mysqld->options(), $first_mysqld->options() ) {
397
# Don't copy options whose name is in "no_copy" list
398
next if grep ( $option->name() eq $_, @no_copy);
400
$config->insert('embedded', $option->name(), $option->value())
406
sub resolve_at_variable {
407
my ($self, $config, $group, $option)= @_;
409
# Split the options value on last .
410
my @parts= split(/\./, $option->value());
411
my $option_name= pop(@parts);
412
my $group_name= join('.', @parts);
414
$group_name =~ s/^\@//; # Remove at
416
my $from_group= $config->group($group_name)
417
or croak "There is no group named '$group_name' that ",
418
"can be used to resolve '$option_name'";
420
my $from= $from_group->value($option_name);
421
$config->insert($group->name(), $option->name(), $from)
425
sub post_fix_resolve_at_variables {
426
my ($self, $config)= @_;
428
foreach my $group ( $config->groups() ) {
429
foreach my $option ( $group->options()) {
430
next unless defined $option->value();
432
$self->resolve_at_variable($config, $group, $option)
433
if ($option->value() =~ /^\@/);
438
sub post_fix_mysql_cluster_section {
439
my ($self, $config)= @_;
441
# Add a [mysl_cluster.<suffix>] section for each
442
# defined [cluster_config.<suffix>] section
443
foreach my $group ( $config->like('cluster_config\.\w*$') )
446
# Generate ndb_connectstring for this cluster
447
foreach my $ndb_mgmd ( $config->like('cluster_config.ndb_mgmd.')) {
448
if ($ndb_mgmd->suffix() eq $group->suffix()) {
449
my $host= $ndb_mgmd->value('HostName');
450
my $port= $ndb_mgmd->value('PortNumber');
451
push(@urls, "$host:$port");
454
croak "Could not generate valid ndb_connectstring for '$group'"
456
my $ndb_connectstring= join(";", @urls);
458
# Add ndb_connectstring to [mysql_cluster.<suffix>]
459
$config->insert('mysql_cluster'.$group->suffix(),
460
'ndb_connectstring', $ndb_connectstring);
462
# Add ndb_connectstring to each mysqld connected to this
464
foreach my $mysqld ( $config->like('cluster_config.mysqld.')) {
465
if ($mysqld->suffix() eq $group->suffix()) {
466
my $after= $mysqld->after('cluster_config.mysqld');
467
$config->insert("mysqld$after",
468
'ndb_connectstring', $ndb_connectstring);
475
# Rules to run last of all
479
\&post_check_client_groups,
480
\&post_fix_mysql_cluster_section,
481
\&post_fix_resolve_at_variables,
482
\&post_check_embedded_group,
486
sub run_rules_for_group {
487
my ($self, $config, $group, @rules)= @_;
488
foreach my $hash ( @rules ) {
489
while (my ($option, $rule)= each( %{$hash} )) {
490
# Only run this rule if the value is not already defined
491
if (!$config->exists($group->name(), $option)) {
493
if (ref $rule eq "CODE") {
494
# Call the rule function
495
$value= &$rule($self, $config, $group->name(),
496
$config->group($group->name()));
500
if (defined $value) {
501
$config->insert($group->name(), $option, $value, 1);
509
sub run_section_rules {
510
my ($self, $config, $name, @rules)= @_;
512
foreach my $group ( $config->like($name) ) {
513
$self->run_rules_for_group($config, $group, @rules);
518
sub run_generate_sections_from_cluster_config {
519
my ($self, $config)= @_;
521
my @options= ('ndb_mgmd', 'ndbd',
524
foreach my $group ( $config->like('cluster_config\.\w*$') ) {
526
# Keep track of current index per process type
528
map { $idxes{$_}= 1; } @options;
530
foreach my $option_name ( @options ) {
531
my $value= $group->value($option_name);
532
my @hosts= split(/,/, $value, -1); # -1 => return also empty strings
534
# Add at least one host
535
push(@hosts, undef) unless scalar(@hosts);
537
# Assign hosts unless already fixed
538
@hosts= map { $self->fix_host() unless $_; } @hosts;
540
# Write the hosts value back
541
$group->insert($option_name, join(",", @hosts));
543
# Generate sections for each host
544
foreach my $host ( @hosts ){
545
my $idx= $idxes{$option_name}++;
547
my $suffix= $group->suffix();
548
# Generate a section for ndb_mgmd to read
549
$config->insert("cluster_config.$option_name.$idx$suffix",
552
if ($option_name eq 'mysqld'){
554
$self->fix_cluster_dir($config,
555
"cluster_config.mysqld.$idx$suffix",
557
$config->insert("mysqld.$idx$suffix",
558
'datadir', "$datadir/data");
567
my ($class, $args)= @_;
569
my @required_args= ('basedir', 'baseport', 'vardir', 'template_path');
571
foreach my $required ( @required_args ) {
572
croak "you must pass '$required'" unless defined $args->{$required};
575
# Fill in hosts/port hash
577
my $baseport= $args->{baseport};
578
$args->{hosts}= [ 'localhost' ] unless exists($args->{hosts});
579
foreach my $host ( @{$args->{hosts}} ) {
580
$hosts->{$host}= $baseport;
583
# Open the config template
584
my $config= My::Config->new($args->{'template_path'});
585
my $extra_template_path= $args->{'extra_template_path'};
586
if ($extra_template_path){
587
$config->append(My::Config->new($extra_template_path));
600
foreach my $rule ( @pre_rules ) {
601
&$rule($self, $config);
606
$self->run_section_rules($config,
607
'cluster_config\.\w*$',
608
@cluster_config_rules);
609
$self->run_generate_sections_from_cluster_config($config);
611
$self->run_section_rules($config,
612
'cluster_config.ndb_mgmd.',
614
$self->run_section_rules($config,
615
'cluster_config.ndbd',
618
$self->run_section_rules($config,
622
# [mysqlbinlog] need additional settings
623
$self->run_rules_for_group($config,
624
$config->insert('mysqlbinlog'),
627
# [mysql_upgrade] need additional settings
628
$self->run_rules_for_group($config,
629
$config->insert('mysql_upgrade'),
630
@mysql_upgrade_rules);
632
# Additional rules required for [client]
633
$self->run_rules_for_group($config,
634
$config->insert('client'),
638
# Additional rules required for [mysqltest]
639
$self->run_rules_for_group($config,
640
$config->insert('mysqltest'),
645
foreach my $rule ( @post_rules ) {
646
&$rule($self, $config);