From eed034b6d3725ad94c16cf17c3b17b441ae1d860 Mon Sep 17 00:00:00 2001 From: Mykola Malkov Date: Thu, 6 Oct 2022 11:48:08 +0300 Subject: [PATCH] MT#55554 Compare local schemes with master hosts Previously we compared only schemes between sp1 and sp2 and didn't check prx 3308 instances while it's quite important part. So: 1. Adopt compare_dbs.pl script. 1.1 Add host and port as the connection parameters. 1.2 Do not specify connection of remote instance but get the list of replicas and compare local schemes with remote ones. 1.3 Remove --schemes parameter and get the list of schemes from replication filter. 1.4 Use replication filters for exceptions. 1.4.1 Change 'constraints' query so it matches constraints// pattern. 1.5 Use names like : instead of Schema[12]. 2. Adopt ngcp-mysql-compare-dbs. 2.1 Get list of local mysql instances. 2.2 Remove usage of DB_BACKUP_LIST because compare_dbs.pl gets the list of schemes. Change-Id: I90eb0209d3b2a51cf4f9223c817b484d149db135 --- helper/compare_dbs.pl | 138 +++++++++++++++++++++--------------- sbin/ngcp-mysql-compare-dbs | 27 +++++-- 2 files changed, 102 insertions(+), 63 deletions(-) diff --git a/helper/compare_dbs.pl b/helper/compare_dbs.pl index 044da2b..225f8b1 100755 --- a/helper/compare_dbs.pl +++ b/helper/compare_dbs.pl @@ -23,17 +23,23 @@ my @diff_exceptions = qw( views/ldap/ldap_entries/view_definition tables/mysql/.+/create_options ); -my @missing_sp1_exceptions = qw(); -my @missing_sp2_exceptions = qw(); +my @local_missing_exceptions = qw(); +my @remote_missing_exceptions = qw(); + +my $exception_list = { + default_diff_exceptions => \@diff_exceptions, + default_local_missing_exceptions => \@local_missing_exceptions, + default_remote_missing_exceptions => \@remote_missing_exceptions, +}; my $credentials_file = '/etc/mysql/sipwise_extra.cnf'; my $argv = { formatter => '', schemes => '', + host_db1 => '', pass_db1 => '', - pass_db2 => '', user_db1 => '', - user_db2 => '', + port_db1 => '', }; get_options(); @@ -46,7 +52,7 @@ SELECT CREATE_OPTIONS, TABLE_NAME AS key_col FROM information_schema.TABLES - WHERE TABLE_SCHEMA = DATABASE() + WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME __SQL__ @@ -68,8 +74,8 @@ FROM information_schema.COLUMNS c INNER JOIN information_schema.TABLES t ON c.TABLE_NAME = t.TABLE_NAME WHERE t.TABLE_TYPE = 'BASE TABLE' - AND c.TABLE_SCHEMA = DATABASE() - AND t.TABLE_SCHEMA = DATABASE() + AND c.TABLE_SCHEMA = t.TABLE_SCHEMA + AND t.TABLE_SCHEMA = ? ORDER BY c.TABLE_NAME, c.COLUMN_NAME __SQL__ , @@ -87,7 +93,7 @@ SELECT INDEX_TYPE, CONCAT(TABLE_NAME, '/', INDEX_NAME, '/', SEQ_IN_INDEX) AS key_col FROM information_schema.STATISTICS -WHERE TABLE_SCHEMA = DATABASE() +WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, INDEX_NAME, COLUMN_NAME __SQL__ , @@ -101,14 +107,14 @@ SELECT rc.DELETE_RULE, cu.REFERENCED_COLUMN_NAME, cu.COLUMN_NAME, - CONCAT(rc.CONSTRAINT_NAME, '/', rc.TABLE_NAME, '/', + CONCAT( rc.TABLE_NAME, '/', rc.CONSTRAINT_NAME, '/', cu.COLUMN_NAME, '/', rc.REFERENCED_TABLE_NAME, '/', cu.REFERENCED_COLUMN_NAME) AS key_col FROM information_schema.REFERENTIAL_CONSTRAINTS rc LEFT JOIN information_schema.KEY_COLUMN_USAGE cu ON (rc.CONSTRAINT_NAME=cu.CONSTRAINT_NAME AND rc.CONSTRAINT_SCHEMA=cu.CONSTRAINT_SCHEMA) -WHERE rc.CONSTRAINT_SCHEMA = DATABASE() +WHERE rc.CONSTRAINT_SCHEMA = ? ORDER BY CONSTRAINT_NAME, rc.TABLE_NAME, cu.COLUMN_NAME __SQL__ , @@ -123,7 +129,7 @@ SELECT EVENT_OBJECT_TABLE, CONCAT(TRIGGER_NAME, '/', EVENT_OBJECT_TABLE) AS key_col FROM information_schema.TRIGGERS -WHERE TRIGGER_SCHEMA = DATABASE() +WHERE TRIGGER_SCHEMA = ? ORDER BY EVENT_OBJECT_TABLE, TRIGGER_NAME __SQL__ , @@ -133,7 +139,7 @@ SELECT TABLE_NAME AS key_col, VIEW_DEFINITION FROM information_schema.VIEWS -WHERE TABLE_SCHEMA = DATABASE() +WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME __SQL__ , @@ -144,47 +150,38 @@ SELECT ROUTINE_DEFINITION, ROUTINE_TYPE FROM information_schema.ROUTINES -WHERE ROUTINE_SCHEMA = DATABASE() +WHERE ROUTINE_SCHEMA = ? __SQL__ , }; my @objs_list = qw( tables columns indexes constraints triggers views routines ); -if ($argv->{schemes} eq '') { - warn " --schemes is empty\n\n"; - print_usage(); - exit 1; -} - +my $schema1 = "DBI:mysql:;host=$argv->{host_db1};port=$argv->{port_db1};mysql_read_default_file=$credentials_file"; my $dbh1 = DBI->connect( - "DBI:mysql:;host=sp1;mysql_read_default_file=$credentials_file", + $schema1, $argv->{user_db1}, $argv->{pass_db1}, { RaiseError => 1 } ) or - croak("Can't connect to db1: DBI:mysql:;host=sp1;mysql_read_default_file=$credentials_file, $argv->{user_db1}, $argv->{pass_db1} "); - -my $dbh2 = DBI->connect( - "DBI:mysql:;host=sp2;mysql_read_default_file=$credentials_file", - $argv->{user_db2}, - $argv->{pass_db2}, - { RaiseError => 1 } ) or - croak("Can't connect to db2: DBI:mysql:;host=sp2;mysql_read_default_file=$credentials_file, $argv->{user_db2}, $argv->{pass_db2} "); + croak("Can't connect to local db: $schema1"); +my $masters = $dbh1->selectall_hashref('SHOW ALL SLAVES STATUS', 'Master_Host'); my $res = []; my $exit = 0; -foreach my $schema ( split( / /, $argv->{schemes} ) ) { - $dbh1->do("USE $schema"); - $dbh2->do("USE $schema"); - - my ($sth1, $sth2); - my ($struct1, $struct2); - foreach my $obj ( @objs_list ) { - $struct1 = $dbh1->selectall_hashref( $queries->{$obj}, 'key_col' ); - $struct2 = $dbh2->selectall_hashref( $queries->{$obj}, 'key_col' ); - - print_diff($struct1, $struct2, $obj, $res, $schema); +foreach my $master ( keys( %{$masters} ) ) { + $exception_list->{local_missing_exceptions} = $exception_list->{default_local_missing_exceptions}; + $exception_list->{remote_missing_exceptions} = $exception_list->{remote_missing_exceptions}; + + my $master_port = $masters->{$master}->{Master_Port}; + my $schemes = $masters->{$master}->{Replicate_Wild_Do_Table}; + my $ignore_tables = $masters->{$master}->{Replicate_Ignore_Table}; + foreach my $entry ( split(/,/, $ignore_tables) ) { + foreach my $obj (@objs_list) { + push( @{$exception_list->{local_missing_exceptions}}, "$obj/" . $entry =~ s/\./\//r ); + } } + + compare_schemes($master, $master_port, $schemes); } if ( $argv->{formatter} eq 'tap' ) { @@ -201,28 +198,54 @@ sub get_options { GetOptions( 'formatter=s' => \$argv->{'formatter'}, 'schemes=s' => \$argv->{'schemes'}, + 'host-db1=s' => \$argv->{'host_db1'}, 'user-db1=s' => \$argv->{'user_db1'}, 'pass-db1=s' => \$argv->{'pass_db1'}, - 'user-db2=s' => \$argv->{'user_db2'}, - 'pass-db2=s' => \$argv->{'pass_db2'}, + 'port-db1=s' => \$argv->{'port_db1'}, 'help|h' => sub{ print_usage(); exit(0); }, ); } +sub compare_schemes { + my ($host, $port, $schemes) = @_; + my $schema2 = "DBI:mysql:;host=$host;port=$port;mysql_read_default_file=$credentials_file"; + my $dbh2 = DBI->connect( + $schema2, + '', + '', + { RaiseError => 1 } ) or + croak("Can't connect to remote db: $schema2"); + + my $connection = "$host:$port"; + my @schemes = map { s/\..*//r } split(/,/, $schemes); + + foreach my $schema (@schemes) { + my ($sth1, $sth2); + my ($struct1, $struct2); + foreach my $obj (@objs_list) { + $struct1 = $dbh1->selectall_hashref( $queries->{$obj}, 'key_col', undef, $schema ); + $struct2 = $dbh2->selectall_hashref( $queries->{$obj}, 'key_col', undef, $schema ); + + print_diff($struct1, $struct2, $obj, $res, $schema, $connection); + } + } +} + sub print_usage { my $usage =<<__USAGE__ Usage: compare_db.pl [] -This script compares two databases by structure and prints result. +This script compares structure of schemes on local mysql instance with +all configured replica instances and prints result. Options: --formatter=[tap] The format of output. Supported values: tap - print in a TAP format. --schemes= List of schemes which should be compared. + --host-db1= Host of the 1st schema --user-db1= User of the 1st schema --pass-db1= Password of the 1st schema - --user-db2= User of the 2nd schema - --pass-db2= Password of the 2nd schema. + --port-db1= Port of the 1st schema -h, --help Print this message and exit. __USAGE__ ; @@ -247,18 +270,21 @@ sub is_exception { } sub print_diff { - my ($obj1, $obj2, $object_name, $result, $schema) = @_; + my ($obj1, $obj2, $object_name, $result, $schema, $connection) = @_; + + my $schema1_name = "$argv->{host_db1}:$argv->{port_db1}"; + my $schema2_name = $connection; foreach my $key ( sort( keys( %{$obj1} ) ) ) { unless ( exists($obj2->{$key}) ) { - next if ( is_exception(\@missing_sp2_exceptions, $object_name, $schema, $key) ); - push( @{$result}, "Element: " . lc("$object_name/$schema/$key") . " is missing in Schema2" ); + next if ( is_exception($exception_list->{remote_missing_exceptions}, $object_name, $schema, $key) ); + push( @{$result}, "Element: " . lc("$object_name/$schema/$key") . " is missing in $schema2_name" ); next; } foreach my $c_name ( sort( keys( %{ $obj1->{$key} } ) ) ) { unless ( exists($obj2->{$key}->{$c_name}) ) { - next if ( is_exception(\@missing_sp2_exceptions, $object_name, $schema, $key, $c_name) ); - push( @{$result}, "Element: " . lc("$object_name/$schema/$key/$c_name") . " is missing in Schema2" ); + next if ( is_exception($exception_list->{remote_missing_exceptions}, $object_name, $schema, $key, $c_name) ); + push( @{$result}, "Element: " . lc("$object_name/$schema/$key/$c_name") . " is missing in $schema2_name" ); next; } @@ -269,24 +295,24 @@ sub print_diff { $obj2->{$key}->{$c_name} = 'NULL' if ( ! defined($obj2->{$key}->{$c_name}) ); if ( $obj1->{$key}->{$c_name} ne $obj2->{$key}->{$c_name} ) { - next if ( is_exception(\@diff_exceptions, $object_name, $schema, $key, $c_name) ); + next if ( is_exception($exception_list->{diff_exceptions}, $object_name, $schema, $key, $c_name) ); push( @{$result}, "Element: " . lc("$object_name/$schema/$key/$c_name") . " are not equal:\n ---\n" - . " Schema1: $obj1->{$key}->{$c_name}\n" - . " Schema2: $obj2->{$key}->{$c_name}" ); + . " $schema1_name: $obj1->{$key}->{$c_name}\n" + . " $schema2_name: $obj2->{$key}->{$c_name}" ); } } } foreach my $key ( sort( keys( %{$obj2} ) ) ) { unless ( exists($obj1->{$key}) ) { - next if ( is_exception(\@missing_sp1_exceptions, $object_name, $schema, $key) ); - push( @{$result}, "Element: " . lc("$object_name/$schema/$key") . " is missing in Schema1" ); + next if ( is_exception($exception_list->{local_missing_exceptions}, $object_name, $schema, $key) ); + push( @{$result}, "Element: " . lc("$object_name/$schema/$key") . " is missing in $schema1_name" ); next; } foreach my $c_name ( sort( keys( %{ $obj2->{$key} } ) ) ) { unless ( exists($obj1->{$key}->{$c_name}) ) { - next if ( is_exception(\@missing_sp1_exceptions, $object_name, $schema, $key, $c_name) ); - push( @{$result}, "Element: ". lc("$object_name/$schema/$key/$c_name") ." is missing in Schema1" ); + next if ( is_exception($exception_list->{local_missing_exceptions}, $object_name, $schema, $key, $c_name) ); + push( @{$result}, "Element: ". lc("$object_name/$schema/$key/$c_name") ." is missing in $schema1_name" ); next; } } diff --git a/sbin/ngcp-mysql-compare-dbs b/sbin/ngcp-mysql-compare-dbs index bf82541..52d28ea 100755 --- a/sbin/ngcp-mysql-compare-dbs +++ b/sbin/ngcp-mysql-compare-dbs @@ -18,6 +18,13 @@ Options: __USAGE__ } +get_local_instances() { + local_instances+=("${NGCP_HOSTNAME}:3306") + if [[ "${NGCP_TYPE}" == 'carrier' && "${NGCP_IS_PROXY}" == 'yes' ]]; then + local_instances+=("${NGCP_HOSTNAME}:3308") + fi +} + FORMATTER='' args=$(getopt -n "$(basename "$0")" -o h -l help,formatter: -- "$@") @@ -43,11 +50,12 @@ while true; do esac done -DB_BACKUP_LIST='/etc/ngcp-backup-tools/db-backup.conf' -if [[ ! -r "${DB_BACKUP_LIST}" ]]; then - echo "Cannot read mandatory config file ${DB_BACKUP_LIST}" 2>&1 +NGCP_ROLES='/etc/default/ngcp-roles' +if [[ ! -r "${NGCP_ROLES}" ]]; then + echo "Cannot read mandatory config file ${NGCP_ROLES}" 2>&1 exit 1 fi +. "${NGCP_ROLES}" MYSQL_CREDENTIALS='/etc/mysql/sipwise_extra.cnf' if [[ ! -r "${MYSQL_CREDENTIALS}" ]]; then @@ -55,11 +63,16 @@ if [[ ! -r "${MYSQL_CREDENTIALS}" ]]; then exit 1 fi -. "${DB_BACKUP_LIST}" declare -a opts if [[ -n "${FORMATTER}" ]]; then opts+=(--formatter="${FORMATTER}") fi -/usr/share/ngcp-system-tests/compare_dbs.pl \ - --schemes="${NGCP_DB_BACKUP_FINAL_LIST[*]}" \ - "${opts[@]}" + +declare -a local_instances=() +get_local_instances +for local_mysql in "${local_instances[@]}"; do + /usr/share/ngcp-system-tests/compare_dbs.pl \ + --host-db1="${local_mysql%:*}" \ + --port-db1="${local_mysql#*:}" \ + "${opts[@]}" +done