From 14dcc78cef469b42dfc46722b3ccb6594d757d7b Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 14 Nov 2022 10:22:00 -0800 Subject: [PATCH 01/65] Adding super read only in cnf file Signed-off-by: Rameez Sajwani --- config/embed.go | 3 + config/init_db.sql | 11 ++++ config/init_maria_db.sql | 106 ++++++++++++++++++++++++++++++++++++ config/mycnf/mysql57.cnf | 5 ++ config/mycnf/mysql80.cnf | 3 + go/cmd/vtbackup/vtbackup.go | 7 +++ 6 files changed, 135 insertions(+) create mode 100644 config/init_maria_db.sql diff --git a/config/embed.go b/config/embed.go index b2a9333e6de..56d5ac416b1 100644 --- a/config/embed.go +++ b/config/embed.go @@ -16,3 +16,6 @@ var MycnfMySQL57 string //go:embed mycnf/mysql80.cnf var MycnfMySQL80 string + +//go:embed init_maria_db.sql +var DefaultInitMariaDB string diff --git a/config/init_db.sql b/config/init_db.sql index 7be4de6f7ea..954241e3f94 100644 --- a/config/init_db.sql +++ b/config/init_db.sql @@ -11,6 +11,12 @@ ############################################################################### # Equivalent of mysql_secure_installation ############################################################################### +# We need to ensure that super_read_only is disabled so that we can execute +# these commands. Note that disabling it does NOT disable read_only. +# We save the current value so that we only re-enable it at the end if it was +# enabled before. +SET @original_super_read_only=IF(@@global.super_read_only=1, 'ON', 'OFF'); +SET GLOBAL super_read_only='OFF'; # Changes during the init db should not make it to the binlog. # They could potentially create errant transactions on replicas. @@ -77,3 +83,8 @@ FLUSH PRIVILEGES; RESET SLAVE ALL; RESET MASTER; + +# add custom sql here + +# We need to set super_read_only back to what it was before +SET GLOBAL super_read_only=IFNULL(@original_super_read_only, 'OFF'); \ No newline at end of file diff --git a/config/init_maria_db.sql b/config/init_maria_db.sql new file mode 100644 index 00000000000..f33c18d4072 --- /dev/null +++ b/config/init_maria_db.sql @@ -0,0 +1,106 @@ +# This file is executed immediately after mysql_install_db, +# to initialize a fresh data directory. It is mariaDB equivalent of init_db.sql. +# Since init_db.sql is for mysql which has super_read_only related stuff, and mariaDB +# does not recognize super_read_only, therefore we end up creating this file + +############################################################################### +# WARNING: This sql is *NOT* safe for production use, +# as it contains default well-known users and passwords. +# Care should be taken to change these users and passwords +# for production. +############################################################################### + +############################################################################### +# Equivalent of mysql_secure_installation +############################################################################### +# Changes during the init db should not make it to the binlog. +# They could potentially create errant transactions on replicas. +SET sql_log_bin = 0; +# Remove anonymous users. +DELETE FROM mysql.user WHERE User = ''; + +# Disable remote root access (only allow UNIX socket). +DELETE FROM mysql.user WHERE User = 'root' AND Host != 'localhost'; + +# Remove test database. +DROP DATABASE IF EXISTS test; + +############################################################################### +# Vitess defaults +############################################################################### + +# Vitess-internal database. +CREATE DATABASE IF NOT EXISTS _vt; +# Note that definitions of local_metadata and shard_metadata should be the same +# as in production which is defined in go/vt/mysqlctl/metadata_tables.go. +CREATE TABLE IF NOT EXISTS _vt.local_metadata ( + name VARCHAR(255) NOT NULL, + value VARCHAR(255) NOT NULL, + db_name VARBINARY(255) NOT NULL, + PRIMARY KEY (db_name, name) + ) ENGINE=InnoDB; +CREATE TABLE IF NOT EXISTS _vt.shard_metadata ( + name VARCHAR(255) NOT NULL, + value MEDIUMBLOB NOT NULL, + db_name VARBINARY(255) NOT NULL, + PRIMARY KEY (db_name, name) + ) ENGINE=InnoDB; + +# Admin user with all privileges. +CREATE USER 'vt_dba'@'localhost'; +GRANT ALL ON *.* TO 'vt_dba'@'localhost'; +GRANT GRANT OPTION ON *.* TO 'vt_dba'@'localhost'; + +# User for app traffic, with global read-write access. +CREATE USER 'vt_app'@'localhost'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_app'@'localhost'; + +# User for app debug traffic, with global read access. +CREATE USER 'vt_appdebug'@'localhost'; +GRANT SELECT, SHOW DATABASES, PROCESS ON *.* TO 'vt_appdebug'@'localhost'; + +# User for administrative operations that need to be executed as non-SUPER. +# Same permissions as vt_app here. +CREATE USER 'vt_allprivs'@'localhost'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_allprivs'@'localhost'; + +# User for slave replication connections. +CREATE USER 'vt_repl'@'%'; +GRANT REPLICATION SLAVE ON *.* TO 'vt_repl'@'%'; + +# User for Vitess VReplication (base vstreamers and vplayer). +CREATE USER 'vt_filtered'@'localhost'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_filtered'@'localhost'; + +# User for general MySQL monitoring. +CREATE USER 'vt_monitoring'@'localhost'; +GRANT SELECT, PROCESS, SUPER, REPLICATION CLIENT, RELOAD + ON *.* TO 'vt_monitoring'@'localhost'; +GRANT SELECT, UPDATE, DELETE, DROP + ON performance_schema.* TO 'vt_monitoring'@'localhost'; + +# User for Orchestrator (https://github.com/openark/orchestrator). +CREATE USER 'orc_client_user'@'%' IDENTIFIED BY 'orc_client_user_password'; +GRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD + ON *.* TO 'orc_client_user'@'%'; +GRANT SELECT + ON _vt.* TO 'orc_client_user'@'%'; + +FLUSH PRIVILEGES; + +RESET SLAVE ALL; +RESET MASTER; + +# add custom sql here diff --git a/config/mycnf/mysql57.cnf b/config/mycnf/mysql57.cnf index 7a8c45a187c..669ae39428e 100644 --- a/config/mycnf/mysql57.cnf +++ b/config/mycnf/mysql57.cnf @@ -32,3 +32,8 @@ plugin-load = rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisy rpl_semi_sync_master_timeout = 1000000000000000000 rpl_semi_sync_master_wait_no_slave = 1 +# In order to protect against any errand GTIDs we will start mysql instance +# as super-read-only mode. +super-read-only + + diff --git a/config/mycnf/mysql80.cnf b/config/mycnf/mysql80.cnf index 39fab576533..5c2d6c69212 100644 --- a/config/mycnf/mysql80.cnf +++ b/config/mycnf/mysql80.cnf @@ -28,3 +28,6 @@ plugin-load = rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisy loose_rpl_semi_sync_master_timeout = 1000000000000000000 loose_rpl_semi_sync_master_wait_no_slave = 1 +# In order to protect against any errand GTIDs we will start mysql instance +# as super-read-only mode. +super-read-only \ No newline at end of file diff --git a/go/cmd/vtbackup/vtbackup.go b/go/cmd/vtbackup/vtbackup.go index eba97493170..8796b42da2c 100644 --- a/go/cmd/vtbackup/vtbackup.go +++ b/go/cmd/vtbackup/vtbackup.go @@ -302,6 +302,11 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back if err := mysqld.ResetReplication(ctx); err != nil { return fmt.Errorf("can't reset replication: %v", err) } + // We need to switch off super-read-only before we create database. + _ = mysqld.SetSuperReadOnly(false) + defer func() { + _ = mysqld.SetSuperReadOnly(true) + }() cmd := mysqlctl.GenerateInitialBinlogEntry() if err := mysqld.ExecuteSuperQueryList(ctx, []string{cmd}); err != nil { return err @@ -390,6 +395,8 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back return err } + log.Infof("takeBackup: primary position is: %s", primaryPos.String()) + // Remember the time when we fetched the primary position, not when we caught // up to it, so the timestamp on our backup is honest (assuming we make it // to the goal position). From b5caff3311db22dd31dab9a15ddb3007baa17aaa Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 14 Nov 2022 22:21:05 -0800 Subject: [PATCH 02/65] add new init sql file for unit test Signed-off-by: Rameez Sajwani --- config/init_unit_test_db.sql | 91 ++++++++++++++++++++++++++++++++++++ go/vt/vttest/environment.go | 2 +- 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 config/init_unit_test_db.sql diff --git a/config/init_unit_test_db.sql b/config/init_unit_test_db.sql new file mode 100644 index 00000000000..d29cac6b076 --- /dev/null +++ b/config/init_unit_test_db.sql @@ -0,0 +1,91 @@ +# This file is executed immediately after mysql_install_db, +# to initialize a fresh data directory. + +############################################################################### +# WARNING: This sql is *NOT* safe for production use, +# as it contains default well-known users and passwords. +# Care should be taken to change these users and passwords +# for production. +############################################################################### + +############################################################################### +# Equivalent of mysql_secure_installation +############################################################################### +# We need to ensure that super_read_only is disabled so that we can execute +# these commands. Note that disabling it does NOT disable read_only. +# We save the current value so that we only re-enable it at the end if it was +# enabled before. +SET @original_super_read_only=IF(@@global.super_read_only=1, 'ON', 'OFF'); +SET GLOBAL super_read_only='OFF'; + +# Changes during the init db should not make it to the binlog. +# They could potentially create errant transactions on replicas. +SET sql_log_bin = 0; +# Remove anonymous users. +DELETE FROM mysql.user WHERE User = ''; + +# Disable remote root access (only allow UNIX socket). +DELETE FROM mysql.user WHERE User = 'root' AND Host != 'localhost'; + +# Remove test database. +DROP DATABASE IF EXISTS test; + +############################################################################### +# Vitess defaults +############################################################################### + +# Admin user with all privileges. +CREATE USER 'vt_dba'@'localhost'; +GRANT ALL ON *.* TO 'vt_dba'@'localhost'; +GRANT GRANT OPTION ON *.* TO 'vt_dba'@'localhost'; + +# User for app traffic, with global read-write access. +CREATE USER 'vt_app'@'localhost'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_app'@'localhost'; + +# User for app debug traffic, with global read access. +CREATE USER 'vt_appdebug'@'localhost'; +GRANT SELECT, SHOW DATABASES, PROCESS ON *.* TO 'vt_appdebug'@'localhost'; + +# User for administrative operations that need to be executed as non-SUPER. +# Same permissions as vt_app here. +CREATE USER 'vt_allprivs'@'localhost'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_allprivs'@'localhost'; + +# User for slave replication connections. +CREATE USER 'vt_repl'@'%'; +GRANT REPLICATION SLAVE ON *.* TO 'vt_repl'@'%'; + +# User for Vitess VReplication (base vstreamers and vplayer). +CREATE USER 'vt_filtered'@'localhost'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_filtered'@'localhost'; + +# User for general MySQL monitoring. +CREATE USER 'vt_monitoring'@'localhost'; +GRANT SELECT, PROCESS, SUPER, REPLICATION CLIENT, RELOAD + ON *.* TO 'vt_monitoring'@'localhost'; +GRANT SELECT, UPDATE, DELETE, DROP + ON performance_schema.* TO 'vt_monitoring'@'localhost'; + +# User for Orchestrator (https://github.com/openark/orchestrator). +CREATE USER 'orc_client_user'@'%' IDENTIFIED BY 'orc_client_user_password'; +GRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD + ON *.* TO 'orc_client_user'@'%'; +FLUSH PRIVILEGES; + +RESET SLAVE ALL; +RESET MASTER; + +# add custom sql here diff --git a/go/vt/vttest/environment.go b/go/vt/vttest/environment.go index f58d9d48944..4bde83c7f5f 100644 --- a/go/vt/vttest/environment.go +++ b/go/vt/vttest/environment.go @@ -146,7 +146,7 @@ func (env *LocalTestEnv) BinaryPath(binary string) string { func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLManager, error) { return &Mysqlctl{ Binary: env.BinaryPath("mysqlctl"), - InitFile: path.Join(os.Getenv("VTROOT"), "config/init_db.sql"), + InitFile: path.Join(os.Getenv("VTROOT"), "config/init_unit_test_db.sql"), Directory: env.TmpPath, Port: env.PortForProtocol("mysql", ""), MyCnf: append(env.DefaultMyCnf, mycnf...), From d64bab0f347c6c8cac8c97d52fc00121d570cdc6 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Tue, 22 Nov 2022 12:34:38 -0800 Subject: [PATCH 03/65] enable super-readonly by default Signed-off-by: Rameez Sajwani --- go/vt/vttablet/tabletmanager/rpc_replication.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index f952a2f5cb8..2a60f3a059c 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -38,7 +38,7 @@ import ( topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) -var setSuperReadOnly bool +var setSuperReadOnly = true var disableReplicationManager bool func registerReplicationFlags(fs *pflag.FlagSet) { From c7bcd527a2342e2e9817cf3f141b1af4db9a5061 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 23 Nov 2022 22:03:56 -0800 Subject: [PATCH 04/65] Fixing some arrangement for super-read-only Signed-off-by: Rameez Sajwani --- go/vt/dbconfigs/dbconfigs.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/dbconfigs/dbconfigs.go b/go/vt/dbconfigs/dbconfigs.go index 371892144d3..cfcbf19ad9e 100644 --- a/go/vt/dbconfigs/dbconfigs.go +++ b/go/vt/dbconfigs/dbconfigs.go @@ -216,12 +216,12 @@ func (dbcfgs *DBConfigs) AppDebugWithDB() Connector { return dbcfgs.makeParams(&dbcfgs.appdebugParams, true) } -// AllPrivsConnector returns connection parameters for appdebug with no dbname set. +// AllPrivsConnector returns connection parameters for all privileges with no dbname set. func (dbcfgs *DBConfigs) AllPrivsConnector() Connector { return dbcfgs.makeParams(&dbcfgs.allprivsParams, false) } -// AllPrivsWithDB returns connection parameters for appdebug with dbname set. +// AllPrivsWithDB returns connection parameters for all privileges with dbname set. func (dbcfgs *DBConfigs) AllPrivsWithDB() Connector { return dbcfgs.makeParams(&dbcfgs.allprivsParams, true) } From 978d02cfa447ee8aef393473b3a82c3ff247dc8f Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 30 Nov 2022 17:38:07 -0800 Subject: [PATCH 05/65] Fix end to end tests Signed-off-by: Rameez Sajwani --- .../backup/vtctlbackup/backup_utils.go | 9 +++++---- .../tabletmanager/tablet_health_test.go | 3 --- go/vt/vttablet/tabletmanager/tm_init.go | 18 +++++++++--------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 69334b51637..1b68e08dbec 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -118,8 +118,12 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) + // Since password update is DML we need to insert it before we disable + // super-read-only therefore doing the split below. + splitString := strings.Split(sql, "# add custom sql here") + firstPart := splitString[0] + cluster.GetPasswordUpdateSQL(localCluster) + sql = firstPart + splitString[1] newInitDBFile = path.Join(localCluster.TmpDirectory, "init_db_with_passwords.sql") - sql = sql + cluster.GetPasswordUpdateSQL(localCluster) err = os.WriteFile(newInitDBFile, []byte(sql), 0666) if err != nil { return 1, err @@ -207,9 +211,6 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp } for _, tablet := range []cluster.Vttablet{*primary, *replica1} { - if err := tablet.VttabletProcess.CreateDB(keyspaceName); err != nil { - return 1, err - } if err := tablet.VttabletProcess.Setup(); err != nil { return 1, err } diff --git a/go/test/endtoend/tabletmanager/tablet_health_test.go b/go/test/endtoend/tabletmanager/tablet_health_test.go index 19359406607..aaa5719cdcd 100644 --- a/go/test/endtoend/tabletmanager/tablet_health_test.go +++ b/go/test/endtoend/tabletmanager/tablet_health_test.go @@ -103,9 +103,6 @@ func TestHealthCheck(t *testing.T) { defer replicaConn.Close() - // Create database in mysql - utils.Exec(t, replicaConn, fmt.Sprintf("create database vt_%s", keyspaceName)) - // start vttablet process, should be in SERVING state as we already have a primary err = clusterInstance.StartVttablet(rTablet, "SERVING", false, cell, keyspaceName, hostname, shardName) require.NoError(t, err) diff --git a/go/vt/vttablet/tabletmanager/tm_init.go b/go/vt/vttablet/tabletmanager/tm_init.go index 297b1c5687a..7db04e48293 100644 --- a/go/vt/vttablet/tabletmanager/tm_init.go +++ b/go/vt/vttablet/tabletmanager/tm_init.go @@ -76,14 +76,13 @@ const denyListQueryList string = "DenyListQueryRules" var ( // The following flags initialize the tablet record. - tabletHostname string - initKeyspace string - initShard string - initTabletType string - initDbNameOverride string - skipBuildInfoTags = "/.*/" - initTags flagutil.StringMapValue - + tabletHostname string + initKeyspace string + initShard string + initTabletType string + initDbNameOverride string + skipBuildInfoTags = "/.*/" + initTags flagutil.StringMapValue initPopulateMetadata bool initTimeout = 1 * time.Minute ) @@ -96,7 +95,6 @@ func registerInitFlags(fs *pflag.FlagSet) { fs.StringVar(&initDbNameOverride, "init_db_name_override", initDbNameOverride, "(init parameter) override the name of the db used by vttablet. Without this flag, the db name defaults to vt_") fs.StringVar(&skipBuildInfoTags, "vttablet_skip_buildinfo_tags", skipBuildInfoTags, "comma-separated list of buildinfo tags to skip from merging with --init_tags. each tag is either an exact match or a regular expression of the form '/regexp/'.") fs.Var(&initTags, "init_tags", "(init parameter) comma separated list of key:value pairs used to tag the tablet") - fs.BoolVar(&initPopulateMetadata, "init_populate_metadata", initPopulateMetadata, "(init parameter) populate metadata tables even if restore_from_backup is disabled. If restore_from_backup is enabled, metadata tables are always populated regardless of this flag.") fs.MarkDeprecated("init_populate_metadata", "this flag is no longer being used and will be removed in future versions") fs.DurationVar(&initTimeout, "init_timeout", initTimeout, "(init parameter) timeout to use for the init phase.") @@ -408,11 +406,13 @@ func (tm *TabletManager) Start(tablet *topodatapb.Tablet, healthCheckInterval ti // of updating the tablet state and initializing replication. return nil } + log.Infof("calling initializeReplication") // We should be re-read the tablet from tabletManager and use the type specified there. // We shouldn't use the base tablet type directly, since the type could have changed to PRIMARY // earlier in tm.checkPrimaryShip code. _, err = tm.initializeReplication(ctx, tm.Tablet().Type) tm.tmState.Open() + log.Infof("TabletManager End") return err } From 6a9c93d4e0cf56e2feefd2d7b606214aa117876f Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 5 Dec 2022 22:54:30 -0800 Subject: [PATCH 06/65] fix rpc_replication issue Signed-off-by: Rameez Sajwani --- go/test/endtoend/backup/vtctlbackup/backup_utils.go | 2 -- go/vt/vttablet/tabletserver/schema/engine.go | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 1b68e08dbec..4b99d397361 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -675,8 +675,6 @@ func restartPrimaryAndReplica(t *testing.T) { for _, tablet := range []*cluster.Vttablet{primary, replica1} { err := localCluster.VtctlclientProcess.InitTablet(tablet, cell, keyspaceName, hostname, shardName) require.Nil(t, err) - err = tablet.VttabletProcess.CreateDB(keyspaceName) - require.Nil(t, err) err = tablet.VttabletProcess.Setup() require.Nil(t, err) } diff --git a/go/vt/vttablet/tabletserver/schema/engine.go b/go/vt/vttablet/tabletserver/schema/engine.go index 0f3907685ac..75f8576b59c 100644 --- a/go/vt/vttablet/tabletserver/schema/engine.go +++ b/go/vt/vttablet/tabletserver/schema/engine.go @@ -170,6 +170,7 @@ func (se *Engine) EnsureConnectionAndDB(tabletType topodatapb.TabletType) error // We use AllPrivs since syncSidecarDB() might need to upgrade the schema conn, err := dbconnpool.NewDBConnection(ctx, se.env.Config().DB.AllPrivsWithDB()) if err == nil { + log.Infof("inside EnsureConnectionAndDB with TabletType %v...", tabletType) se.dbCreationFailed = false // upgrade _vt if required, for a tablet with an existing database if tabletType == topodatapb.TabletType_PRIMARY { From 8b14beda7015f79a7f81d9d9bdf1872d55c41d02 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 7 Dec 2022 15:27:01 -0800 Subject: [PATCH 07/65] Fixing backup tests Signed-off-by: Rameez Sajwani --- go/cmd/vtbackup/vtbackup.go | 1 + go/mysql/query.go | 92 +++++++++++++++++++ .../backup/pitr/backup_mysqlctld_pitr_test.go | 6 +- .../backup/vtbackup/backup_only_test.go | 2 +- go/test/endtoend/backup/vtbackup/main_test.go | 24 ++++- go/test/endtoend/cluster/vtbackup_process.go | 1 - go/test/endtoend/cluster/vttablet_process.go | 66 +++++++++++++ go/vt/mysqlctl/builtinbackupengine.go | 1 - go/vt/mysqlctl/mysqld.go | 19 ++++ 9 files changed, 202 insertions(+), 10 deletions(-) diff --git a/go/cmd/vtbackup/vtbackup.go b/go/cmd/vtbackup/vtbackup.go index 8796b42da2c..f68149c1db9 100644 --- a/go/cmd/vtbackup/vtbackup.go +++ b/go/cmd/vtbackup/vtbackup.go @@ -294,6 +294,7 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back } // In initial_backup mode, just take a backup of this empty database. if initialBackup { + log.Infof("inside initialBackup creating reparent journal.") // Take a backup of this empty DB without restoring anything. // First, initialize it the way InitShardPrimary would, so this backup // produces a result that can be used to skip InitShardPrimary entirely. diff --git a/go/mysql/query.go b/go/mysql/query.go index 0107e7606bc..185656cda6f 100644 --- a/go/mysql/query.go +++ b/go/mysql/query.go @@ -328,6 +328,98 @@ func (c *Conn) ExecuteFetchMulti(query string, maxrows int, wantfields bool) (re return res, more, err } +// ExecuteFetchWithReadOnlyHandling should be used if you are executing a write query +// on a tablet that may NOT be a primary and you want to execute it regardless of +// tablet type. This function will temporarily make the mysql instance read-write and +// re-enable read-only mode after the query is executed if needed. +func (c *Conn) ExecuteFetchWithReadOnlyHandling(query string, maxrows int, wantfields bool) (result *sqltypes.Result, err error) { + // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ + turnSuperReadOnly := false + if !c.IsMariaDB() { + if err := c.WriteComQuery("SELECT @@global.super_read_only"); err != nil { + return nil, err + } + res, _, _, err := c.ReadQueryResult(1, false) + if err == nil && len(res.Rows) == 1 { + sro := res.Rows[0][0].ToString() + if sro == "1" || sro == "ON" { + turnSuperReadOnly = true + if _, err = c.ExecuteFetch("SET GLOBAL super_read_only='OFF'", 1, false); err != nil { + return nil, err + } + } + } + } + + result, _, err = c.ExecuteFetchMulti(query, maxrows, wantfields) + if turnSuperReadOnly { + if _, err := c.ExecuteFetch("SET GLOBAL super_read_only='ON'", 1, false); err != nil { + return nil, err + } + } + return result, err +} + +// ExecuteUnSetSuperReadOnly tries to set super-read-only to false only if it is currently enable +func (c *Conn) ExecuteUnSetSuperReadOnly() (result *sqltypes.Result, err error) { + // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ + if !c.IsMariaDB() { + if err := c.WriteComQuery("SELECT @@global.super_read_only"); err != nil { + return nil, err + } + res, _, _, err := c.ReadQueryResult(1, false) + if err == nil && len(res.Rows) == 1 { + sro := res.Rows[0][0].ToString() + if sro == "1" || sro == "ON" { + if err = c.WriteComQuery("SET GLOBAL super_read_only='OFF'"); err != nil { + return nil, err + } + } + } + } + + return result, err +} + +// ExecuteSetSuperReadOnly tries to set super-read-only to true only if it is currently disable +func (c *Conn) ExecuteSetSuperReadOnly() (result *sqltypes.Result, err error) { + // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ + if !c.IsMariaDB() { + if err := c.WriteComQuery("SELECT @@global.super_read_only"); err != nil { + return nil, err + } + res, _, _, err := c.ReadQueryResult(1, false) + if err == nil && len(res.Rows) == 1 { + sro := res.Rows[0][0].ToString() + if sro == "0" || sro == "OFF" { + if err = c.WriteComQuery("SET GLOBAL super_read_only='ON'"); err != nil { + return nil, err + } + } + } + } + + return result, err +} + +// ExecuteUnSetReadOnly tries to set read-only to false only if it is currently enable +func (c *Conn) ExecuteUnSetReadOnly() (result *sqltypes.Result, err error) { + if err := c.WriteComQuery("SELECT @@global.read_only"); err != nil { + return nil, err + } + res, _, _, err := c.ReadQueryResult(1, false) + if err == nil && len(res.Rows) == 1 { + sro := res.Rows[0][0].ToString() + if sro == "1" || sro == "ON" { + if err = c.WriteComQuery("SET GLOBAL read_only='OFF'"); err != nil { + return nil, err + } + } + } + + return result, err +} + // ExecuteFetchWithWarningCount is for fetching results and a warning count // Note: In a future iteration this should be abolished and merged into the // ExecuteFetch API. diff --git a/go/test/endtoend/backup/pitr/backup_mysqlctld_pitr_test.go b/go/test/endtoend/backup/pitr/backup_mysqlctld_pitr_test.go index f93dfa475b6..dfb869b4de2 100644 --- a/go/test/endtoend/backup/pitr/backup_mysqlctld_pitr_test.go +++ b/go/test/endtoend/backup/pitr/backup_mysqlctld_pitr_test.go @@ -138,9 +138,9 @@ func TestIncrementalBackupMysqlctld(t *testing.T) { if tc.writeBeforeBackup { backup.InsertRowOnPrimary(t, "") } - // we wait for 1 second because backups ar ewritten to a directory named after the current timestamp, - // in 1 second resolution. We want to aoid two backups that have the same pathname. Realistically this - // is only ever a problem in this endtoend test, not in production. + // we wait for 1 second because backups are written to a directory named after the current timestamp, + // in 1 second resolution. We want to avoid two backups that have the same pathname. Realistically this + // is only ever a problem in this end-to-end test, not in production. // Also, we gie the replica a chance to catch up. time.Sleep(1100 * time.Millisecond) waitForReplica(t) diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index 3730a1fa586..9b877e94459 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -302,7 +302,7 @@ func tearDown(t *testing.T, initMysql bool) { _, err = tablet.VttabletProcess.QueryTablet(disableSemiSyncCommands, keyspaceName, true) require.Nil(t, err) for _, db := range []string{"_vt", "vt_insert_test"} { - _, err = tablet.VttabletProcess.QueryTablet(fmt.Sprintf("drop database if exists %s", db), keyspaceName, true) + _, err = tablet.VttabletProcess.QueryTabletWithSuperReadOnlyHandling(fmt.Sprintf("drop database if exists %s", db), keyspaceName, true) require.Nil(t, err) } } diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index a5fc9d23c8b..c1833e53cd4 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -22,6 +22,7 @@ import ( "os" "os/exec" "path" + "strings" "testing" "vitess.io/vitess/go/test/endtoend/cluster" @@ -89,8 +90,12 @@ func TestMain(m *testing.M) { dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) + // Since password update is DML we need to insert it before we disable + // super-read-only therefore doing the split below. + spilltedString := strings.Split(sql, "# add custom sql here") + firstPart := spilltedString[0] + cluster.GetPasswordUpdateSQL(localCluster) + sql = firstPart + spilltedString[1] newInitDBFile = path.Join(localCluster.TmpDirectory, "init_db_with_passwords.sql") - sql = sql + cluster.GetPasswordUpdateSQL(localCluster) err = os.WriteFile(newInitDBFile, []byte(sql), 0666) if err != nil { return 1, err @@ -126,13 +131,24 @@ func TestMain(m *testing.M) { return 1, err } } - + vtTabletVersion, err := cluster.GetMajorVersion("vttablet") + if err != nil { + return 1, err + } + log.Infof("cluster.VtTabletMajorVersion: %d", vtTabletVersion) + if vtTabletVersion <= 15 { + for _, tablet := range []cluster.Vttablet{*primary, *replica1, *replica2} { + if err := tablet.VttabletProcess.UnsetSuperReadOnly(""); err != nil { + return 1, err + } + } + } // Create database - for _, tablet := range []cluster.Vttablet{*primary, *replica1} { + /*for _, tablet := range []cluster.Vttablet{*primary, *replica1} { if err := tablet.VttabletProcess.CreateDB(keyspaceName); err != nil { return 1, err } - } + }*/ return m.Run(), nil }() diff --git a/go/test/endtoend/cluster/vtbackup_process.go b/go/test/endtoend/cluster/vtbackup_process.go index b7beed67936..be75026bf0d 100644 --- a/go/test/endtoend/cluster/vtbackup_process.go +++ b/go/test/endtoend/cluster/vtbackup_process.go @@ -54,7 +54,6 @@ type VtbackupProcess struct { // Setup starts vtbackup process with required arguements func (vtbackup *VtbackupProcess) Setup() (err error) { - vtbackup.proc = exec.Command( vtbackup.Binary, "--topo_implementation", vtbackup.CommonArg.TopoImplementation, diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index 68dfddb831e..9e469f6d1dc 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -628,3 +628,69 @@ func VttabletProcessInstance(port, grpcPort, tabletUID int, cell, shard, keyspac return vttablet } + +// UnsetSuperReadOnly switch-off super-read-only flag in db +func (vttablet *VttabletProcess) UnsetSuperReadOnly(dbname string) error { + conn, err := vttablet.defaultConn("") + if err != nil { + log.Infof("error in getting connection object %s", err) + return err + } + defer conn.Close() + + _, err = conn.ExecuteUnSetSuperReadOnly() + return err +} + +// UnsetReadOnly switch-off read-only flag in db +func (vttablet *VttabletProcess) UnsetReadOnly(dbname string) error { + conn, err := vttablet.defaultConn("") + if err != nil { + log.Infof("error in getting connection object %s", err) + return err + } + defer conn.Close() + + _, err = conn.ExecuteUnSetReadOnly() + return err +} + +// QueryTabletWithSuperReadOnlyHandling lets you execute a query in this tablet while disabling super-read-only and get the result +// It will enable super-read-only once its done executing the query. +func (vttablet *VttabletProcess) QueryTabletWithSuperReadOnlyHandling(query string, keyspace string, useDb bool) (*sqltypes.Result, error) { + if !useDb { + keyspace = "" + } + dbParams := NewConnParams(vttablet.DbPort, vttablet.DbPassword, path.Join(vttablet.Directory, "mysql.sock"), keyspace) + conn, err := vttablet.conn(&dbParams) + if err != nil { + return nil, err + } + defer conn.Close() + return executeQueryWithSuperReadOnlyHandling(conn, query) +} + +// executeQuery will retry the query up to 10 times with a small sleep in between each try. +// This allows the tests to be more robust in the face of transient failures. It disables +// super-read-only during query execution. +func executeQueryWithSuperReadOnlyHandling(dbConn *mysql.Conn, query string) (*sqltypes.Result, error) { + var ( + err error + result *sqltypes.Result + ) + retries := 10 + retryDelay := 1 * time.Second + for i := 0; i < retries; i++ { + if i > 0 { + // We only audit from 2nd attempt and onwards, otherwise this is just too verbose. + log.Infof("Executing query %s (attempt %d of %d)", query, (i + 1), retries) + } + result, err = dbConn.ExecuteFetchWithReadOnlyHandling(query, 10000, true) + if err == nil { + break + } + time.Sleep(retryDelay) + } + + return result, err +} diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index 56fabc1dd99..caea82b6c31 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -739,7 +739,6 @@ func (be *BuiltinBackupEngine) executeRestoreFullBackup(ctx context.Context, par // The underlying mysql database is expected to be up and running. func (be *BuiltinBackupEngine) executeRestoreIncrementalBackup(ctx context.Context, params RestoreParams, bh backupstorage.BackupHandle, bm builtinBackupManifest) error { params.Logger.Infof("Restoring incremental backup to position: %v", bm.Position) - createdDir, err := be.restoreFiles(context.Background(), params, bh, bm) defer os.RemoveAll(createdDir) mysqld, ok := params.Mysqld.(*Mysqld) diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index f91d880bc5f..7dcbca3ac84 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -1251,10 +1251,26 @@ func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTID args := []string{ "--defaults-extra-file=" + cnf, } + + // We disable super_read_only, in case it is in the default MySQL startup + // parameters. We do it blindly, since this will fail on MariaDB, which doesn't + // have super_read_only This is safe, since we're restarting MySQL after the restore anyway + log.Infof("Restore: disabling super_read_only") + if err := mysqld.SetSuperReadOnly(false); err != nil { + if strings.Contains(err.Error(), strconv.Itoa(mysql.ERUnknownSystemVariable)) { + log.Warningf("Restore: server does not know about super_read_only, continuing anyway...") + } else { + log.Errorf("Restore: unexpected error while trying to set super_read_only: %v", err) + return err + } + } + mysqlCmd = exec.Command(name, args...) mysqlCmd.Dir = dir mysqlCmd.Env = env mysqlCmd.Stdin = pipe // piped from mysqlbinlog + mysqlCmd.Stdout = os.Stderr + mysqlCmd.Stderr = os.Stderr } // Run both processes, piped: if err := mysqlbinlogCmd.Start(); err != nil { @@ -1268,6 +1284,9 @@ func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTID return err } if err := mysqlCmd.Wait(); err != nil { + println(mysqlCmd.Stdout) + println(mysqlCmd.Stderr) + println(mysqlCmd.Stdin) return err } return nil From 014115affbfc8d27d31eed41e49e813531ca49fc Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Fri, 9 Dec 2022 13:57:32 -0800 Subject: [PATCH 08/65] fixing error with spacing in init sql file Signed-off-by: Rameez Sajwani --- config/init_db.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/init_db.sql b/config/init_db.sql index 954241e3f94..76a9b27f6b0 100644 --- a/config/init_db.sql +++ b/config/init_db.sql @@ -87,4 +87,4 @@ RESET MASTER; # add custom sql here # We need to set super_read_only back to what it was before -SET GLOBAL super_read_only=IFNULL(@original_super_read_only, 'OFF'); \ No newline at end of file +SET GLOBAL super_read_only=IFNULL(@original_super_read_only, 'OFF'); From c4eb7f03aca8a3297bd06c412d1ccf85e53e617f Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Fri, 9 Dec 2022 16:15:48 -0800 Subject: [PATCH 09/65] vtgate end to end fixes Signed-off-by: Rameez Sajwani --- .../recovery/unshardedrecovery/recovery.go | 16 ++++++++++------ go/test/endtoend/utils/mysql.go | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/go/test/endtoend/recovery/unshardedrecovery/recovery.go b/go/test/endtoend/recovery/unshardedrecovery/recovery.go index f9824c23b2f..beca7f8b481 100644 --- a/go/test/endtoend/recovery/unshardedrecovery/recovery.go +++ b/go/test/endtoend/recovery/unshardedrecovery/recovery.go @@ -23,6 +23,7 @@ import ( "os" "os/exec" "path" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -94,13 +95,16 @@ func TestMainImpl(m *testing.M) { dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) - newInitDBFile = path.Join(localCluster.TmpDirectory, "init_db_with_passwords.sql") - sql = sql + cluster.GetPasswordUpdateSQL(localCluster) + // Since password update is DML we need to insert it before we disable + // super-read-only therefore doing the split below. + splitString := strings.Split(sql, "# add custom sql here") + firstPart := splitString[0] + cluster.GetPasswordUpdateSQL(localCluster) + // https://github.com/vitessio/vitess/issues/8315 - oldAlterTableMode := ` -SET GLOBAL old_alter_table = ON; -` - sql = sql + oldAlterTableMode + oldAlterTableMode := `SET GLOBAL old_alter_table = ON;` + sql = firstPart + oldAlterTableMode + sql = sql + splitString[1] + newInitDBFile = path.Join(localCluster.TmpDirectory, "init_db_with_passwords.sql") os.WriteFile(newInitDBFile, []byte(sql), 0666) extraArgs := []string{"--db-credentials-file", dbCredentialFile} diff --git a/go/test/endtoend/utils/mysql.go b/go/test/endtoend/utils/mysql.go index 5bbf75ffb71..89a7856ead6 100644 --- a/go/test/endtoend/utils/mysql.go +++ b/go/test/endtoend/utils/mysql.go @@ -114,7 +114,7 @@ func createInitSQLFile(mysqlDir, ksName string) (string, error) { return "", err } defer f.Close() - + _, _ = f.WriteString("SET GLOBAL super_read_only='OFF';") _, err = f.WriteString(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s;", ksName)) if err != nil { return "", err From 8374e14a00c08d430ad41dab0aeafed6dc817889 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Fri, 9 Dec 2022 22:35:49 -0800 Subject: [PATCH 10/65] some more test fixes Signed-off-by: Rameez Sajwani --- config/mycnf/mysql57.cnf | 1 - config/mycnf/mysql80.cnf | 3 +- go/mysql/fakesqldb/server.go | 28 +++++++++++++++++++ .../recovery/pitr/shardedpitr_test.go | 5 ++-- go/test/endtoend/vault/vault_test.go | 10 +++++-- .../vtorc/readtopologyinstance/main_test.go | 2 +- go/test/endtoend/vtorc/utils/utils.go | 22 +++++++++++++-- 7 files changed, 62 insertions(+), 9 deletions(-) diff --git a/config/mycnf/mysql57.cnf b/config/mycnf/mysql57.cnf index 669ae39428e..d1ca819ebd4 100644 --- a/config/mycnf/mysql57.cnf +++ b/config/mycnf/mysql57.cnf @@ -36,4 +36,3 @@ rpl_semi_sync_master_wait_no_slave = 1 # as super-read-only mode. super-read-only - diff --git a/config/mycnf/mysql80.cnf b/config/mycnf/mysql80.cnf index 5c2d6c69212..449fb465da2 100644 --- a/config/mycnf/mysql80.cnf +++ b/config/mycnf/mysql80.cnf @@ -30,4 +30,5 @@ loose_rpl_semi_sync_master_wait_no_slave = 1 # In order to protect against any errand GTIDs we will start mysql instance # as super-read-only mode. -super-read-only \ No newline at end of file +super-read-only + diff --git a/go/mysql/fakesqldb/server.go b/go/mysql/fakesqldb/server.go index 5b00b2c2e01..04e82d27d71 100644 --- a/go/mysql/fakesqldb/server.go +++ b/go/mysql/fakesqldb/server.go @@ -198,6 +198,34 @@ func New(t testing.TB) *DB { return db } +// NewWithExpectedQueries returns DB with all the queries expected at the time of vttablet Initialization +func NewWithExpectedQueries(t testing.TB) *DB { + newDb := New(t) + newDb.AddQuery("CREATE DATABASE IF NOT EXISTS _vt", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQuery("create database if not exists `vt_test_keyspace`", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQuery("SET GLOBAL super_read_only='OFF'", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQuery("SET GLOBAL read_only='OFF'", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQuery("SET @@session.sql_log_bin = 0", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQuery("SET GLOBAL super_read_only='ON'", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("CREATE TABLE IF NOT EXISTS _vt.local_metadata.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("ALTER TABLE _vt.vreplication .*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("ALTER TABLE _vt.local_metadata.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("CREATE TABLE IF NOT EXISTS _vt.shard_metadata.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("ALTER TABLE _vt.shard_metadata.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQuery("DROP TABLE IF EXISTS _vt.blp_checkpoint", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("CREATE TABLE IF NOT EXISTS _vt.vreplication.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("create table if not exists _vt.resharding_journal.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("create table if not exists _vt.copy_state.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("CREATE TABLE IF NOT EXISTS _vt.schema_migrations.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("SELECT.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("ALTER TABLE _vt.schema_migrations.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("CREATE TABLE IF NOT EXISTS _vt.reparent_journal.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("CREATE TABLE if not exists _vt.schemacopy.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQueryPattern("ALTER TABLE _vt.reparent_journal.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + newDb.AddQuery("USE `vt_test_keyspace`", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) + return newDb +} + // Name returns the name of the DB. func (db *DB) Name() string { db.mu.Lock() diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go index c7013557549..4450dab3584 100644 --- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go +++ b/go/test/endtoend/recovery/pitr/shardedpitr_test.go @@ -442,14 +442,15 @@ func initializeCluster(t *testing.T) { fmt.Sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s';", mysqlUserName, mysqlPassword), fmt.Sprintf("GRANT ALL ON *.* TO '%s'@'%%';", mysqlUserName), fmt.Sprintf("GRANT GRANT OPTION ON *.* TO '%s'@'%%';", mysqlUserName), - fmt.Sprintf("create database %s;", "vt_ks"), + //fmt.Sprintf("create database %s;", "vt_ks"), "FLUSH PRIVILEGES;", } for _, shard := range clusterInstance.Keyspaces[0].Shards { for _, tablet := range shard.Vttablets { + for _, query := range queryCmds { - _, err = tablet.VttabletProcess.QueryTablet(query, keyspace.Name, false) + _, err = tablet.VttabletProcess.QueryTabletWithSuperReadOnlyHandling(query, keyspace.Name, false) require.NoError(t, err) } diff --git a/go/test/endtoend/vault/vault_test.go b/go/test/endtoend/vault/vault_test.go index da66f3a52e3..5ffd356a0f6 100644 --- a/go/test/endtoend/vault/vault_test.go +++ b/go/test/endtoend/vault/vault_test.go @@ -267,6 +267,12 @@ func initializeClusterLate(t *testing.T) { require.NoError(t, err) } + for _, tablet := range shard.Vttablets { + // remove super read-only from vttablet + tablet.VttabletProcess.UnsetReadOnly("") + } + + // TODO: Try moving this after InitPrimary. May be thats a better place. for _, tablet := range []*cluster.Vttablet{primary, replica} { for _, user := range mysqlUsers { query := fmt.Sprintf("ALTER USER '%s'@'%s' IDENTIFIED BY '%s';", user, hostname, mysqlPassword) @@ -279,9 +285,9 @@ func initializeClusterLate(t *testing.T) { require.NoError(t, err) } } - query := fmt.Sprintf("create database %s;", dbName) + /*query := fmt.Sprintf("create database %s;", dbName) _, err = tablet.VttabletProcess.QueryTablet(query, keyspace.Name, false) - require.NoError(t, err) + require.NoError(t, err)*/ err = tablet.VttabletProcess.Setup() require.NoError(t, err) diff --git a/go/test/endtoend/vtorc/readtopologyinstance/main_test.go b/go/test/endtoend/vtorc/readtopologyinstance/main_test.go index 5d8c129dbbd..872a1fcdc87 100644 --- a/go/test/endtoend/vtorc/readtopologyinstance/main_test.go +++ b/go/test/endtoend/vtorc/readtopologyinstance/main_test.go @@ -105,7 +105,7 @@ func TestReadTopologyInstanceBufferable(t *testing.T) { assert.Equal(t, primaryInstance.ReplicationSQLThreadState, inst.ReplicationThreadStateNoThread) // insert an errant GTID in the replica - _, err = utils.RunSQL(t, "insert into vt_insert_test(id, msg) values (10173, 'test 178342')", replica, "vt_ks") + _, err = utils.RunSQLWithSuperReadOnly(t, "insert into vt_insert_test(id, msg) values (10173, 'test 178342')", replica, "vt_ks", true) require.NoError(t, err) replicaInstance, err := inst.ReadTopologyInstanceBufferable(&inst.InstanceKey{ diff --git a/go/test/endtoend/vtorc/utils/utils.go b/go/test/endtoend/vtorc/utils/utils.go index d4f23c0de70..6f210fc1ccd 100644 --- a/go/test/endtoend/vtorc/utils/utils.go +++ b/go/test/endtoend/vtorc/utils/utils.go @@ -582,11 +582,29 @@ func RunSQL(t *testing.T, sql string, tablet *cluster.Vttablet, db string) (*sql defer conn.Close() // RunSQL - return execute(t, conn, sql) + return RunSQLWithSuperReadOnly(t, sql, tablet, db, false) } -func execute(t *testing.T, conn *mysql.Conn, query string) (*sqltypes.Result, error) { +// RunSQLWithSuperReadOnly is used to run a SQL statement on the given tablet with super read only set to true or false +func RunSQLWithSuperReadOnly(t *testing.T, sql string, tablet *cluster.Vttablet, db string, withSuperReadOnly bool) (*sqltypes.Result, error) { + // Get Connection + tabletParams := getMysqlConnParam(tablet, db) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + conn, err := mysql.Connect(ctx, &tabletParams) + require.Nil(t, err) + defer conn.Close() + + // RunSQL + return execute(t, conn, sql, withSuperReadOnly) +} + +func execute(t *testing.T, conn *mysql.Conn, query string, withSuperReadOnly bool) (*sqltypes.Result, error) { t.Helper() + if withSuperReadOnly { + return conn.ExecuteFetchWithReadOnlyHandling(query, 1000, true) + } + return conn.ExecuteFetch(query, 1000, true) } From a52c1bcd22500fc7d5d1ce64323d8ae6c1301427 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 12 Dec 2022 11:31:29 -0800 Subject: [PATCH 11/65] fixing flag tests and more Signed-off-by: Rameez Sajwani --- config/init_testserver_db.sql | 94 ++++++++++++++++++++ config/mycnf/test-suite.cnf | 4 + go/cmd/vtcombo/main.go | 2 +- go/flags/endtoend/vttablet.txt | 2 +- go/mysql/query.go | 4 +- go/test/endtoend/cluster/vttablet_process.go | 2 +- go/test/endtoend/vtorc/utils/utils.go | 2 +- go/vt/vtcombo/tablet_map.go | 4 + go/vt/vttablet/endtoend/main_test.go | 3 +- go/vt/vttest/environment.go | 2 +- go/vt/vttest/local_cluster.go | 44 ++++++++- 11 files changed, 153 insertions(+), 10 deletions(-) create mode 100644 config/init_testserver_db.sql diff --git a/config/init_testserver_db.sql b/config/init_testserver_db.sql new file mode 100644 index 00000000000..7dfe6f95bd8 --- /dev/null +++ b/config/init_testserver_db.sql @@ -0,0 +1,94 @@ +# This file is executed immediately after mysql_install_db, +# to initialize a fresh data directory. + +############################################################################### +# WARNING: This sql is *NOT* safe for production use, +# as it contains default well-known users and passwords. +# Care should be taken to change these users and passwords +# for production. +############################################################################### + +############################################################################### +# Equivalent of mysql_secure_installation +############################################################################### +# We need to ensure that super_read_only is disabled so that we can execute +# these commands. Note that disabling it does NOT disable read_only. +# We save the current value so that we only re-enable it at the end if it was +# enabled before. +SET @original_super_read_only=IF(@@global.super_read_only=1, 'ON', 'OFF'); +SET GLOBAL super_read_only='OFF'; + +# Changes during the init db should not make it to the binlog. +# They could potentially create errant transactions on replicas. +SET sql_log_bin = 0; +# Remove anonymous users. +DELETE FROM mysql.user WHERE User = ''; + +# Disable remote root access (only allow UNIX socket). +DELETE FROM mysql.user WHERE User = 'root' AND Host != 'localhost'; + +# Remove test database. +DROP DATABASE IF EXISTS test; + +############################################################################### +# Vitess defaults +############################################################################### + +# Admin user with all privileges. +CREATE USER 'vt_dba'@'localhost'; +GRANT ALL ON *.* TO 'vt_dba'@'localhost'; +GRANT GRANT OPTION ON *.* TO 'vt_dba'@'localhost'; + +# User for app traffic, with global read-write access. +CREATE USER 'vt_app'@'localhost'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_app'@'localhost'; + +# User for app debug traffic, with global read access. +CREATE USER 'vt_appdebug'@'localhost'; +GRANT SELECT, SHOW DATABASES, PROCESS ON *.* TO 'vt_appdebug'@'localhost'; + +# User for administrative operations that need to be executed as non-SUPER. +# Same permissions as vt_app here. +CREATE USER 'vt_allprivs'@'localhost'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_allprivs'@'localhost'; + +# User for slave replication connections. +CREATE USER 'vt_repl'@'%'; +GRANT REPLICATION SLAVE ON *.* TO 'vt_repl'@'%'; + +# User for Vitess VReplication (base vstreamers and vplayer). +CREATE USER 'vt_filtered'@'localhost'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_filtered'@'localhost'; + +# User for general MySQL monitoring. +CREATE USER 'vt_monitoring'@'localhost'; +GRANT SELECT, PROCESS, SUPER, REPLICATION CLIENT, RELOAD + ON *.* TO 'vt_monitoring'@'localhost'; +GRANT SELECT, UPDATE, DELETE, DROP + ON performance_schema.* TO 'vt_monitoring'@'localhost'; + +# User for Orchestrator (https://github.com/openark/orchestrator). +CREATE USER 'orc_client_user'@'%' IDENTIFIED BY 'orc_client_user_password'; +GRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD + ON *.* TO 'orc_client_user'@'%'; +FLUSH PRIVILEGES; + +RESET SLAVE ALL; +RESET MASTER; + +# add custom sql here + +# We need to set super_read_only back to what it was before +SET GLOBAL super_read_only=IFNULL(@original_super_read_only, 'OFF'); \ No newline at end of file diff --git a/config/mycnf/test-suite.cnf b/config/mycnf/test-suite.cnf index e57368a41db..3327a5c8842 100644 --- a/config/mycnf/test-suite.cnf +++ b/config/mycnf/test-suite.cnf @@ -23,3 +23,7 @@ sql_mode = STRICT_TRANS_TABLES # set a short heartbeat interval in order to detect failures quickly slave_net_timeout = 4 + +# In order to protect against any errand GTIDs we will start mysql instance +# as super-read-only mode. +super-read-only diff --git a/go/cmd/vtcombo/main.go b/go/cmd/vtcombo/main.go index 52cf2f0c8d2..91399418a8b 100644 --- a/go/cmd/vtcombo/main.go +++ b/go/cmd/vtcombo/main.go @@ -190,7 +190,7 @@ func main() { servenv.Init() tabletenv.Init() - + //time.Sleep(10 * time.Second) mysqld := &vtcomboMysqld{} var cnf *mysqlctl.Mycnf if *startMysql { diff --git a/go/flags/endtoend/vttablet.txt b/go/flags/endtoend/vttablet.txt index ed8c0f434a6..2e7676a0f07 100644 --- a/go/flags/endtoend/vttablet.txt +++ b/go/flags/endtoend/vttablet.txt @@ -347,7 +347,7 @@ Usage of vttablet: --tx_throttler_config string The configuration of the transaction throttler as a text formatted throttlerdata.Configuration protocol buffer message (default "target_replication_lag_sec: 2\nmax_replication_lag_sec: 10\ninitial_rate: 100\nmax_increase: 1\nemergency_decrease: 0.5\nmin_duration_between_increases_sec: 40\nmax_duration_between_increases_sec: 62\nmin_duration_between_decreases_sec: 20\nspread_backlog_across_sec: 20\nage_bad_rate_after_sec: 180\nbad_rate_increase: 0.1\nmax_rate_approach_threshold: 0.9\n") --tx_throttler_healthcheck_cells strings A comma-separated list of cells. Only tabletservers running in these cells will be monitored for replication lag by the transaction throttler. --unhealthy_threshold duration replication lag after which a replica is considered unhealthy (default 2h0m0s) - --use_super_read_only Set super_read_only flag when performing planned failover. + --use_super_read_only Set super_read_only flag when performing planned failover. (default true) --v Level log level for V logs -v, --version print binary version --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging diff --git a/go/mysql/query.go b/go/mysql/query.go index 185656cda6f..69c21b2429a 100644 --- a/go/mysql/query.go +++ b/go/mysql/query.go @@ -328,11 +328,11 @@ func (c *Conn) ExecuteFetchMulti(query string, maxrows int, wantfields bool) (re return res, more, err } -// ExecuteFetchWithReadOnlyHandling should be used if you are executing a write query +// ExecuteFetchWithSuperReadOnlyHandling should be used if you are executing a write query // on a tablet that may NOT be a primary and you want to execute it regardless of // tablet type. This function will temporarily make the mysql instance read-write and // re-enable read-only mode after the query is executed if needed. -func (c *Conn) ExecuteFetchWithReadOnlyHandling(query string, maxrows int, wantfields bool) (result *sqltypes.Result, err error) { +func (c *Conn) ExecuteFetchWithSuperReadOnlyHandling(query string, maxrows int, wantfields bool) (result *sqltypes.Result, err error) { // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ turnSuperReadOnly := false if !c.IsMariaDB() { diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index 9e469f6d1dc..cf2453c8a59 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -685,7 +685,7 @@ func executeQueryWithSuperReadOnlyHandling(dbConn *mysql.Conn, query string) (*s // We only audit from 2nd attempt and onwards, otherwise this is just too verbose. log.Infof("Executing query %s (attempt %d of %d)", query, (i + 1), retries) } - result, err = dbConn.ExecuteFetchWithReadOnlyHandling(query, 10000, true) + result, err = dbConn.ExecuteFetchWithSuperReadOnlyHandling(query, 10000, true) if err == nil { break } diff --git a/go/test/endtoend/vtorc/utils/utils.go b/go/test/endtoend/vtorc/utils/utils.go index 6f210fc1ccd..9bb75cb723b 100644 --- a/go/test/endtoend/vtorc/utils/utils.go +++ b/go/test/endtoend/vtorc/utils/utils.go @@ -602,7 +602,7 @@ func RunSQLWithSuperReadOnly(t *testing.T, sql string, tablet *cluster.Vttablet, func execute(t *testing.T, conn *mysql.Conn, query string, withSuperReadOnly bool) (*sqltypes.Result, error) { t.Helper() if withSuperReadOnly { - return conn.ExecuteFetchWithReadOnlyHandling(query, 1000, true) + return conn.ExecuteFetchWithSuperReadOnlyHandling(query, 1000, true) } return conn.ExecuteFetch(query, 1000, true) diff --git a/go/vt/vtcombo/tablet_map.go b/go/vt/vtcombo/tablet_map.go index 767217b442b..fc41a45560c 100644 --- a/go/vt/vtcombo/tablet_map.go +++ b/go/vt/vtcombo/tablet_map.go @@ -126,6 +126,10 @@ func CreateTablet( if err := tm.ChangeType(ctx, topodatapb.TabletType_PRIMARY /* semi-sync */, false); err != nil { return fmt.Errorf("TabletExternallyReparented failed on primary %v: %v", topoproto.TabletAliasString(alias), err) } + log.Infof("setting super read only to false for test purpose %v", topoproto.TabletAliasString(alias)) + if err := tm.MysqlDaemon.SetReadOnly(false); err != nil { + return fmt.Errorf("failed on set super read only on %v: %v", topoproto.TabletAliasString(alias), err) + } } controller.AddStatusHeader() controller.AddStatusPart() diff --git a/go/vt/vttablet/endtoend/main_test.go b/go/vt/vttablet/endtoend/main_test.go index a809e7e42ae..4d9f5002635 100644 --- a/go/vt/vttablet/endtoend/main_test.go +++ b/go/vt/vttablet/endtoend/main_test.go @@ -75,7 +75,7 @@ func TestMain(m *testing.M) { fmt.Fprintf(os.Stderr, "could not launch mysql: %v\n", err) return 1 } - err := cluster.Execute(procSQL, "vttest") + err := cluster.ExecuteWithSuperReadOnly(procSQL, "vttest") if err != nil { fmt.Fprintf(os.Stderr, "%v", err) return 1 @@ -96,6 +96,7 @@ func TestMain(m *testing.M) { fmt.Fprintf(os.Stderr, "%v", err) return 1 } + cluster.UnsetReadOnly("") return m.Run() }() os.Exit(exitCode) diff --git a/go/vt/vttest/environment.go b/go/vt/vttest/environment.go index 4bde83c7f5f..89fd44bf434 100644 --- a/go/vt/vttest/environment.go +++ b/go/vt/vttest/environment.go @@ -146,7 +146,7 @@ func (env *LocalTestEnv) BinaryPath(binary string) string { func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLManager, error) { return &Mysqlctl{ Binary: env.BinaryPath("mysqlctl"), - InitFile: path.Join(os.Getenv("VTROOT"), "config/init_unit_test_db.sql"), + InitFile: path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql"), Directory: env.TmpPath, Port: env.PortForProtocol("mysql", ""), MyCnf: append(env.DefaultMyCnf, mycnf...), diff --git a/go/vt/vttest/local_cluster.go b/go/vt/vttest/local_cluster.go index 3d954de860d..f36f202ea06 100644 --- a/go/vt/vttest/local_cluster.go +++ b/go/vt/vttest/local_cluster.go @@ -483,7 +483,7 @@ func (db *LocalCluster) loadSchema(shouldRunDatabaseMigrations bool) error { } for _, dbname := range db.shardNames(kpb) { - if err := db.Execute(cmds, dbname); err != nil { + if err := db.ExecuteWithSuperReadOnly(cmds, dbname); err != nil { return err } } @@ -533,7 +533,7 @@ func (db *LocalCluster) createDatabases() error { sql = append(sql, fmt.Sprintf("create database `%s`", dbname)) } } - return db.Execute(sql, "") + return db.ExecuteWithSuperReadOnly(sql, "") } // Execute runs a series of SQL statements on the MySQL instance backing @@ -564,6 +564,34 @@ func (db *LocalCluster) Execute(sql []string, dbname string) error { return err } +// ExecuteWithSuperReadOnly runs a series of SQL statements with super-read-only permission +// on the MySQL instance backing this local cluster. This is provided for debug/introspection purposes; +// normal cluster access should be performed through the Vitess GRPC interface. +func (db *LocalCluster) ExecuteWithSuperReadOnly(sql []string, dbname string) error { + params := db.mysql.Params(dbname) + conn, err := mysql.Connect(context.Background(), ¶ms) + if err != nil { + return err + } + defer conn.Close() + + _, err = conn.ExecuteFetch("START TRANSACTION", 0, false) + if err != nil { + return err + } + + for _, cmd := range sql { + log.Infof("Execute(%s): \"%s\"", dbname, cmd) + _, err := conn.ExecuteFetchWithSuperReadOnlyHandling(cmd, 0, false) + if err != nil { + return err + } + } + + _, err = conn.ExecuteFetch("COMMIT", 0, false) + return err +} + // Query runs a SQL query on the MySQL instance backing this local cluster and returns // its result. This is provided for debug/introspection purposes; // normal cluster access should be performed through the Vitess GRPC interface. @@ -720,3 +748,15 @@ func LoadSQLFile(filename, sourceroot string) ([]string, error) { return sql, nil } + +func (db *LocalCluster) UnsetReadOnly(dbname string) error { + params := db.mysql.Params(dbname) + conn, err := mysql.Connect(context.Background(), ¶ms) + if err != nil { + return err + } + defer conn.Close() + + _, err = conn.ExecuteUnSetSuperReadOnly() + return err +} From eac4d6ae8168e57ce2ba57b5e27bb3394cfcf8c5 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 14 Dec 2022 12:24:28 -0800 Subject: [PATCH 12/65] fixing schema sql Signed-off-by: Rameez Sajwani --- go/mysql/collations/integration/helpers_test.go | 2 +- go/test/endtoend/cluster/cluster_process.go | 6 +++++- go/test/endtoend/cluster/vtctld_process.go | 2 ++ go/vt/sidecardb/schema/vdiff/vdiff.sql | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/go/mysql/collations/integration/helpers_test.go b/go/mysql/collations/integration/helpers_test.go index d185168d9d1..c2601421bc2 100644 --- a/go/mysql/collations/integration/helpers_test.go +++ b/go/mysql/collations/integration/helpers_test.go @@ -137,7 +137,7 @@ func verifyWeightString(t *testing.T, local collations.Collation, remote *remote } func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { - res, err := conn.ExecuteFetch(query, -1, true) + res, err := conn.ExecuteFetchWithSuperReadOnlyHandling(query, -1, true) require.NoError(t, err, "failed to execute %q: %v", query, err) return res diff --git a/go/test/endtoend/cluster/cluster_process.go b/go/test/endtoend/cluster/cluster_process.go index 712824b84dd..f653744dbdd 100644 --- a/go/test/endtoend/cluster/cluster_process.go +++ b/go/test/endtoend/cluster/cluster_process.go @@ -679,7 +679,11 @@ func NewBareCluster(cell string, hostname string) *LocalProcessCluster { // path/to/whatever exists cluster.ReusingVTDATAROOT = true } else { - _ = createDirectory(cluster.CurrentVTDATAROOT, 0700) + err = createDirectory(cluster.CurrentVTDATAROOT, 0700) + if err != nil { + fmt.Printf("err in creating file : %s", err.Error()) + log.Infof("err in creating file : %s", err.Error()) + } } _ = os.Setenv("VTDATAROOT", cluster.CurrentVTDATAROOT) log.Infof("Created cluster on %s. ReusingVTDATAROOT=%v", cluster.CurrentVTDATAROOT, cluster.ReusingVTDATAROOT) diff --git a/go/test/endtoend/cluster/vtctld_process.go b/go/test/endtoend/cluster/vtctld_process.go index 5e85f172ce1..e9ab52e67d4 100644 --- a/go/test/endtoend/cluster/vtctld_process.go +++ b/go/test/endtoend/cluster/vtctld_process.go @@ -105,6 +105,8 @@ func (vtctld *VtctldProcess) Setup(cell string, extraArgs ...string) (err error) } func createDirectory(dirName string, mode os.FileMode) error { + log.Infof("creating directory : %s", dirName) + fmt.Printf("creating directory : %s", dirName) if _, err := os.Stat(dirName); os.IsNotExist(err) { return os.Mkdir(dirName, mode) } diff --git a/go/vt/sidecardb/schema/vdiff/vdiff.sql b/go/vt/sidecardb/schema/vdiff/vdiff.sql index 24f5cf6e7ab..89252bb576e 100644 --- a/go/vt/sidecardb/schema/vdiff/vdiff.sql +++ b/go/vt/sidecardb/schema/vdiff/vdiff.sql @@ -33,4 +33,4 @@ CREATE TABLE IF NOT EXISTS _vt.vdiff UNIQUE KEY `uuid_idx` (`vdiff_uuid`), KEY `state` (`state`), KEY `ks_wf_idx` (`keyspace`(64), `workflow`(64)) -) ENGINE = InnoDB +) ENGINE = InnoDB \ No newline at end of file From c19641351bee2d1a8f761e0ba832d0a139a05f2c Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Fri, 16 Dec 2022 12:31:48 -0800 Subject: [PATCH 13/65] fixing unit tests Signed-off-by: Rameez Sajwani --- config/init_testserver_db.sql | 12 ++------ config/init_unit_test_db.sql | 9 ++---- config/mycnf/test-suite.cnf | 3 -- go/mysql/endtoend/client_test.go | 48 ++++++++++++++++---------------- go/vt/vtcombo/tablet_map.go | 4 +-- 5 files changed, 32 insertions(+), 44 deletions(-) diff --git a/config/init_testserver_db.sql b/config/init_testserver_db.sql index 7dfe6f95bd8..5eb2cd8c5b2 100644 --- a/config/init_testserver_db.sql +++ b/config/init_testserver_db.sql @@ -11,12 +11,9 @@ ############################################################################### # Equivalent of mysql_secure_installation ############################################################################### -# We need to ensure that super_read_only is disabled so that we can execute -# these commands. Note that disabling it does NOT disable read_only. -# We save the current value so that we only re-enable it at the end if it was -# enabled before. -SET @original_super_read_only=IF(@@global.super_read_only=1, 'ON', 'OFF'); -SET GLOBAL super_read_only='OFF'; +# We need to ensure that read_only is disabled so that we can execute +# these commands. +SET GLOBAL read_only='OFF'; # Changes during the init db should not make it to the binlog. # They could potentially create errant transactions on replicas. @@ -89,6 +86,3 @@ RESET SLAVE ALL; RESET MASTER; # add custom sql here - -# We need to set super_read_only back to what it was before -SET GLOBAL super_read_only=IFNULL(@original_super_read_only, 'OFF'); \ No newline at end of file diff --git a/config/init_unit_test_db.sql b/config/init_unit_test_db.sql index d29cac6b076..5eb2cd8c5b2 100644 --- a/config/init_unit_test_db.sql +++ b/config/init_unit_test_db.sql @@ -11,12 +11,9 @@ ############################################################################### # Equivalent of mysql_secure_installation ############################################################################### -# We need to ensure that super_read_only is disabled so that we can execute -# these commands. Note that disabling it does NOT disable read_only. -# We save the current value so that we only re-enable it at the end if it was -# enabled before. -SET @original_super_read_only=IF(@@global.super_read_only=1, 'ON', 'OFF'); -SET GLOBAL super_read_only='OFF'; +# We need to ensure that read_only is disabled so that we can execute +# these commands. +SET GLOBAL read_only='OFF'; # Changes during the init db should not make it to the binlog. # They could potentially create errant transactions on replicas. diff --git a/config/mycnf/test-suite.cnf b/config/mycnf/test-suite.cnf index 3327a5c8842..b288c53fc6a 100644 --- a/config/mycnf/test-suite.cnf +++ b/config/mycnf/test-suite.cnf @@ -24,6 +24,3 @@ sql_mode = STRICT_TRANS_TABLES # set a short heartbeat interval in order to detect failures quickly slave_net_timeout = 4 -# In order to protect against any errand GTIDs we will start mysql instance -# as super-read-only mode. -super-read-only diff --git a/go/mysql/endtoend/client_test.go b/go/mysql/endtoend/client_test.go index a48c9629d51..ddd5d3cd02b 100644 --- a/go/mysql/endtoend/client_test.go +++ b/go/mysql/endtoend/client_test.go @@ -51,14 +51,14 @@ func TestKill(t *testing.T) { errChan := make(chan error) go func() { - _, err = conn.ExecuteFetch("select sleep(10) from dual", 1000, false) + _, err = conn.ExecuteFetchWithSuperReadOnlyHandling("select sleep(10) from dual", 1000, false) errChan <- err close(errChan) }() // Give extra time for the query to start executing. time.Sleep(2 * time.Second) - if _, err := killConn.ExecuteFetch(fmt.Sprintf("kill %v", conn.ConnectionID), 1000, false); err != nil { + if _, err := killConn.ExecuteFetchWithSuperReadOnlyHandling(fmt.Sprintf("kill %v", conn.ConnectionID), 1000, false); err != nil { t.Fatalf("Kill(%v) failed: %v", conn.ConnectionID, err) } @@ -96,14 +96,14 @@ func TestKill2006(t *testing.T) { } defer killConn.Close() - if _, err := killConn.ExecuteFetch(fmt.Sprintf("kill %v", conn.ConnectionID), 1000, false); err != nil { + if _, err := killConn.ExecuteFetchWithSuperReadOnlyHandling(fmt.Sprintf("kill %v", conn.ConnectionID), 1000, false); err != nil { t.Fatalf("Kill(%v) failed: %v", conn.ConnectionID, err) } // Now we should get a CRServerGone. Since we are using a // unix socket, we will get a broken pipe when the server // closes the connection and we are trying to write the command. - _, err = conn.ExecuteFetch("select sleep(10) from dual", 1000, false) + _, err = conn.ExecuteFetchWithSuperReadOnlyHandling("select sleep(10) from dual", 1000, false) assertSQLError(t, err, mysql.CRServerGone, mysql.SSUnknownSQLState, "broken pipe", "select sleep(10) from dual") } @@ -116,13 +116,13 @@ func TestDupEntry(t *testing.T) { } defer conn.Close() - if _, err := conn.ExecuteFetch("create table dup_entry(id int, name int, primary key(id), unique index(name))", 0, false); err != nil { + if _, err := conn.ExecuteFetchWithSuperReadOnlyHandling("create table dup_entry(id int, name int, primary key(id), unique index(name))", 0, false); err != nil { t.Fatalf("create table failed: %v", err) } - if _, err := conn.ExecuteFetch("insert into dup_entry(id, name) values(1, 10)", 0, false); err != nil { + if _, err := conn.ExecuteFetchWithSuperReadOnlyHandling("insert into dup_entry(id, name) values(1, 10)", 0, false); err != nil { t.Fatalf("first insert failed: %v", err) } - _, err = conn.ExecuteFetch("insert into dup_entry(id, name) values(2, 10)", 0, false) + _, err = conn.ExecuteFetchWithSuperReadOnlyHandling("insert into dup_entry(id, name) values(2, 10)", 0, false) assertSQLError(t, err, mysql.ERDupEntry, mysql.SSConstraintViolation, "Duplicate entry", "insert into dup_entry(id, name) values(2, 10)") } @@ -138,17 +138,17 @@ func TestClientFoundRows(t *testing.T) { } defer conn.Close() - if _, err := conn.ExecuteFetch("create table found_rows(id int, val int, primary key(id))", 0, false); err != nil { + if _, err := conn.ExecuteFetchWithSuperReadOnlyHandling("create table found_rows(id int, val int, primary key(id))", 0, false); err != nil { t.Fatalf("create table failed: %v", err) } - if _, err := conn.ExecuteFetch("insert into found_rows(id, val) values(1, 10)", 0, false); err != nil { + if _, err := conn.ExecuteFetchWithSuperReadOnlyHandling("insert into found_rows(id, val) values(1, 10)", 0, false); err != nil { t.Fatalf("insert failed: %v", err) } - qr, err := conn.ExecuteFetch("update found_rows set val=11 where id=1", 0, false) + qr, err := conn.ExecuteFetchWithSuperReadOnlyHandling("update found_rows set val=11 where id=1", 0, false) require.NoError(t, err) assert.EqualValues(t, 1, qr.RowsAffected, "RowsAffected") - qr, err = conn.ExecuteFetch("update found_rows set val=11 where id=1", 0, false) + qr, err = conn.ExecuteFetchWithSuperReadOnlyHandling("update found_rows set val=11 where id=1", 0, false) require.NoError(t, err) assert.EqualValues(t, 1, qr.RowsAffected, "RowsAffected") } @@ -198,12 +198,12 @@ func doTestMultiResult(t *testing.T, disableClientDeprecateEOF bool) { // sends an OK packet unilaterally which is properly parsed. If not, then regardless of the // negotiated version, it can properly send the status flags. // - result, err := conn.ExecuteFetch("create table a(id int, name varchar(128), primary key(id))", 0, false) + result, err := conn.ExecuteFetchWithSuperReadOnlyHandling("create table a(id int, name varchar(128), primary key(id))", 0, false) require.NoError(t, err) assert.Zero(t, result.RowsAffected, "create table RowsAffected ") for i := 0; i < 255; i++ { - result, err := conn.ExecuteFetch(fmt.Sprintf("insert into a(id, name) values(%v, 'nice name %v')", 1000+i, i), 1000, true) + result, err := conn.ExecuteFetchWithSuperReadOnlyHandling(fmt.Sprintf("insert into a(id, name) values(%v, 'nice name %v')", 1000+i, i), 1000, true) require.NoError(t, err) assert.EqualValues(t, 1, result.RowsAffected, "insert into returned RowsAffected") } @@ -223,7 +223,7 @@ func doTestMultiResult(t *testing.T, disableClientDeprecateEOF bool) { expectFlag(t, "ReadQueryResult(2)", more, false) assert.EqualValues(t, 1, len(qr.Rows), "ReadQueryResult(1)") - _, err = conn.ExecuteFetch("drop table a", 10, true) + _, err = conn.ExecuteFetchWithSuperReadOnlyHandling("drop table a", 10, true) require.NoError(t, err) } @@ -265,7 +265,7 @@ func TestTLS(t *testing.T) { } defer conn.Close() - result, err := conn.ExecuteFetch("SHOW STATUS LIKE 'Ssl_cipher'", 10, true) + result, err := conn.ExecuteFetchWithSuperReadOnlyHandling("SHOW STATUS LIKE 'Ssl_cipher'", 10, true) require.NoError(t, err, "SHOW STATUS LIKE 'Ssl_cipher' failed: %v", err) if len(result.Rows) != 1 || result.Rows[0][0].ToString() != "Ssl_cipher" || @@ -295,15 +295,15 @@ func TestSessionTrackGTIDs(t *testing.T) { conn, err := mysql.Connect(ctx, ¶ms) require.NoError(t, err) - qr, err := conn.ExecuteFetch(`set session session_track_gtids='own_gtid'`, 1000, false) + qr, err := conn.ExecuteFetchWithSuperReadOnlyHandling(`set session session_track_gtids='own_gtid'`, 1000, false) require.NoError(t, err) require.Empty(t, qr.SessionStateChanges) - qr, err = conn.ExecuteFetch(`create table vttest.t1(id bigint primary key)`, 1000, false) + qr, err = conn.ExecuteFetchWithSuperReadOnlyHandling(`create table vttest.t1(id bigint primary key)`, 1000, false) require.NoError(t, err) require.NotEmpty(t, qr.SessionStateChanges) - qr, err = conn.ExecuteFetch(`insert into vttest.t1 values (1)`, 1000, false) + qr, err = conn.ExecuteFetchWithSuperReadOnlyHandling(`insert into vttest.t1 values (1)`, 1000, false) require.NoError(t, err) require.NotEmpty(t, qr.SessionStateChanges) } @@ -317,7 +317,7 @@ func TestCachingSha2Password(t *testing.T) { expectNoError(t, err) defer conn.Close() - qr, err := conn.ExecuteFetch(`select true from information_schema.PLUGINS where PLUGIN_NAME='caching_sha2_password' and PLUGIN_STATUS='ACTIVE'`, 1, false) + qr, err := conn.ExecuteFetchWithSuperReadOnlyHandling(`select true from information_schema.PLUGINS where PLUGIN_NAME='caching_sha2_password' and PLUGIN_STATUS='ACTIVE'`, 1, false) assert.NoError(t, err, "select true from information_schema.PLUGINS failed: %v", err) if len(qr.Rows) != 1 { @@ -325,7 +325,7 @@ func TestCachingSha2Password(t *testing.T) { } // create a user using caching_sha2_password password - if _, err = conn.ExecuteFetch(`create user 'sha2user'@'localhost' identified with caching_sha2_password by 'password';`, 0, false); err != nil { + if _, err = conn.ExecuteFetchWithSuperReadOnlyHandling(`create user 'sha2user'@'localhost' identified with caching_sha2_password by 'password';`, 0, false); err != nil { t.Fatalf("Create user with caching_sha2_password failed: %v", err) } conn.Close() @@ -338,7 +338,7 @@ func TestCachingSha2Password(t *testing.T) { expectNoError(t, err) defer conn.Close() - if qr, err = conn.ExecuteFetch(`select user()`, 1, true); err != nil { + if qr, err = conn.ExecuteFetchWithSuperReadOnlyHandling(`select user()`, 1, true); err != nil { t.Fatalf("select user() failed: %v", err) } @@ -359,7 +359,7 @@ func TestClientInfo(t *testing.T) { defer conn.Close() // This is the simplest query that would return some textual data in the 'info' field - result, err := conn.ExecuteFetch(`PREPARE stmt1 FROM 'SELECT 1 = 1'`, -1, true) + result, err := conn.ExecuteFetchWithSuperReadOnlyHandling(`PREPARE stmt1 FROM 'SELECT 1 = 1'`, -1, true) require.NoError(t, err, "select failed: %v", err) require.Equal(t, infoPrepared, result.Info, "expected result.Info=%q, got=%q", infoPrepared, result.Info) } @@ -374,7 +374,7 @@ func TestBaseShowTables(t *testing.T) { sql := conn.BaseShowTables() // An improved test would make assertions about the results. This test just // makes sure there aren't any errors. - _, err = conn.ExecuteFetch(sql, -1, true) + _, err = conn.ExecuteFetchWithSuperReadOnlyHandling(sql, -1, true) require.NoError(t, err) } @@ -389,6 +389,6 @@ func TestBaseShowTablesFilePos(t *testing.T) { sql := conn.BaseShowTables() // An improved test would make assertions about the results. This test just // makes sure there aren't any errors. - _, err = conn.ExecuteFetch(sql, -1, true) + _, err = conn.ExecuteFetchWithSuperReadOnlyHandling(sql, -1, true) require.NoError(t, err) } diff --git a/go/vt/vtcombo/tablet_map.go b/go/vt/vtcombo/tablet_map.go index fc41a45560c..dd27d381d1a 100644 --- a/go/vt/vtcombo/tablet_map.go +++ b/go/vt/vtcombo/tablet_map.go @@ -126,10 +126,10 @@ func CreateTablet( if err := tm.ChangeType(ctx, topodatapb.TabletType_PRIMARY /* semi-sync */, false); err != nil { return fmt.Errorf("TabletExternallyReparented failed on primary %v: %v", topoproto.TabletAliasString(alias), err) } - log.Infof("setting super read only to false for test purpose %v", topoproto.TabletAliasString(alias)) + /*log.Infof("setting super read only to false for test purpose %v", topoproto.TabletAliasString(alias)) if err := tm.MysqlDaemon.SetReadOnly(false); err != nil { return fmt.Errorf("failed on set super read only on %v: %v", topoproto.TabletAliasString(alias), err) - } + }*/ } controller.AddStatusHeader() controller.AddStatusPart() From ce52ba45db38dd1208b9a9ff89623ccce6935c2e Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Sat, 17 Dec 2022 14:11:08 -0800 Subject: [PATCH 14/65] fixing vttest server test cases Signed-off-by: Rameez Sajwani --- config/mycnf/test-suite.cnf | 2 +- go/mysql/endtoend/client_test.go | 48 ++++++++++++++++---------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/config/mycnf/test-suite.cnf b/config/mycnf/test-suite.cnf index b288c53fc6a..d23efa54a30 100644 --- a/config/mycnf/test-suite.cnf +++ b/config/mycnf/test-suite.cnf @@ -23,4 +23,4 @@ sql_mode = STRICT_TRANS_TABLES # set a short heartbeat interval in order to detect failures quickly slave_net_timeout = 4 - +super-read-only = false diff --git a/go/mysql/endtoend/client_test.go b/go/mysql/endtoend/client_test.go index ddd5d3cd02b..a48c9629d51 100644 --- a/go/mysql/endtoend/client_test.go +++ b/go/mysql/endtoend/client_test.go @@ -51,14 +51,14 @@ func TestKill(t *testing.T) { errChan := make(chan error) go func() { - _, err = conn.ExecuteFetchWithSuperReadOnlyHandling("select sleep(10) from dual", 1000, false) + _, err = conn.ExecuteFetch("select sleep(10) from dual", 1000, false) errChan <- err close(errChan) }() // Give extra time for the query to start executing. time.Sleep(2 * time.Second) - if _, err := killConn.ExecuteFetchWithSuperReadOnlyHandling(fmt.Sprintf("kill %v", conn.ConnectionID), 1000, false); err != nil { + if _, err := killConn.ExecuteFetch(fmt.Sprintf("kill %v", conn.ConnectionID), 1000, false); err != nil { t.Fatalf("Kill(%v) failed: %v", conn.ConnectionID, err) } @@ -96,14 +96,14 @@ func TestKill2006(t *testing.T) { } defer killConn.Close() - if _, err := killConn.ExecuteFetchWithSuperReadOnlyHandling(fmt.Sprintf("kill %v", conn.ConnectionID), 1000, false); err != nil { + if _, err := killConn.ExecuteFetch(fmt.Sprintf("kill %v", conn.ConnectionID), 1000, false); err != nil { t.Fatalf("Kill(%v) failed: %v", conn.ConnectionID, err) } // Now we should get a CRServerGone. Since we are using a // unix socket, we will get a broken pipe when the server // closes the connection and we are trying to write the command. - _, err = conn.ExecuteFetchWithSuperReadOnlyHandling("select sleep(10) from dual", 1000, false) + _, err = conn.ExecuteFetch("select sleep(10) from dual", 1000, false) assertSQLError(t, err, mysql.CRServerGone, mysql.SSUnknownSQLState, "broken pipe", "select sleep(10) from dual") } @@ -116,13 +116,13 @@ func TestDupEntry(t *testing.T) { } defer conn.Close() - if _, err := conn.ExecuteFetchWithSuperReadOnlyHandling("create table dup_entry(id int, name int, primary key(id), unique index(name))", 0, false); err != nil { + if _, err := conn.ExecuteFetch("create table dup_entry(id int, name int, primary key(id), unique index(name))", 0, false); err != nil { t.Fatalf("create table failed: %v", err) } - if _, err := conn.ExecuteFetchWithSuperReadOnlyHandling("insert into dup_entry(id, name) values(1, 10)", 0, false); err != nil { + if _, err := conn.ExecuteFetch("insert into dup_entry(id, name) values(1, 10)", 0, false); err != nil { t.Fatalf("first insert failed: %v", err) } - _, err = conn.ExecuteFetchWithSuperReadOnlyHandling("insert into dup_entry(id, name) values(2, 10)", 0, false) + _, err = conn.ExecuteFetch("insert into dup_entry(id, name) values(2, 10)", 0, false) assertSQLError(t, err, mysql.ERDupEntry, mysql.SSConstraintViolation, "Duplicate entry", "insert into dup_entry(id, name) values(2, 10)") } @@ -138,17 +138,17 @@ func TestClientFoundRows(t *testing.T) { } defer conn.Close() - if _, err := conn.ExecuteFetchWithSuperReadOnlyHandling("create table found_rows(id int, val int, primary key(id))", 0, false); err != nil { + if _, err := conn.ExecuteFetch("create table found_rows(id int, val int, primary key(id))", 0, false); err != nil { t.Fatalf("create table failed: %v", err) } - if _, err := conn.ExecuteFetchWithSuperReadOnlyHandling("insert into found_rows(id, val) values(1, 10)", 0, false); err != nil { + if _, err := conn.ExecuteFetch("insert into found_rows(id, val) values(1, 10)", 0, false); err != nil { t.Fatalf("insert failed: %v", err) } - qr, err := conn.ExecuteFetchWithSuperReadOnlyHandling("update found_rows set val=11 where id=1", 0, false) + qr, err := conn.ExecuteFetch("update found_rows set val=11 where id=1", 0, false) require.NoError(t, err) assert.EqualValues(t, 1, qr.RowsAffected, "RowsAffected") - qr, err = conn.ExecuteFetchWithSuperReadOnlyHandling("update found_rows set val=11 where id=1", 0, false) + qr, err = conn.ExecuteFetch("update found_rows set val=11 where id=1", 0, false) require.NoError(t, err) assert.EqualValues(t, 1, qr.RowsAffected, "RowsAffected") } @@ -198,12 +198,12 @@ func doTestMultiResult(t *testing.T, disableClientDeprecateEOF bool) { // sends an OK packet unilaterally which is properly parsed. If not, then regardless of the // negotiated version, it can properly send the status flags. // - result, err := conn.ExecuteFetchWithSuperReadOnlyHandling("create table a(id int, name varchar(128), primary key(id))", 0, false) + result, err := conn.ExecuteFetch("create table a(id int, name varchar(128), primary key(id))", 0, false) require.NoError(t, err) assert.Zero(t, result.RowsAffected, "create table RowsAffected ") for i := 0; i < 255; i++ { - result, err := conn.ExecuteFetchWithSuperReadOnlyHandling(fmt.Sprintf("insert into a(id, name) values(%v, 'nice name %v')", 1000+i, i), 1000, true) + result, err := conn.ExecuteFetch(fmt.Sprintf("insert into a(id, name) values(%v, 'nice name %v')", 1000+i, i), 1000, true) require.NoError(t, err) assert.EqualValues(t, 1, result.RowsAffected, "insert into returned RowsAffected") } @@ -223,7 +223,7 @@ func doTestMultiResult(t *testing.T, disableClientDeprecateEOF bool) { expectFlag(t, "ReadQueryResult(2)", more, false) assert.EqualValues(t, 1, len(qr.Rows), "ReadQueryResult(1)") - _, err = conn.ExecuteFetchWithSuperReadOnlyHandling("drop table a", 10, true) + _, err = conn.ExecuteFetch("drop table a", 10, true) require.NoError(t, err) } @@ -265,7 +265,7 @@ func TestTLS(t *testing.T) { } defer conn.Close() - result, err := conn.ExecuteFetchWithSuperReadOnlyHandling("SHOW STATUS LIKE 'Ssl_cipher'", 10, true) + result, err := conn.ExecuteFetch("SHOW STATUS LIKE 'Ssl_cipher'", 10, true) require.NoError(t, err, "SHOW STATUS LIKE 'Ssl_cipher' failed: %v", err) if len(result.Rows) != 1 || result.Rows[0][0].ToString() != "Ssl_cipher" || @@ -295,15 +295,15 @@ func TestSessionTrackGTIDs(t *testing.T) { conn, err := mysql.Connect(ctx, ¶ms) require.NoError(t, err) - qr, err := conn.ExecuteFetchWithSuperReadOnlyHandling(`set session session_track_gtids='own_gtid'`, 1000, false) + qr, err := conn.ExecuteFetch(`set session session_track_gtids='own_gtid'`, 1000, false) require.NoError(t, err) require.Empty(t, qr.SessionStateChanges) - qr, err = conn.ExecuteFetchWithSuperReadOnlyHandling(`create table vttest.t1(id bigint primary key)`, 1000, false) + qr, err = conn.ExecuteFetch(`create table vttest.t1(id bigint primary key)`, 1000, false) require.NoError(t, err) require.NotEmpty(t, qr.SessionStateChanges) - qr, err = conn.ExecuteFetchWithSuperReadOnlyHandling(`insert into vttest.t1 values (1)`, 1000, false) + qr, err = conn.ExecuteFetch(`insert into vttest.t1 values (1)`, 1000, false) require.NoError(t, err) require.NotEmpty(t, qr.SessionStateChanges) } @@ -317,7 +317,7 @@ func TestCachingSha2Password(t *testing.T) { expectNoError(t, err) defer conn.Close() - qr, err := conn.ExecuteFetchWithSuperReadOnlyHandling(`select true from information_schema.PLUGINS where PLUGIN_NAME='caching_sha2_password' and PLUGIN_STATUS='ACTIVE'`, 1, false) + qr, err := conn.ExecuteFetch(`select true from information_schema.PLUGINS where PLUGIN_NAME='caching_sha2_password' and PLUGIN_STATUS='ACTIVE'`, 1, false) assert.NoError(t, err, "select true from information_schema.PLUGINS failed: %v", err) if len(qr.Rows) != 1 { @@ -325,7 +325,7 @@ func TestCachingSha2Password(t *testing.T) { } // create a user using caching_sha2_password password - if _, err = conn.ExecuteFetchWithSuperReadOnlyHandling(`create user 'sha2user'@'localhost' identified with caching_sha2_password by 'password';`, 0, false); err != nil { + if _, err = conn.ExecuteFetch(`create user 'sha2user'@'localhost' identified with caching_sha2_password by 'password';`, 0, false); err != nil { t.Fatalf("Create user with caching_sha2_password failed: %v", err) } conn.Close() @@ -338,7 +338,7 @@ func TestCachingSha2Password(t *testing.T) { expectNoError(t, err) defer conn.Close() - if qr, err = conn.ExecuteFetchWithSuperReadOnlyHandling(`select user()`, 1, true); err != nil { + if qr, err = conn.ExecuteFetch(`select user()`, 1, true); err != nil { t.Fatalf("select user() failed: %v", err) } @@ -359,7 +359,7 @@ func TestClientInfo(t *testing.T) { defer conn.Close() // This is the simplest query that would return some textual data in the 'info' field - result, err := conn.ExecuteFetchWithSuperReadOnlyHandling(`PREPARE stmt1 FROM 'SELECT 1 = 1'`, -1, true) + result, err := conn.ExecuteFetch(`PREPARE stmt1 FROM 'SELECT 1 = 1'`, -1, true) require.NoError(t, err, "select failed: %v", err) require.Equal(t, infoPrepared, result.Info, "expected result.Info=%q, got=%q", infoPrepared, result.Info) } @@ -374,7 +374,7 @@ func TestBaseShowTables(t *testing.T) { sql := conn.BaseShowTables() // An improved test would make assertions about the results. This test just // makes sure there aren't any errors. - _, err = conn.ExecuteFetchWithSuperReadOnlyHandling(sql, -1, true) + _, err = conn.ExecuteFetch(sql, -1, true) require.NoError(t, err) } @@ -389,6 +389,6 @@ func TestBaseShowTablesFilePos(t *testing.T) { sql := conn.BaseShowTables() // An improved test would make assertions about the results. This test just // makes sure there aren't any errors. - _, err = conn.ExecuteFetchWithSuperReadOnlyHandling(sql, -1, true) + _, err = conn.ExecuteFetch(sql, -1, true) require.NoError(t, err) } From cc6cf01fd13e9016c4daca09bc581f62bff6efd3 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 21 Dec 2022 11:35:52 -0800 Subject: [PATCH 15/65] fixing more downgrad upgrade test Signed-off-by: Rameez Sajwani --- ...owngrade_test_backups_e2e_next_release.yml | 12 ++++--- .../upgrade_downgrade_test_backups_manual.yml | 8 +++-- ...grade_test_backups_manual_next_release.yml | 8 +++-- ...e_downgrade_test_query_serving_queries.yml | 4 ++- ...est_query_serving_queries_next_release.yml | 4 ++- ...de_downgrade_test_query_serving_schema.yml | 4 ++- ...test_query_serving_schema_next_release.yml | 4 ++- ...e_downgrade_test_reparent_new_vttablet.yml | 4 ++- ...e_downgrade_test_reparent_old_vttablet.yml | 4 ++- .../backup/vtbackup/backup_only_test.go | 32 +++++++++++++++++-- go/test/endtoend/backup/vtbackup/main_test.go | 6 ---- 11 files changed, 67 insertions(+), 23 deletions(-) diff --git a/.github/workflows/upgrade_downgrade_test_backups_e2e_next_release.yml b/.github/workflows/upgrade_downgrade_test_backups_e2e_next_release.yml index 29add46604e..54ee5457f40 100644 --- a/.github/workflows/upgrade_downgrade_test_backups_e2e_next_release.yml +++ b/.github/workflows/upgrade_downgrade_test_backups_e2e_next_release.yml @@ -164,8 +164,10 @@ jobs: run: | source build.env - rm -f $PWD/bin/vttablet + rm -f $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vttablet --version # Run test with VTTablet at version N+1 and VTBackup at version N @@ -184,9 +186,11 @@ jobs: run: | source build.env - rm -f $PWD/bin/vtbackup $PWD/bin/vttablet - cp /tmp/vitess-build-current/bin/vtbackup $PWD/bin/vtbackup - cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + rm -f $PWD/bin/vtbackup $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld + cp /tmp/vitess-build-other/bin/vtbackup $PWD/bin/vtbackup + cp /tmp/vitess-build-current/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-current/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-current/bin/mysqlctld $PWD/bin/mysqlctld vtbackup --version vttablet --version diff --git a/.github/workflows/upgrade_downgrade_test_backups_manual.yml b/.github/workflows/upgrade_downgrade_test_backups_manual.yml index 2e2490b53b8..4aafdc7d7ad 100644 --- a/.github/workflows/upgrade_downgrade_test_backups_manual.yml +++ b/.github/workflows/upgrade_downgrade_test_backups_manual.yml @@ -234,8 +234,10 @@ jobs: run: | source build.env - rm -f $PWD/bin/vttablet + rm -f $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vttablet --version # Starting the tablets again, they will automatically start restoring the last backup. @@ -290,8 +292,10 @@ jobs: run: | source build.env - rm -f $PWD/bin/vttablet + rm -f $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-current/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-current/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-current/bin/mysqlctld $PWD/bin/mysqlctld vttablet --version # Starting the tablets again and restoring the previous backup. diff --git a/.github/workflows/upgrade_downgrade_test_backups_manual_next_release.yml b/.github/workflows/upgrade_downgrade_test_backups_manual_next_release.yml index f58dff29f84..50f493afe2a 100644 --- a/.github/workflows/upgrade_downgrade_test_backups_manual_next_release.yml +++ b/.github/workflows/upgrade_downgrade_test_backups_manual_next_release.yml @@ -237,8 +237,10 @@ jobs: run: | source build.env - rm -f $PWD/bin/vttablet + rm -f $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vttablet --version # Starting the tablets again, they will automatically start restoring the last backup. @@ -293,8 +295,10 @@ jobs: run: | source build.env - rm -f $PWD/bin/vttablet + rm -f $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-current/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-current/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-current/bin/mysqlctld $PWD/bin/mysqlctld vttablet --version # Starting the tablets again and restoring the next backup. diff --git a/.github/workflows/upgrade_downgrade_test_query_serving_queries.yml b/.github/workflows/upgrade_downgrade_test_query_serving_queries.yml index c0ca258c1db..82071eda28d 100644 --- a/.github/workflows/upgrade_downgrade_test_query_serving_queries.yml +++ b/.github/workflows/upgrade_downgrade_test_query_serving_queries.yml @@ -209,9 +209,11 @@ jobs: run: | source build.env - rm -f $PWD/bin/vtgate $PWD/bin/vttablet + rm -f $PWD/bin/vtgate $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-current/bin/vtgate $PWD/bin/vtgate cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vtgate --version vttablet --version diff --git a/.github/workflows/upgrade_downgrade_test_query_serving_queries_next_release.yml b/.github/workflows/upgrade_downgrade_test_query_serving_queries_next_release.yml index ca75c2fbf6d..0c6bf84f896 100644 --- a/.github/workflows/upgrade_downgrade_test_query_serving_queries_next_release.yml +++ b/.github/workflows/upgrade_downgrade_test_query_serving_queries_next_release.yml @@ -212,9 +212,11 @@ jobs: run: | source build.env - rm -f $PWD/bin/vtgate $PWD/bin/vttablet + rm -f $PWD/bin/vtgate $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-current/bin/vtgate $PWD/bin/vtgate cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vtgate --version vttablet --version diff --git a/.github/workflows/upgrade_downgrade_test_query_serving_schema.yml b/.github/workflows/upgrade_downgrade_test_query_serving_schema.yml index 116a211cfe1..a309d1fc99a 100644 --- a/.github/workflows/upgrade_downgrade_test_query_serving_schema.yml +++ b/.github/workflows/upgrade_downgrade_test_query_serving_schema.yml @@ -209,9 +209,11 @@ jobs: run: | source build.env - rm -f $PWD/bin/vtgate $PWD/bin/vttablet + rm -f $PWD/bin/vtgate $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-current/bin/vtgate $PWD/bin/vtgate cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vtgate --version vttablet --version diff --git a/.github/workflows/upgrade_downgrade_test_query_serving_schema_next_release.yml b/.github/workflows/upgrade_downgrade_test_query_serving_schema_next_release.yml index a1bfe3fb8e9..4add0acab41 100644 --- a/.github/workflows/upgrade_downgrade_test_query_serving_schema_next_release.yml +++ b/.github/workflows/upgrade_downgrade_test_query_serving_schema_next_release.yml @@ -212,9 +212,11 @@ jobs: run: | source build.env - rm -f $PWD/bin/vtgate $PWD/bin/vttablet + rm -f $PWD/bin/vtgate $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-current/bin/vtgate $PWD/bin/vtgate cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vtgate --version vttablet --version diff --git a/.github/workflows/upgrade_downgrade_test_reparent_new_vttablet.yml b/.github/workflows/upgrade_downgrade_test_reparent_new_vttablet.yml index e288c5b9c26..12fde50dc98 100644 --- a/.github/workflows/upgrade_downgrade_test_reparent_new_vttablet.yml +++ b/.github/workflows/upgrade_downgrade_test_reparent_new_vttablet.yml @@ -182,8 +182,10 @@ jobs: run: | source build.env - rm -f $PWD/bin/vttablet + rm -f $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vtctl --version vttablet --version diff --git a/.github/workflows/upgrade_downgrade_test_reparent_old_vttablet.yml b/.github/workflows/upgrade_downgrade_test_reparent_old_vttablet.yml index ad1febeab85..de97a18a095 100644 --- a/.github/workflows/upgrade_downgrade_test_reparent_old_vttablet.yml +++ b/.github/workflows/upgrade_downgrade_test_reparent_old_vttablet.yml @@ -179,8 +179,10 @@ jobs: run: | source build.env - rm -f $PWD/bin/vttablet + rm -f $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vtctl --version vttablet --version diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index 9b877e94459..42c37e06ff9 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -62,12 +62,21 @@ func TestTabletInitialBackup(t *testing.T) { // Initialize the tablets initTablets(t, false, false) + _, err := getVTExecVersion("vttablet") + require.NoError(t, err) + //if ver > 15 { + //_, err := primary.VttabletProcess.QueryTablet(vtInsertTest, keyspaceName, true) + //require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") + //_, err = replica1.VttabletProcess.QueryTablet(vtInsertTest, keyspaceName, true) + //require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") + //} + // Restore the Tablets restore(t, primary, "replica", "NOT_SERVING") // Vitess expects that the user has set the database into ReadWrite mode before calling // TabletExternallyReparented - err := localCluster.VtctlclientProcess.ExecuteCommand( + err = localCluster.VtctlclientProcess.ExecuteCommand( "SetReadWrite", primary.Alias) require.Nil(t, err) err = localCluster.VtctlclientProcess.ExecuteCommand( @@ -175,15 +184,21 @@ func vtBackup(t *testing.T, initialBackup bool, restartBeforeBackup, disableRedo if restartBeforeBackup { extraArgs = append(extraArgs, "--restart_before_backup") } + ver, err := getVTExecVersion("vtbackup") + require.NoError(t, err) if disableRedoLog { - extraArgs = append(extraArgs, "--disable-redo-log") + if ver > 15 { + extraArgs = append(extraArgs, "--disable-redo-log") + } } ctx, cancel := context.WithCancel(context.Background()) defer cancel() if !initialBackup && disableRedoLog { - go verifyDisableEnableRedoLogs(ctx, t, mysqlSocket.Name()) + if ver > 15 { + go verifyDisableEnableRedoLogs(ctx, t, mysqlSocket.Name()) + } } log.Infof("starting backup tablet %s", time.Now()) @@ -367,3 +382,14 @@ func verifyDisableEnableRedoLogs(ctx context.Context, t *testing.T, mysqlSocket } } } + +// insert should not work for any of the replicas and primary +func getVTExecVersion(binaryName string) (int, error) { + vtTabletVersion := 0 + vtTabletVersion, err := cluster.GetMajorVersion(binaryName) + if err != nil { + return 0, err + } + log.Infof("cluster.VtTabletMajorVersion: %d", vtTabletVersion) + return vtTabletVersion, nil +} diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index c1833e53cd4..af33ee4a523 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -143,12 +143,6 @@ func TestMain(m *testing.M) { } } } - // Create database - /*for _, tablet := range []cluster.Vttablet{*primary, *replica1} { - if err := tablet.VttabletProcess.CreateDB(keyspaceName); err != nil { - return 1, err - } - }*/ return m.Run(), nil }() From 4e0bd8095f877c9931ee71a005e9f454e540b9c9 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 21 Dec 2022 16:14:52 -0800 Subject: [PATCH 16/65] fixing reparent upgrade downgrade test Signed-off-by: Rameez Sajwani --- .../reparent/plannedreparent/reparent_test.go | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go index de7e6a0368b..6a476b183ed 100644 --- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go +++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go @@ -363,6 +363,33 @@ func TestChangeTypeSemiSync(t *testing.T) { utils.CheckDBstatus(ctx, t, rdonly2, "Rpl_semi_sync_slave_status", "ON") } +func TestReparentDoesntHangIfPrimaryFails(t *testing.T) { + //FIXME: need to rewrite this test: how? + t.Skip("since the new schema init approach will automatically heal mismatched schemas, the approach in this test doesn't work now") + defer cluster.PanicHandler(t) + clusterInstance := utils.SetupReparentCluster(t, "semi_sync") + defer utils.TeardownCluster(clusterInstance) + tablets := clusterInstance.Keyspaces[0].Shards[0].Vttablets + + // Change the schema of the _vt.reparent_journal table, so that + // inserts into it will fail. That will make the primary fail. + _, err := tablets[0].VttabletProcess.QueryTabletWithDB( + "ALTER TABLE reparent_journal DROP COLUMN replication_position", "_vt") + require.NoError(t, err) + + // Perform a planned reparent operation, the primary will fail the + // insert. The replicas should then abort right away. + ver, err := getVTExecVersion("vttablet") + require.NoError(t, err) + out, err := utils.Prs(t, clusterInstance, tablets[1]) + if ver <= 15 { + require.Error(t, err) + assert.Contains(t, out, "primary failed to PopulateReparentJournal") + } else { + require.NoError(t, err, "PRS should not fail.") + } +} + // TestCrossCellDurability tests 2 things - // 1. When PRS is run with the cross_cell durability policy setup, then the semi-sync settings on all the tablets are as expected // 2. Bringing up a new vttablet should have its replication and semi-sync setup correctly without any manual intervention @@ -532,3 +559,14 @@ func rowNumberFromPosition(pos string) int { rowNum, _ := strconv.Atoi(rowNumStr) return rowNum } + +// insert should not work for any of the replicas and primary +func getVTExecVersion(binaryName string) (int, error) { + vtTabletVersion := 0 + vtTabletVersion, err := cluster.GetMajorVersion(binaryName) + if err != nil { + return 0, err + } + log.Infof("cluster.VtTabletMajorVersion: %d", vtTabletVersion) + return vtTabletVersion, nil +} From 215f3180d062fcf438d41b3cb78d6904df7a2596 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 18 Jan 2023 23:02:51 -0800 Subject: [PATCH 17/65] Bug fix for replication position Signed-off-by: Rameez Sajwani --- go/cmd/vtcombo/main.go | 1 - go/test/endtoend/cluster/cluster_process.go | 1 - go/test/endtoend/cluster/vtctld_process.go | 2 -- go/test/endtoend/recovery/pitr/shardedpitr_test.go | 2 +- go/test/endtoend/vault/vault_test.go | 3 --- 5 files changed, 1 insertion(+), 8 deletions(-) diff --git a/go/cmd/vtcombo/main.go b/go/cmd/vtcombo/main.go index 91399418a8b..837887b192b 100644 --- a/go/cmd/vtcombo/main.go +++ b/go/cmd/vtcombo/main.go @@ -190,7 +190,6 @@ func main() { servenv.Init() tabletenv.Init() - //time.Sleep(10 * time.Second) mysqld := &vtcomboMysqld{} var cnf *mysqlctl.Mycnf if *startMysql { diff --git a/go/test/endtoend/cluster/cluster_process.go b/go/test/endtoend/cluster/cluster_process.go index f653744dbdd..61e2a3252f5 100644 --- a/go/test/endtoend/cluster/cluster_process.go +++ b/go/test/endtoend/cluster/cluster_process.go @@ -681,7 +681,6 @@ func NewBareCluster(cell string, hostname string) *LocalProcessCluster { } else { err = createDirectory(cluster.CurrentVTDATAROOT, 0700) if err != nil { - fmt.Printf("err in creating file : %s", err.Error()) log.Infof("err in creating file : %s", err.Error()) } } diff --git a/go/test/endtoend/cluster/vtctld_process.go b/go/test/endtoend/cluster/vtctld_process.go index e9ab52e67d4..5e85f172ce1 100644 --- a/go/test/endtoend/cluster/vtctld_process.go +++ b/go/test/endtoend/cluster/vtctld_process.go @@ -105,8 +105,6 @@ func (vtctld *VtctldProcess) Setup(cell string, extraArgs ...string) (err error) } func createDirectory(dirName string, mode os.FileMode) error { - log.Infof("creating directory : %s", dirName) - fmt.Printf("creating directory : %s", dirName) if _, err := os.Stat(dirName); os.IsNotExist(err) { return os.Mkdir(dirName, mode) } diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go index 4450dab3584..295c5afbc4f 100644 --- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go +++ b/go/test/endtoend/recovery/pitr/shardedpitr_test.go @@ -442,7 +442,7 @@ func initializeCluster(t *testing.T) { fmt.Sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s';", mysqlUserName, mysqlPassword), fmt.Sprintf("GRANT ALL ON *.* TO '%s'@'%%';", mysqlUserName), fmt.Sprintf("GRANT GRANT OPTION ON *.* TO '%s'@'%%';", mysqlUserName), - //fmt.Sprintf("create database %s;", "vt_ks"), + fmt.Sprintf("create database %s;", "vt_ks"), "FLUSH PRIVILEGES;", } diff --git a/go/test/endtoend/vault/vault_test.go b/go/test/endtoend/vault/vault_test.go index 5ffd356a0f6..dbebd66a0c4 100644 --- a/go/test/endtoend/vault/vault_test.go +++ b/go/test/endtoend/vault/vault_test.go @@ -285,9 +285,6 @@ func initializeClusterLate(t *testing.T) { require.NoError(t, err) } } - /*query := fmt.Sprintf("create database %s;", dbName) - _, err = tablet.VttabletProcess.QueryTablet(query, keyspace.Name, false) - require.NoError(t, err)*/ err = tablet.VttabletProcess.Setup() require.NoError(t, err) From 4da62a4d83075a1f2cc5fa5a782b59659452c98f Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Thu, 19 Jan 2023 12:46:00 -0800 Subject: [PATCH 18/65] Fixing vtexplain tests Signed-off-by: Rameez Sajwani --- go/test/endtoend/backup/vtbackup/backup_only_test.go | 2 +- go/test/endtoend/cluster/vttablet_process.go | 7 +++++++ go/test/endtoend/tabletmanager/tablet_test.go | 6 +++--- go/vt/vtexplain/vtexplain_vttablet.go | 4 ++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index 42c37e06ff9..0a5ae1036c5 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -273,7 +273,7 @@ func restore(t *testing.T, tablet *cluster.Vttablet, tabletType string, waitForS log.Infof("restoring tablet %s", time.Now()) resetTabletDirectory(t, *tablet, true) - err := tablet.VttabletProcess.CreateDB(keyspaceName) + err := tablet.VttabletProcess.CreateDBWithSuperReadOnly(keyspaceName) require.Nil(t, err) // Start tablets diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index cf2453c8a59..1300240fccf 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -410,6 +410,13 @@ func (vttablet *VttabletProcess) CreateDB(keyspace string) error { return err } +// CreateDBWithSuperReadOnly creates the database for keyspace +func (vttablet *VttabletProcess) CreateDBWithSuperReadOnly(keyspace string) error { + _, _ = vttablet.QueryTabletWithSuperReadOnlyHandling(fmt.Sprintf("drop database IF EXISTS vt_%s", keyspace), keyspace, false) + _, err := vttablet.QueryTabletWithSuperReadOnlyHandling(fmt.Sprintf("create database IF NOT EXISTS vt_%s", keyspace), keyspace, false) + return err +} + // QueryTablet lets you execute a query in this tablet and get the result func (vttablet *VttabletProcess) QueryTablet(query string, keyspace string, useDb bool) (*sqltypes.Result, error) { if !useDb { diff --git a/go/test/endtoend/tabletmanager/tablet_test.go b/go/test/endtoend/tabletmanager/tablet_test.go index 3c597e97981..d191679e106 100644 --- a/go/test/endtoend/tabletmanager/tablet_test.go +++ b/go/test/endtoend/tabletmanager/tablet_test.go @@ -45,12 +45,12 @@ func TestEnsureDB(t *testing.T) { // Make it the primary. err = clusterInstance.VtctlclientProcess.ExecuteCommand("TabletExternallyReparented", tablet.Alias) - require.EqualError(t, err, "exit status 1") + require.NoError(t, err, "No error expected.") // It is still NOT_SERVING because the db is read-only. - assert.Equal(t, "NOT_SERVING", tablet.VttabletProcess.GetTabletStatus()) + assert.Equal(t, "SERVING", tablet.VttabletProcess.GetTabletStatus()) status := tablet.VttabletProcess.GetStatusDetails() - assert.Contains(t, status, "read-only") + assert.Contains(t, status, "healthy") // Switch to read-write and verify that we go serving. // Note: for TabletExternallyReparented, we expect SetReadWrite to be called by the user diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 6784efe4cbd..1ed23322872 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -691,6 +691,10 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* result = &sqltypes.Result{ RowsAffected: 1, } + case sqlparser.StmtUse: + result = &sqltypes.Result{} + case sqlparser.StmtDDL: + result = &sqltypes.Result{} default: return fmt.Errorf("unsupported query %s", query) } From 8c4e93332b16d2a4cc54d4d5e77ca3083ebc7710 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 23 Jan 2023 11:33:37 -0800 Subject: [PATCH 19/65] Fixing mariadb initialization Signed-off-by: Rameez Sajwani --- config/init_maria_db.sql | 24 ------------------------ go/vt/mysqlctl/mysqld.go | 11 +++++++++-- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/config/init_maria_db.sql b/config/init_maria_db.sql index f33c18d4072..e2c4d018424 100644 --- a/config/init_maria_db.sql +++ b/config/init_maria_db.sql @@ -29,23 +29,6 @@ DROP DATABASE IF EXISTS test; # Vitess defaults ############################################################################### -# Vitess-internal database. -CREATE DATABASE IF NOT EXISTS _vt; -# Note that definitions of local_metadata and shard_metadata should be the same -# as in production which is defined in go/vt/mysqlctl/metadata_tables.go. -CREATE TABLE IF NOT EXISTS _vt.local_metadata ( - name VARCHAR(255) NOT NULL, - value VARCHAR(255) NOT NULL, - db_name VARBINARY(255) NOT NULL, - PRIMARY KEY (db_name, name) - ) ENGINE=InnoDB; -CREATE TABLE IF NOT EXISTS _vt.shard_metadata ( - name VARCHAR(255) NOT NULL, - value MEDIUMBLOB NOT NULL, - db_name VARBINARY(255) NOT NULL, - PRIMARY KEY (db_name, name) - ) ENGINE=InnoDB; - # Admin user with all privileges. CREATE USER 'vt_dba'@'localhost'; GRANT ALL ON *.* TO 'vt_dba'@'localhost'; @@ -91,13 +74,6 @@ GRANT SELECT, PROCESS, SUPER, REPLICATION CLIENT, RELOAD GRANT SELECT, UPDATE, DELETE, DROP ON performance_schema.* TO 'vt_monitoring'@'localhost'; -# User for Orchestrator (https://github.com/openark/orchestrator). -CREATE USER 'orc_client_user'@'%' IDENTIFIED BY 'orc_client_user_password'; -GRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD - ON *.* TO 'orc_client_user'@'%'; -GRANT SELECT - ON _vt.* TO 'orc_client_user'@'%'; - FLUSH PRIVILEGES; RESET SLAVE ALL; diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index 7dcbca3ac84..6abf5a7bdc4 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -697,8 +697,15 @@ func (mysqld *Mysqld) Init(ctx context.Context, cnf *Mycnf, initDBSQLFile string } if initDBSQLFile == "" { // default to built-in - if err := mysqld.executeMysqlScript(params, strings.NewReader(config.DefaultInitDB)); err != nil { - return fmt.Errorf("failed to initialize mysqld: %v", err) + if mysqld.capabilities.isMySQLLike() { + if err := mysqld.executeMysqlScript(params, strings.NewReader(config.DefaultInitDB)); err != nil { + return fmt.Errorf("failed to initialize mysqld: %v", err) + } + } else { + // it is mariaDB + if err := mysqld.executeMysqlScript(params, strings.NewReader(config.DefaultInitMariaDB)); err != nil { + return fmt.Errorf("failed to initialize mariadb mysqld: %v", err) + } } return nil } From e8afcab5d2c86d472085e66f9cc4120cb3122eb7 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 23 Jan 2023 12:02:38 -0800 Subject: [PATCH 20/65] fixing upgrade downgrade e2e test Signed-off-by: Rameez Sajwani --- .github/workflows/upgrade_downgrade_test_backups_e2e.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/upgrade_downgrade_test_backups_e2e.yml b/.github/workflows/upgrade_downgrade_test_backups_e2e.yml index b7f6ddc092a..ee94ead08cd 100644 --- a/.github/workflows/upgrade_downgrade_test_backups_e2e.yml +++ b/.github/workflows/upgrade_downgrade_test_backups_e2e.yml @@ -161,8 +161,10 @@ jobs: run: | source build.env - rm -f $PWD/bin/vttablet + rm -f $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vttablet --version # Run test with VTTablet at version N-1 and VTBackup at version N @@ -181,9 +183,11 @@ jobs: run: | source build.env - rm -f $PWD/bin/vtbackup $PWD/bin/vttablet + rm -f $PWD/bin/vtbackup $PWD/bin/vttablet $PWD/bin/mysqlctl $PWD/bin/mysqlctld cp /tmp/vitess-build-current/bin/vtbackup $PWD/bin/vtbackup cp /tmp/vitess-build-other/bin/vttablet $PWD/bin/vttablet + cp /tmp/vitess-build-other/bin/mysqlctl $PWD/bin/mysqlctl + cp /tmp/vitess-build-other/bin/mysqlctld $PWD/bin/mysqlctld vtbackup --version vttablet --version From 3c26c6be98ff71bebedc3918020d3ae403d6911d Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 23 Jan 2023 17:00:52 -0800 Subject: [PATCH 21/65] Fixing assignment of init sql db file Signed-off-by: Rameez Sajwani --- go/test/endtoend/cluster/mysqlctl_process.go | 25 ++++++++++++++++++- go/test/endtoend/cluster/mysqlctld_process.go | 8 +++++- go/vt/mysqlctl/mysqld.go | 1 + go/vt/vttest/environment.go | 19 +++++++++++++- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/go/test/endtoend/cluster/mysqlctl_process.go b/go/test/endtoend/cluster/mysqlctl_process.go index eafc8f6b98f..f8642a32c5b 100644 --- a/go/test/endtoend/cluster/mysqlctl_process.go +++ b/go/test/endtoend/cluster/mysqlctl_process.go @@ -30,6 +30,7 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/mysqlctl" "vitess.io/vitess/go/vt/tlstest" ) @@ -236,11 +237,17 @@ func (mysqlctl *MysqlctlProcess) Connect(ctx context.Context, username string) ( // MysqlCtlProcessInstanceOptionalInit returns a Mysqlctl handle for mysqlctl process // configured with the given Config. func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirectory string, initMySQL bool) *MysqlctlProcess { + var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value + if isSQL, err := isSQLFlavor(); err == nil { + if !isSQL { + initFile = path.Join(os.Getenv("VTROOT"), "config/init_maria_db.sql") + } + } mysqlctl := &MysqlctlProcess{ Name: "mysqlctl", Binary: "mysqlctl", LogDirectory: tmpDirectory, - InitDBFile: path.Join(os.Getenv("VTROOT"), "/config/init_db.sql"), + InitDBFile: initFile, } mysqlctl.MySQLPort = mySQLPort mysqlctl.TabletUID = tabletUID @@ -249,6 +256,22 @@ func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirect return mysqlctl } +func isSQLFlavor() (bool, error) { + versionStr, err := mysqlctl.GetVersionString() + if err != nil { + return false, err + } + flavor, _, err := mysqlctl.ParseVersionString(versionStr) + if err != nil { + return false, err + } + if flavor == mysqlctl.FlavorMySQL || flavor == mysqlctl.FlavorPercona { + return true, nil + } + + return false, nil +} + // MysqlCtlProcessInstance returns a Mysqlctl handle for mysqlctl process // configured with the given Config. func MysqlCtlProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) *MysqlctlProcess { diff --git a/go/test/endtoend/cluster/mysqlctld_process.go b/go/test/endtoend/cluster/mysqlctld_process.go index d71f2e3b1c8..5e05a665ac1 100644 --- a/go/test/endtoend/cluster/mysqlctld_process.go +++ b/go/test/endtoend/cluster/mysqlctld_process.go @@ -145,11 +145,17 @@ func (mysqlctld *MysqlctldProcess) CleanupFiles(tabletUID int) { // MysqlCtldProcessInstance returns a Mysqlctld handle for mysqlctld process // configured with the given Config. func MysqlCtldProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) *MysqlctldProcess { + var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value + if isSQL, err := isSQLFlavor(); err == nil { + if !isSQL { + initFile = path.Join(os.Getenv("VTROOT"), "config/init_maria_db.sql") + } + } mysqlctld := &MysqlctldProcess{ Name: "mysqlctld", Binary: "mysqlctld", LogDirectory: tmpDirectory, - InitDBFile: path.Join(os.Getenv("VTROOT"), "/config/init_db.sql"), + InitDBFile: initFile, } mysqlctld.MySQLPort = mySQLPort mysqlctld.TabletUID = tabletUID diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index 6abf5a7bdc4..83a5b0bbc78 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -696,6 +696,7 @@ func (mysqld *Mysqld) Init(ctx context.Context, cnf *Mycnf, initDBSQLFile string return err } + log.Infof("initDBSQLFile: %s", initDBSQLFile) if initDBSQLFile == "" { // default to built-in if mysqld.capabilities.isMySQLLike() { if err := mysqld.executeMysqlScript(params, strings.NewReader(config.DefaultInitDB)); err != nil { diff --git a/go/vt/vttest/environment.go b/go/vt/vttest/environment.go index 89fd44bf434..830a7316d43 100644 --- a/go/vt/vttest/environment.go +++ b/go/vt/vttest/environment.go @@ -92,6 +92,9 @@ type Environment interface { // any temporary data in the environment. Environments that can // last through several test runs do not need to implement it. TearDown() error + + // IsSQLFlavor retruns the flavor or SQL Server running + IsSQLFlavor() bool } // LocalTestEnv is an Environment implementation for local testing @@ -144,9 +147,14 @@ func (env *LocalTestEnv) BinaryPath(binary string) string { // MySQLManager implements MySQLManager for LocalTestEnv func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLManager, error) { + // maria db doesn't recognize super-read-only, therefore we have separate sql for that. + var initFile = path.Join(os.Getenv("VTROOT"), "config/init_db.sql") + if !env.IsSQLFlavor() { + initFile = path.Join(os.Getenv("VTROOT"), "config/init_maria_db.sql") + } return &Mysqlctl{ Binary: env.BinaryPath("mysqlctl"), - InitFile: path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql"), + InitFile: initFile, Directory: env.TmpPath, Port: env.PortForProtocol("mysql", ""), MyCnf: append(env.DefaultMyCnf, mycnf...), @@ -155,6 +163,15 @@ func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLMan }, nil } +func (env *LocalTestEnv) IsSQLFlavor() bool { + for _, val := range env.Env { + if strings.Contains(val, "MYSQL_FLAVOR=MySQL") { + return true + } + } + return false +} + // TopoManager implements TopoManager for LocalTestEnv func (env *LocalTestEnv) TopoManager(topoImplementation, topoServerAddress, topoRoot string, topology *vttest.VTTestTopology) TopoManager { return &Topoctl{ From 46ab5507d196372f3644e405fa6815c6abef6b0e Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Tue, 24 Jan 2023 11:21:12 -0800 Subject: [PATCH 22/65] code clean up Signed-off-by: Rameez Sajwani --- go/cmd/vtbackup/vtbackup.go | 2 +- go/mysql/fakesqldb/server.go | 28 ------------------- .../backup/vtbackup/backup_only_test.go | 15 +++++----- go/test/endtoend/tabletmanager/tablet_test.go | 3 +- go/vt/mysqlctl/mysqld.go | 5 ---- go/vt/vtcombo/tablet_map.go | 4 --- 6 files changed, 10 insertions(+), 47 deletions(-) diff --git a/go/cmd/vtbackup/vtbackup.go b/go/cmd/vtbackup/vtbackup.go index f68149c1db9..6f5a3fcad8f 100644 --- a/go/cmd/vtbackup/vtbackup.go +++ b/go/cmd/vtbackup/vtbackup.go @@ -294,7 +294,7 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back } // In initial_backup mode, just take a backup of this empty database. if initialBackup { - log.Infof("inside initialBackup creating reparent journal.") + log.Infof("inside initialBackup creating initial binlog entry.") // Take a backup of this empty DB without restoring anything. // First, initialize it the way InitShardPrimary would, so this backup // produces a result that can be used to skip InitShardPrimary entirely. diff --git a/go/mysql/fakesqldb/server.go b/go/mysql/fakesqldb/server.go index 04e82d27d71..5b00b2c2e01 100644 --- a/go/mysql/fakesqldb/server.go +++ b/go/mysql/fakesqldb/server.go @@ -198,34 +198,6 @@ func New(t testing.TB) *DB { return db } -// NewWithExpectedQueries returns DB with all the queries expected at the time of vttablet Initialization -func NewWithExpectedQueries(t testing.TB) *DB { - newDb := New(t) - newDb.AddQuery("CREATE DATABASE IF NOT EXISTS _vt", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQuery("create database if not exists `vt_test_keyspace`", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQuery("SET GLOBAL super_read_only='OFF'", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQuery("SET GLOBAL read_only='OFF'", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQuery("SET @@session.sql_log_bin = 0", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQuery("SET GLOBAL super_read_only='ON'", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("CREATE TABLE IF NOT EXISTS _vt.local_metadata.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("ALTER TABLE _vt.vreplication .*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("ALTER TABLE _vt.local_metadata.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("CREATE TABLE IF NOT EXISTS _vt.shard_metadata.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("ALTER TABLE _vt.shard_metadata.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQuery("DROP TABLE IF EXISTS _vt.blp_checkpoint", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("CREATE TABLE IF NOT EXISTS _vt.vreplication.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("create table if not exists _vt.resharding_journal.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("create table if not exists _vt.copy_state.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("CREATE TABLE IF NOT EXISTS _vt.schema_migrations.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("SELECT.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("ALTER TABLE _vt.schema_migrations.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("CREATE TABLE IF NOT EXISTS _vt.reparent_journal.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("CREATE TABLE if not exists _vt.schemacopy.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQueryPattern("ALTER TABLE _vt.reparent_journal.*", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - newDb.AddQuery("USE `vt_test_keyspace`", &sqltypes.Result{InsertID: 0, RowsAffected: 0}) - return newDb -} - // Name returns the name of the DB. func (db *DB) Name() string { db.mu.Lock() diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index 0a5ae1036c5..b6e3d076096 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -62,17 +62,16 @@ func TestTabletInitialBackup(t *testing.T) { // Initialize the tablets initTablets(t, false, false) - _, err := getVTExecVersion("vttablet") + ver, err := getVTExecVersion("vttablet") require.NoError(t, err) - //if ver > 15 { - //_, err := primary.VttabletProcess.QueryTablet(vtInsertTest, keyspaceName, true) - //require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") - //_, err = replica1.VttabletProcess.QueryTablet(vtInsertTest, keyspaceName, true) - //require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") - //} + if ver > 15 { + _, err := primary.VttabletProcess.QueryTablet(vtInsertTest, keyspaceName, true) + require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") + _, err = replica1.VttabletProcess.QueryTablet(vtInsertTest, keyspaceName, true) + require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") + } // Restore the Tablets - restore(t, primary, "replica", "NOT_SERVING") // Vitess expects that the user has set the database into ReadWrite mode before calling // TabletExternallyReparented diff --git a/go/test/endtoend/tabletmanager/tablet_test.go b/go/test/endtoend/tabletmanager/tablet_test.go index d191679e106..ca1707f2b3b 100644 --- a/go/test/endtoend/tabletmanager/tablet_test.go +++ b/go/test/endtoend/tabletmanager/tablet_test.go @@ -47,7 +47,8 @@ func TestEnsureDB(t *testing.T) { err = clusterInstance.VtctlclientProcess.ExecuteCommand("TabletExternallyReparented", tablet.Alias) require.NoError(t, err, "No error expected.") - // It is still NOT_SERVING because the db is read-only. + // Once promoted to primary during vschema/engine.go we change tablet to ReadWrite, hence promoting + // tablet to SERVING status. assert.Equal(t, "SERVING", tablet.VttabletProcess.GetTabletStatus()) status := tablet.VttabletProcess.GetStatusDetails() assert.Contains(t, status, "healthy") diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index 83a5b0bbc78..bb43576cfbf 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -1277,8 +1277,6 @@ func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTID mysqlCmd.Dir = dir mysqlCmd.Env = env mysqlCmd.Stdin = pipe // piped from mysqlbinlog - mysqlCmd.Stdout = os.Stderr - mysqlCmd.Stderr = os.Stderr } // Run both processes, piped: if err := mysqlbinlogCmd.Start(); err != nil { @@ -1292,9 +1290,6 @@ func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTID return err } if err := mysqlCmd.Wait(); err != nil { - println(mysqlCmd.Stdout) - println(mysqlCmd.Stderr) - println(mysqlCmd.Stdin) return err } return nil diff --git a/go/vt/vtcombo/tablet_map.go b/go/vt/vtcombo/tablet_map.go index dd27d381d1a..767217b442b 100644 --- a/go/vt/vtcombo/tablet_map.go +++ b/go/vt/vtcombo/tablet_map.go @@ -126,10 +126,6 @@ func CreateTablet( if err := tm.ChangeType(ctx, topodatapb.TabletType_PRIMARY /* semi-sync */, false); err != nil { return fmt.Errorf("TabletExternallyReparented failed on primary %v: %v", topoproto.TabletAliasString(alias), err) } - /*log.Infof("setting super read only to false for test purpose %v", topoproto.TabletAliasString(alias)) - if err := tm.MysqlDaemon.SetReadOnly(false); err != nil { - return fmt.Errorf("failed on set super read only on %v: %v", topoproto.TabletAliasString(alias), err) - }*/ } controller.AddStatusHeader() controller.AddStatusPart() From a3804cad739172db4065feb9bcfb424d94ec1596 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Tue, 24 Jan 2023 15:48:01 -0800 Subject: [PATCH 23/65] Fixing backup test Signed-off-by: Rameez Sajwani --- go/test/endtoend/backup/vtbackup/backup_only_test.go | 4 ++-- go/test/endtoend/tabletmanager/tablet_test.go | 1 + go/vt/vttablet/tabletserver/tx_engine.go | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index b6e3d076096..a9788edcc26 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -65,9 +65,9 @@ func TestTabletInitialBackup(t *testing.T) { ver, err := getVTExecVersion("vttablet") require.NoError(t, err) if ver > 15 { - _, err := primary.VttabletProcess.QueryTablet(vtInsertTest, keyspaceName, true) + err := primary.VttabletProcess.CreateDB("testDB") require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") - _, err = replica1.VttabletProcess.QueryTablet(vtInsertTest, keyspaceName, true) + err = replica1.VttabletProcess.CreateDB("testDB") require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") } diff --git a/go/test/endtoend/tabletmanager/tablet_test.go b/go/test/endtoend/tabletmanager/tablet_test.go index ca1707f2b3b..c2c2a0e6b6d 100644 --- a/go/test/endtoend/tabletmanager/tablet_test.go +++ b/go/test/endtoend/tabletmanager/tablet_test.go @@ -43,6 +43,7 @@ func TestEnsureDB(t *testing.T) { err = clusterInstance.StartVttablet(tablet, "NOT_SERVING", false, cell, "dbtest", hostname, "0") require.NoError(t, err) + assert.Equal(t, "NOT_SERVING", tablet.VttabletProcess.GetTabletStatus()) // Make it the primary. err = clusterInstance.VtctlclientProcess.ExecuteCommand("TabletExternallyReparented", tablet.Alias) require.NoError(t, err, "No error expected.") diff --git a/go/vt/vttablet/tabletserver/tx_engine.go b/go/vt/vttablet/tabletserver/tx_engine.go index 4e1ceeeb1eb..c379ef83d2f 100644 --- a/go/vt/vttablet/tabletserver/tx_engine.go +++ b/go/vt/vttablet/tabletserver/tx_engine.go @@ -19,6 +19,7 @@ package tabletserver import ( "context" "fmt" + "runtime/debug" "sync" "time" @@ -155,6 +156,7 @@ func (te *TxEngine) transition(state txEngineState) { } log.Infof("TxEngine transition: %v", state) + log.Infof("call stack: %s", debug.Stack()) switch te.state { case AcceptingReadOnly, AcceptingReadAndWrite: te.shutdownLocked() From deba5c79974a4165f8f4e79845e814048340b598 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Tue, 24 Jan 2023 22:38:55 -0800 Subject: [PATCH 24/65] adding super read only api for sql demon Signed-off-by: Rameez Sajwani --- .../fakemysqldaemon/fakemysqldaemon.go | 5 +++ go/vt/mysqlctl/mysql_daemon.go | 1 + go/vt/mysqlctl/replication.go | 15 ++++++++ .../replicationdata/replicationdata.pb.go | 28 ++++++++++----- .../replicationdata_vtproto.pb.go | 35 +++++++++++++++++++ .../vttablet/tabletmanager/rpc_replication.go | 7 ++++ proto/replicationdata.proto | 1 + 7 files changed, 83 insertions(+), 9 deletions(-) diff --git a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go index 3bc1c984a15..ff478693d73 100644 --- a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go +++ b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go @@ -366,6 +366,11 @@ func (fmd *FakeMysqlDaemon) IsReadOnly() (bool, error) { return fmd.ReadOnly, nil } +// IsSuperReadOnly is part of the MysqlDaemon interface +func (fmd *FakeMysqlDaemon) IsSuperReadOnly() (bool, error) { + return fmd.SuperReadOnly, nil +} + // SetReadOnly is part of the MysqlDaemon interface func (fmd *FakeMysqlDaemon) SetReadOnly(on bool) error { fmd.ReadOnly = on diff --git a/go/vt/mysqlctl/mysql_daemon.go b/go/vt/mysqlctl/mysql_daemon.go index ac0aede5614..f88dce2cf30 100644 --- a/go/vt/mysqlctl/mysql_daemon.go +++ b/go/vt/mysqlctl/mysql_daemon.go @@ -72,6 +72,7 @@ type MysqlDaemon interface { ResetReplication(ctx context.Context) error PrimaryPosition() (mysql.Position, error) IsReadOnly() (bool, error) + IsSuperReadOnly() (bool, error) SetReadOnly(on bool) error SetSuperReadOnly(on bool) error SetReplicationPosition(ctx context.Context, pos mysql.Position) error diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index 1f9ca28af7c..d29bc14f235 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -231,6 +231,21 @@ func (mysqld *Mysqld) IsReadOnly() (bool, error) { return false, nil } +// IsSuperReadOnly return true if the instance is super read only +func (mysqld *Mysqld) IsSuperReadOnly() (bool, error) { + qr, err := mysqld.FetchSuperQuery(context.TODO(), "SHOW VARIABLES LIKE 'super_read_only'") + if err != nil { + return true, err + } + if len(qr.Rows) != 1 { + return true, errors.New("no super_read_only variable in mysql") + } + if qr.Rows[0][1].ToString() == "ON" { + return true, nil + } + return false, nil +} + // SetReadOnly set/unset the read_only flag func (mysqld *Mysqld) SetReadOnly(on bool) error { // temp logging, to be removed in v17 diff --git a/go/vt/proto/replicationdata/replicationdata.pb.go b/go/vt/proto/replicationdata/replicationdata.pb.go index 55bcdf99b55..58aedab8bbc 100644 --- a/go/vt/proto/replicationdata/replicationdata.pb.go +++ b/go/vt/proto/replicationdata/replicationdata.pb.go @@ -441,6 +441,7 @@ type FullStatus struct { SemiSyncPrimaryClients uint32 `protobuf:"varint,18,opt,name=semi_sync_primary_clients,json=semiSyncPrimaryClients,proto3" json:"semi_sync_primary_clients,omitempty"` SemiSyncPrimaryTimeout uint64 `protobuf:"varint,19,opt,name=semi_sync_primary_timeout,json=semiSyncPrimaryTimeout,proto3" json:"semi_sync_primary_timeout,omitempty"` SemiSyncWaitForReplicaCount uint32 `protobuf:"varint,20,opt,name=semi_sync_wait_for_replica_count,json=semiSyncWaitForReplicaCount,proto3" json:"semi_sync_wait_for_replica_count,omitempty"` + SuperReadOnly bool `protobuf:"varint,21,opt,name=super_read_only,json=superReadOnly,proto3" json:"super_read_only,omitempty"` } func (x *FullStatus) Reset() { @@ -615,6 +616,13 @@ func (x *FullStatus) GetSemiSyncWaitForReplicaCount() uint32 { return 0 } +func (x *FullStatus) GetSuperReadOnly() bool { + if x != nil { + return x.SuperReadOnly + } + return false +} + var File_replicationdata_proto protoreflect.FileDescriptor var file_replicationdata_proto_rawDesc = []byte{ @@ -690,7 +698,7 @@ var file_replicationdata_proto_rawDesc = []byte{ 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x66, 0x69, 0x6c, 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc3, 0x07, 0x0a, + 0x66, 0x69, 0x6c, 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xeb, 0x07, 0x0a, 0x0a, 0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, @@ -751,14 +759,16 @@ var file_replicationdata_proto_rawDesc = []byte{ 0x72, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1b, 0x73, 0x65, 0x6d, 0x69, 0x53, 0x79, 0x6e, 0x63, 0x57, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x2a, 0x3b, 0x0a, 0x13, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4f, 0x41, - 0x4e, 0x44, 0x53, 0x51, 0x4c, 0x54, 0x48, 0x52, 0x45, 0x41, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, - 0x0c, 0x49, 0x4f, 0x54, 0x48, 0x52, 0x45, 0x41, 0x44, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x01, 0x42, - 0x2e, 0x5a, 0x2c, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x76, 0x69, 0x74, - 0x65, 0x73, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x64, 0x61, 0x74, 0x61, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x61, 0x64, + 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x75, 0x70, + 0x65, 0x72, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x2a, 0x3b, 0x0a, 0x13, 0x53, 0x74, + 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, + 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4f, 0x41, 0x4e, 0x44, 0x53, 0x51, 0x4c, 0x54, 0x48, 0x52, + 0x45, 0x41, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x4f, 0x54, 0x48, 0x52, 0x45, 0x41, + 0x44, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x01, 0x42, 0x2e, 0x5a, 0x2c, 0x76, 0x69, 0x74, 0x65, 0x73, + 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x76, + 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/go/vt/proto/replicationdata/replicationdata_vtproto.pb.go b/go/vt/proto/replicationdata/replicationdata_vtproto.pb.go index 9a7b297a4fa..e136ff70c2d 100644 --- a/go/vt/proto/replicationdata/replicationdata_vtproto.pb.go +++ b/go/vt/proto/replicationdata/replicationdata_vtproto.pb.go @@ -354,6 +354,18 @@ func (m *FullStatus) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.SuperReadOnly { + i-- + if m.SuperReadOnly { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa8 + } if m.SemiSyncWaitForReplicaCount != 0 { i = encodeVarint(dAtA, i, uint64(m.SemiSyncWaitForReplicaCount)) i-- @@ -740,6 +752,9 @@ func (m *FullStatus) SizeVT() (n int) { if m.SemiSyncWaitForReplicaCount != 0 { n += 2 + sov(uint64(m.SemiSyncWaitForReplicaCount)) } + if m.SuperReadOnly { + n += 3 + } if m.unknownFields != nil { n += len(m.unknownFields) } @@ -2135,6 +2150,26 @@ func (m *FullStatus) UnmarshalVT(dAtA []byte) error { break } } + case 21: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SuperReadOnly", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SuperReadOnly = bool(v != 0) default: iNdEx = preIndex skippy, err := skip(dAtA[iNdEx:]) diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index 2a60f3a059c..72597437f3a 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -112,6 +112,12 @@ func (tm *TabletManager) FullStatus(ctx context.Context) (*replicationdatapb.Ful return nil, err } + // Read only - "SHOW VARIABLES LIKE 'read_only'" + superReadOnly, err := tm.MysqlDaemon.IsSuperReadOnly() + if err != nil { + return nil, err + } + // Binlog Information - "select @@global.binlog_format, @@global.log_bin, @@global.log_slave_updates, @@global.binlog_row_image" binlogFormat, logBin, logReplicaUpdates, binlogRowImage, err := tm.MysqlDaemon.GetBinlogInformation(ctx) if err != nil { @@ -157,6 +163,7 @@ func (tm *TabletManager) FullStatus(ctx context.Context) (*replicationdatapb.Ful SemiSyncPrimaryClients: semiSyncClients, SemiSyncPrimaryTimeout: semiSyncTimeout, SemiSyncWaitForReplicaCount: semiSyncNumReplicas, + SuperReadOnly: superReadOnly, }, nil } diff --git a/proto/replicationdata.proto b/proto/replicationdata.proto index 536ea2c4d13..2f98e30576f 100644 --- a/proto/replicationdata.proto +++ b/proto/replicationdata.proto @@ -93,4 +93,5 @@ message FullStatus { uint32 semi_sync_primary_clients = 18; uint64 semi_sync_primary_timeout = 19; uint32 semi_sync_wait_for_replica_count = 20; + bool super_read_only = 21; } From d443df55fec926520f03d29b9ede173d4266858e Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Tue, 24 Jan 2023 23:22:20 -0800 Subject: [PATCH 25/65] converting read-only calls to super-read-only calls Signed-off-by: Rameez Sajwani --- go/vt/mysqlctl/builtinbackupengine.go | 12 +++++++++--- go/vt/vttablet/tabletmanager/rpc_replication.go | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index caea82b6c31..23bc42015b1 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -331,7 +331,7 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac if sourceIsPrimary { if !readOnly { params.Logger.Infof("turning primary read-only before backup") - if err = params.Mysqld.SetReadOnly(true); err != nil { + if err = params.Mysqld.SetSuperReadOnly(true); err != nil { return false, vterrors.Wrap(err, "can't set read-only status") } } @@ -386,8 +386,14 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac // And set read-only mode params.Logger.Infof("resetting mysqld read-only to %v", readOnly) - if err := params.Mysqld.SetReadOnly(readOnly); err != nil { - return usable, err + if !readOnly { + if err := params.Mysqld.SetReadOnly(readOnly); err != nil { + return usable, err + } + } else { + if err := params.Mysqld.SetSuperReadOnly(readOnly); err != nil { + return usable, err + } } // Restore original mysqld state that we saved above. diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index 72597437f3a..b89065bfe6c 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -497,7 +497,7 @@ func (tm *TabletManager) demotePrimary(ctx context.Context, revertPartialFailure } } } else { - if err := tm.MysqlDaemon.SetReadOnly(true); err != nil { + if err := tm.MysqlDaemon.SetSuperReadOnly(true); err != nil { return nil, err } } From 31664d7c00efe1bf36ed8d7be527f31b4f89d602 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 25 Jan 2023 16:17:24 -0800 Subject: [PATCH 26/65] restructure vtexplain code to be more generic Signed-off-by: Rameez Sajwani --- go/mysql/fakesqldb/server.go | 45 +++++++++++++++++++++++++++ go/vt/vtexplain/vtexplain_test.go | 3 +- go/vt/vtexplain/vtexplain_vttablet.go | 23 ++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/go/mysql/fakesqldb/server.go b/go/mysql/fakesqldb/server.go index 5b00b2c2e01..d9b9fe51905 100644 --- a/go/mysql/fakesqldb/server.go +++ b/go/mysql/fakesqldb/server.go @@ -783,3 +783,48 @@ func (db *DB) MockQueriesForTable(table string, result *sqltypes.Result) { cols..., )) } + +func (db *DB) GetRejectedQueryResult(key string) error { + // check if we should reject it. + if err, ok := db.rejectedData[key]; ok { + return err + } + + return nil +} + +func (db *DB) GetQueryResult(key string) *ExpectedResult { + // Check explicit queries from AddQuery(). + result, ok := db.data[key] + if ok { + return result + } + return nil +} + +func (db *DB) GetQueryPatternResult(key string) (ExprResult, bool) { + for _, pat := range db.patternData { + if pat.Expr.MatchString(key) || strings.Contains(key, pat.QueryPattern) { + return pat, true + /*userCallback, ok := db.queryPatternUserCallback[pat.expr] + if ok { + userCallback(query) + } + if pat.err != "" { + return fmt.Errorf(pat.err) + } + return callback(pat.result)*/ + } + } + + return ExprResult{}, false +} + +func (db *DB) GetQueryPatternUserCallBack(exp *regexp.Regexp) (func(string), bool) { + userCallback, ok := db.queryPatternUserCallback[exp] + if ok { + return userCallback, true + } + + return nil, false +} diff --git a/go/vt/vtexplain/vtexplain_test.go b/go/vt/vtexplain/vtexplain_test.go index 8145c59b44d..256f9be048d 100644 --- a/go/vt/vtexplain/vtexplain_test.go +++ b/go/vt/vtexplain/vtexplain_test.go @@ -24,13 +24,14 @@ import ( "strings" "testing" + querypb "vitess.io/vitess/go/vt/proto/query" + "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv/tabletenvtest" "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" "vitess.io/vitess/go/vt/key" - querypb "vitess.io/vitess/go/vt/proto/query" "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/vt/topo" ) diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 1ed23322872..19e1f5f5d31 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -501,6 +501,29 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* if result != nil { return callback(result) } + + if err := t.db.GetRejectedQueryResult(query); err != nil { + return err + } + + if result := t.db.GetQueryResult(query); result != nil { + if f := result.BeforeFunc; f != nil { + f() + } + return callback(result.Result) + } + + if pat, ok := t.db.GetQueryPatternResult(query); ok { + userCallback, ok := t.db.GetQueryPatternUserCallBack(pat.Expr) + if ok { + userCallback(query) + } + if pat.Err != "" { + return fmt.Errorf(pat.Err) + } + return callback(pat.Result) + } + switch sqlparser.Preview(query) { case sqlparser.StmtSelect: // Parse the select statement to figure out the table and columns From e7a8aeb0d324e206dbcf09523e751e675f5c5a2e Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 25 Jan 2023 17:56:48 -0800 Subject: [PATCH 27/65] forgot to make proto vtadmin Signed-off-by: Rameez Sajwani --- web/vtadmin/src/proto/vtadmin.d.ts | 6 ++++++ web/vtadmin/src/proto/vtadmin.js | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/web/vtadmin/src/proto/vtadmin.d.ts b/web/vtadmin/src/proto/vtadmin.d.ts index 25b0c92bfa1..1a1e2b45142 100644 --- a/web/vtadmin/src/proto/vtadmin.d.ts +++ b/web/vtadmin/src/proto/vtadmin.d.ts @@ -31992,6 +31992,9 @@ export namespace replicationdata { /** FullStatus semi_sync_wait_for_replica_count */ semi_sync_wait_for_replica_count?: (number|null); + + /** FullStatus super_read_only */ + super_read_only?: (boolean|null); } /** Represents a FullStatus. */ @@ -32063,6 +32066,9 @@ export namespace replicationdata { /** FullStatus semi_sync_wait_for_replica_count. */ public semi_sync_wait_for_replica_count: number; + /** FullStatus super_read_only. */ + public super_read_only: boolean; + /** * Creates a new FullStatus instance using the specified properties. * @param [properties] Properties to set diff --git a/web/vtadmin/src/proto/vtadmin.js b/web/vtadmin/src/proto/vtadmin.js index cd7a5fe2936..7862951a54a 100644 --- a/web/vtadmin/src/proto/vtadmin.js +++ b/web/vtadmin/src/proto/vtadmin.js @@ -75678,6 +75678,7 @@ $root.replicationdata = (function() { * @property {number|null} [semi_sync_primary_clients] FullStatus semi_sync_primary_clients * @property {number|Long|null} [semi_sync_primary_timeout] FullStatus semi_sync_primary_timeout * @property {number|null} [semi_sync_wait_for_replica_count] FullStatus semi_sync_wait_for_replica_count + * @property {boolean|null} [super_read_only] FullStatus super_read_only */ /** @@ -75855,6 +75856,14 @@ $root.replicationdata = (function() { */ FullStatus.prototype.semi_sync_wait_for_replica_count = 0; + /** + * FullStatus super_read_only. + * @member {boolean} super_read_only + * @memberof replicationdata.FullStatus + * @instance + */ + FullStatus.prototype.super_read_only = false; + /** * Creates a new FullStatus instance using the specified properties. * @function create @@ -75919,6 +75928,8 @@ $root.replicationdata = (function() { writer.uint32(/* id 19, wireType 0 =*/152).uint64(message.semi_sync_primary_timeout); if (message.semi_sync_wait_for_replica_count != null && Object.hasOwnProperty.call(message, "semi_sync_wait_for_replica_count")) writer.uint32(/* id 20, wireType 0 =*/160).uint32(message.semi_sync_wait_for_replica_count); + if (message.super_read_only != null && Object.hasOwnProperty.call(message, "super_read_only")) + writer.uint32(/* id 21, wireType 0 =*/168).bool(message.super_read_only); return writer; }; @@ -76013,6 +76024,9 @@ $root.replicationdata = (function() { case 20: message.semi_sync_wait_for_replica_count = reader.uint32(); break; + case 21: + message.super_read_only = reader.bool(); + break; default: reader.skipType(tag & 7); break; @@ -76112,6 +76126,9 @@ $root.replicationdata = (function() { if (message.semi_sync_wait_for_replica_count != null && message.hasOwnProperty("semi_sync_wait_for_replica_count")) if (!$util.isInteger(message.semi_sync_wait_for_replica_count)) return "semi_sync_wait_for_replica_count: integer expected"; + if (message.super_read_only != null && message.hasOwnProperty("super_read_only")) + if (typeof message.super_read_only !== "boolean") + return "super_read_only: boolean expected"; return null; }; @@ -76180,6 +76197,8 @@ $root.replicationdata = (function() { message.semi_sync_primary_timeout = new $util.LongBits(object.semi_sync_primary_timeout.low >>> 0, object.semi_sync_primary_timeout.high >>> 0).toNumber(true); if (object.semi_sync_wait_for_replica_count != null) message.semi_sync_wait_for_replica_count = object.semi_sync_wait_for_replica_count >>> 0; + if (object.super_read_only != null) + message.super_read_only = Boolean(object.super_read_only); return message; }; @@ -76221,6 +76240,7 @@ $root.replicationdata = (function() { } else object.semi_sync_primary_timeout = options.longs === String ? "0" : 0; object.semi_sync_wait_for_replica_count = 0; + object.super_read_only = false; } if (message.server_id != null && message.hasOwnProperty("server_id")) object.server_id = message.server_id; @@ -76265,6 +76285,8 @@ $root.replicationdata = (function() { object.semi_sync_primary_timeout = options.longs === String ? $util.Long.prototype.toString.call(message.semi_sync_primary_timeout) : options.longs === Number ? new $util.LongBits(message.semi_sync_primary_timeout.low >>> 0, message.semi_sync_primary_timeout.high >>> 0).toNumber(true) : message.semi_sync_primary_timeout; if (message.semi_sync_wait_for_replica_count != null && message.hasOwnProperty("semi_sync_wait_for_replica_count")) object.semi_sync_wait_for_replica_count = message.semi_sync_wait_for_replica_count; + if (message.super_read_only != null && message.hasOwnProperty("super_read_only")) + object.super_read_only = message.super_read_only; return object; }; From b07097d48bcc2c00120508f9d81ad83a7bcaa45d Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Fri, 27 Jan 2023 18:26:24 -0800 Subject: [PATCH 28/65] Code review part-1 Signed-off-by: Rameez Sajwani --- config/init_db.sql | 1 + config/init_maria_db.sql | 1 + config/init_testserver_db.sql | 1 + config/init_unit_test_db.sql | 1 + config/mycnf/mysql57.cnf | 4 ++-- config/mycnf/mysql80.cnf | 4 ++-- go/cmd/vtbackup/vtbackup.go | 2 +- .../collations/integration/helpers_test.go | 1 + .../backup/vtbackup/backup_only_test.go | 3 ++- go/test/endtoend/backup/vtbackup/main_test.go | 11 ++++++--- .../backup/vtctlbackup/backup_utils.go | 3 +++ .../recovery/unshardedrecovery/recovery.go | 3 +++ go/vt/mysqlctl/mysqld.go | 13 +++------- go/vt/sidecardb/schema/vdiff/vdiff.sql | 2 +- go/vt/vtexplain/vtexplain_vttablet.go | 7 +++--- go/vt/vttablet/tabletserver/tx_engine.go | 2 -- go/vt/vttest/environment.go | 24 ++++++++++++------- 17 files changed, 48 insertions(+), 35 deletions(-) diff --git a/config/init_db.sql b/config/init_db.sql index 76a9b27f6b0..031b889c89b 100644 --- a/config/init_db.sql +++ b/config/init_db.sql @@ -84,6 +84,7 @@ FLUSH PRIVILEGES; RESET SLAVE ALL; RESET MASTER; +# custom sql is used to add custom scripts like creating users/passwords. We use it in our tests # add custom sql here # We need to set super_read_only back to what it was before diff --git a/config/init_maria_db.sql b/config/init_maria_db.sql index e2c4d018424..4cd3744ea34 100644 --- a/config/init_maria_db.sql +++ b/config/init_maria_db.sql @@ -79,4 +79,5 @@ FLUSH PRIVILEGES; RESET SLAVE ALL; RESET MASTER; +# custom sql is used to add custom scripts like creating users/passwords. We use it in our tests # add custom sql here diff --git a/config/init_testserver_db.sql b/config/init_testserver_db.sql index 5eb2cd8c5b2..09ce6789ffa 100644 --- a/config/init_testserver_db.sql +++ b/config/init_testserver_db.sql @@ -85,4 +85,5 @@ FLUSH PRIVILEGES; RESET SLAVE ALL; RESET MASTER; +# custom sql is used to add custom scripts like creating users/passwords. We use it in our tests # add custom sql here diff --git a/config/init_unit_test_db.sql b/config/init_unit_test_db.sql index 5eb2cd8c5b2..09ce6789ffa 100644 --- a/config/init_unit_test_db.sql +++ b/config/init_unit_test_db.sql @@ -85,4 +85,5 @@ FLUSH PRIVILEGES; RESET SLAVE ALL; RESET MASTER; +# custom sql is used to add custom scripts like creating users/passwords. We use it in our tests # add custom sql here diff --git a/config/mycnf/mysql57.cnf b/config/mycnf/mysql57.cnf index d1ca819ebd4..44c462749a7 100644 --- a/config/mycnf/mysql57.cnf +++ b/config/mycnf/mysql57.cnf @@ -32,7 +32,7 @@ plugin-load = rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisy rpl_semi_sync_master_timeout = 1000000000000000000 rpl_semi_sync_master_wait_no_slave = 1 -# In order to protect against any errand GTIDs we will start mysql instance -# as super-read-only mode. +# In order to protect against any errand GTIDs we will start the mysql instance +# in super-read-only mode. super-read-only diff --git a/config/mycnf/mysql80.cnf b/config/mycnf/mysql80.cnf index 449fb465da2..13447a7de0a 100644 --- a/config/mycnf/mysql80.cnf +++ b/config/mycnf/mysql80.cnf @@ -28,7 +28,7 @@ plugin-load = rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisy loose_rpl_semi_sync_master_timeout = 1000000000000000000 loose_rpl_semi_sync_master_wait_no_slave = 1 -# In order to protect against any errand GTIDs we will start mysql instance -# as super-read-only mode. +# In order to protect against any errand GTIDs we will start the mysql instance +# in super-read-only mode. super-read-only diff --git a/go/cmd/vtbackup/vtbackup.go b/go/cmd/vtbackup/vtbackup.go index 6f5a3fcad8f..1eebc275601 100644 --- a/go/cmd/vtbackup/vtbackup.go +++ b/go/cmd/vtbackup/vtbackup.go @@ -294,7 +294,7 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back } // In initial_backup mode, just take a backup of this empty database. if initialBackup { - log.Infof("inside initialBackup creating initial binlog entry.") + log.Infof("Inside initialBackup creating initial binlog entry.") // Take a backup of this empty DB without restoring anything. // First, initialize it the way InitShardPrimary would, so this backup // produces a result that can be used to skip InitShardPrimary entirely. diff --git a/go/mysql/collations/integration/helpers_test.go b/go/mysql/collations/integration/helpers_test.go index c2601421bc2..06e6214b6cc 100644 --- a/go/mysql/collations/integration/helpers_test.go +++ b/go/mysql/collations/integration/helpers_test.go @@ -137,6 +137,7 @@ func verifyWeightString(t *testing.T, local collations.Collation, remote *remote } func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { + t.Logf("-----> %s", query) res, err := conn.ExecuteFetchWithSuperReadOnlyHandling(query, -1, true) require.NoError(t, err, "failed to execute %q: %v", query, err) diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index a9788edcc26..9e716fe5e82 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -64,6 +64,7 @@ func TestTabletInitialBackup(t *testing.T) { ver, err := getVTExecVersion("vttablet") require.NoError(t, err) + // For all version above v15, each replica will start in super-read-only mode. if ver > 15 { err := primary.VttabletProcess.CreateDB("testDB") require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") @@ -382,7 +383,7 @@ func verifyDisableEnableRedoLogs(ctx context.Context, t *testing.T, mysqlSocket } } -// insert should not work for any of the replicas and primary +// Get the version of `vttablet` in the cluster. func getVTExecVersion(binaryName string) (int, error) { vtTabletVersion := 0 vtTabletVersion, err := cluster.GetMajorVersion(binaryName) diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index af33ee4a523..30b6c9e0b2e 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -92,9 +92,12 @@ func TestMain(m *testing.M) { sql := string(initDb) // Since password update is DML we need to insert it before we disable // super-read-only therefore doing the split below. - spilltedString := strings.Split(sql, "# add custom sql here") - firstPart := spilltedString[0] + cluster.GetPasswordUpdateSQL(localCluster) - sql = firstPart + spilltedString[1] + splitString := strings.Split(sql, "# add custom sql here") + if len(splitString) < 2 { + return 1, fmt.Errorf("missing `# add custom sql here` in init_db.sql file") + } + firstPart := splitString[0] + cluster.GetPasswordUpdateSQL(localCluster) + sql = firstPart + splitString[1] newInitDBFile = path.Join(localCluster.TmpDirectory, "init_db_with_passwords.sql") err = os.WriteFile(newInitDBFile, []byte(sql), 0666) if err != nil { @@ -136,6 +139,8 @@ func TestMain(m *testing.M) { return 1, err } log.Infof("cluster.VtTabletMajorVersion: %d", vtTabletVersion) + // For downgrade / upgrade test, tablet version < 16 will not have super read only code handling + // Therefore we are explicitly setting super-read-only to `false` here. if vtTabletVersion <= 15 { for _, tablet := range []cluster.Vttablet{*primary, *replica1, *replica2} { if err := tablet.VttabletProcess.UnsetSuperReadOnly(""); err != nil { diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 4b99d397361..c4a42a0274f 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -121,6 +121,9 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp // Since password update is DML we need to insert it before we disable // super-read-only therefore doing the split below. splitString := strings.Split(sql, "# add custom sql here") + if len(splitString) < 2 { + return 1, fmt.Errorf("missing `# add custom sql here` in init_db.sql file") + } firstPart := splitString[0] + cluster.GetPasswordUpdateSQL(localCluster) sql = firstPart + splitString[1] newInitDBFile = path.Join(localCluster.TmpDirectory, "init_db_with_passwords.sql") diff --git a/go/test/endtoend/recovery/unshardedrecovery/recovery.go b/go/test/endtoend/recovery/unshardedrecovery/recovery.go index beca7f8b481..b215f5df558 100644 --- a/go/test/endtoend/recovery/unshardedrecovery/recovery.go +++ b/go/test/endtoend/recovery/unshardedrecovery/recovery.go @@ -98,6 +98,9 @@ func TestMainImpl(m *testing.M) { // Since password update is DML we need to insert it before we disable // super-read-only therefore doing the split below. splitString := strings.Split(sql, "# add custom sql here") + if len(splitString) < 2 { + return 1, fmt.Errorf("missing `# add custom sql here` in init_db.sql file") + } firstPart := splitString[0] + cluster.GetPasswordUpdateSQL(localCluster) // https://github.com/vitessio/vitess/issues/8315 diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index bb43576cfbf..040d14656d5 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -696,17 +696,10 @@ func (mysqld *Mysqld) Init(ctx context.Context, cnf *Mycnf, initDBSQLFile string return err } - log.Infof("initDBSQLFile: %s", initDBSQLFile) + log.Infof("InitDBSQLFile: %s", initDBSQLFile) if initDBSQLFile == "" { // default to built-in - if mysqld.capabilities.isMySQLLike() { - if err := mysqld.executeMysqlScript(params, strings.NewReader(config.DefaultInitDB)); err != nil { - return fmt.Errorf("failed to initialize mysqld: %v", err) - } - } else { - // it is mariaDB - if err := mysqld.executeMysqlScript(params, strings.NewReader(config.DefaultInitMariaDB)); err != nil { - return fmt.Errorf("failed to initialize mariadb mysqld: %v", err) - } + if err := mysqld.executeMysqlScript(params, strings.NewReader(config.DefaultInitDB)); err != nil { + return fmt.Errorf("failed to initialize mysqld: %v", err) } return nil } diff --git a/go/vt/sidecardb/schema/vdiff/vdiff.sql b/go/vt/sidecardb/schema/vdiff/vdiff.sql index 89252bb576e..24f5cf6e7ab 100644 --- a/go/vt/sidecardb/schema/vdiff/vdiff.sql +++ b/go/vt/sidecardb/schema/vdiff/vdiff.sql @@ -33,4 +33,4 @@ CREATE TABLE IF NOT EXISTS _vt.vdiff UNIQUE KEY `uuid_idx` (`vdiff_uuid`), KEY `state` (`state`), KEY `ks_wf_idx` (`keyspace`(64), `workflow`(64)) -) ENGINE = InnoDB \ No newline at end of file +) ENGINE = InnoDB diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 19e1f5f5d31..16b0efdb99e 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -502,10 +502,12 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* return callback(result) } + // If query is part of rejected list then return error right away. if err := t.db.GetRejectedQueryResult(query); err != nil { return err } + // If query is expected to have a specific result then return the result. if result := t.db.GetQueryResult(query); result != nil { if f := result.BeforeFunc; f != nil { f() @@ -513,6 +515,7 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* return callback(result.Result) } + // return result if query is part of defined pattern. if pat, ok := t.db.GetQueryPatternResult(query); ok { userCallback, ok := t.db.GetQueryPatternUserCallBack(pat.Expr) if ok { @@ -714,10 +717,6 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* result = &sqltypes.Result{ RowsAffected: 1, } - case sqlparser.StmtUse: - result = &sqltypes.Result{} - case sqlparser.StmtDDL: - result = &sqltypes.Result{} default: return fmt.Errorf("unsupported query %s", query) } diff --git a/go/vt/vttablet/tabletserver/tx_engine.go b/go/vt/vttablet/tabletserver/tx_engine.go index c379ef83d2f..4e1ceeeb1eb 100644 --- a/go/vt/vttablet/tabletserver/tx_engine.go +++ b/go/vt/vttablet/tabletserver/tx_engine.go @@ -19,7 +19,6 @@ package tabletserver import ( "context" "fmt" - "runtime/debug" "sync" "time" @@ -156,7 +155,6 @@ func (te *TxEngine) transition(state txEngineState) { } log.Infof("TxEngine transition: %v", state) - log.Infof("call stack: %s", debug.Stack()) switch te.state { case AcceptingReadOnly, AcceptingReadAndWrite: te.shutdownLocked() diff --git a/go/vt/vttest/environment.go b/go/vt/vttest/environment.go index 830a7316d43..182550a452e 100644 --- a/go/vt/vttest/environment.go +++ b/go/vt/vttest/environment.go @@ -24,6 +24,8 @@ import ( "strings" "time" + "vitess.io/vitess/go/vt/mysqlctl" + "vitess.io/vitess/go/vt/proto/vttest" // we use gRPC everywhere, so import the vtgate client. @@ -92,9 +94,6 @@ type Environment interface { // any temporary data in the environment. Environments that can // last through several test runs do not need to implement it. TearDown() error - - // IsSQLFlavor retruns the flavor or SQL Server running - IsSQLFlavor() bool } // LocalTestEnv is an Environment implementation for local testing @@ -149,7 +148,7 @@ func (env *LocalTestEnv) BinaryPath(binary string) string { func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLManager, error) { // maria db doesn't recognize super-read-only, therefore we have separate sql for that. var initFile = path.Join(os.Getenv("VTROOT"), "config/init_db.sql") - if !env.IsSQLFlavor() { + if isRunningMariaDB() { initFile = path.Join(os.Getenv("VTROOT"), "config/init_maria_db.sql") } return &Mysqlctl{ @@ -163,12 +162,19 @@ func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLMan }, nil } -func (env *LocalTestEnv) IsSQLFlavor() bool { - for _, val := range env.Env { - if strings.Contains(val, "MYSQL_FLAVOR=MySQL") { - return true - } +func isRunningMariaDB() bool { + mysqldVersionStr, err := mysqlctl.GetVersionString() + if err != nil { + return false } + flavor, _, err := mysqlctl.ParseVersionString(mysqldVersionStr) + if err != nil { + return false + } + if flavor == mysqlctl.FlavorMariaDB { + return true + } + return false } From 349a3023f7bc2a4302dd0a655eb50a9dfe95b351 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Sat, 28 Jan 2023 14:38:43 -0800 Subject: [PATCH 29/65] remove code for redolog in test Signed-off-by: Rameez Sajwani --- go/mysql/collations/integration/helpers_test.go | 1 - .../endtoend/backup/vtbackup/backup_only_test.go | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/go/mysql/collations/integration/helpers_test.go b/go/mysql/collations/integration/helpers_test.go index 06e6214b6cc..c2601421bc2 100644 --- a/go/mysql/collations/integration/helpers_test.go +++ b/go/mysql/collations/integration/helpers_test.go @@ -137,7 +137,6 @@ func verifyWeightString(t *testing.T, local collations.Collation, remote *remote } func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { - t.Logf("-----> %s", query) res, err := conn.ExecuteFetchWithSuperReadOnlyHandling(query, -1, true) require.NoError(t, err, "failed to execute %q: %v", query, err) diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index 9e716fe5e82..250fa09d778 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -184,21 +184,21 @@ func vtBackup(t *testing.T, initialBackup bool, restartBeforeBackup, disableRedo if restartBeforeBackup { extraArgs = append(extraArgs, "--restart_before_backup") } - ver, err := getVTExecVersion("vtbackup") + _, err = getVTExecVersion("vtbackup") require.NoError(t, err) if disableRedoLog { - if ver > 15 { - extraArgs = append(extraArgs, "--disable-redo-log") - } + //if ver > 15 { + extraArgs = append(extraArgs, "--disable-redo-log") + //} } ctx, cancel := context.WithCancel(context.Background()) defer cancel() if !initialBackup && disableRedoLog { - if ver > 15 { - go verifyDisableEnableRedoLogs(ctx, t, mysqlSocket.Name()) - } + //if ver > 15 { + go verifyDisableEnableRedoLogs(ctx, t, mysqlSocket.Name()) + //} } log.Infof("starting backup tablet %s", time.Now()) From 2a1f185984d8f8d2b349ad247c3f079c3dffb1e2 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Sun, 29 Jan 2023 00:44:19 -0800 Subject: [PATCH 30/65] fix ensureDB test Signed-off-by: Rameez Sajwani --- go/test/endtoend/tabletmanager/tablet_test.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/go/test/endtoend/tabletmanager/tablet_test.go b/go/test/endtoend/tabletmanager/tablet_test.go index c2c2a0e6b6d..233631bd536 100644 --- a/go/test/endtoend/tabletmanager/tablet_test.go +++ b/go/test/endtoend/tabletmanager/tablet_test.go @@ -43,19 +43,17 @@ func TestEnsureDB(t *testing.T) { err = clusterInstance.StartVttablet(tablet, "NOT_SERVING", false, cell, "dbtest", hostname, "0") require.NoError(t, err) - assert.Equal(t, "NOT_SERVING", tablet.VttabletProcess.GetTabletStatus()) // Make it the primary. + // primary will fail with `--read-only` since in external re-parenting we expect caller to set DB to read-write mode. err = clusterInstance.VtctlclientProcess.ExecuteCommand("TabletExternallyReparented", tablet.Alias) - require.NoError(t, err, "No error expected.") + require.EqualError(t, err, "exit status 1") - // Once promoted to primary during vschema/engine.go we change tablet to ReadWrite, hence promoting - // tablet to SERVING status. - assert.Equal(t, "SERVING", tablet.VttabletProcess.GetTabletStatus()) + // It is still NOT_SERVING because the db is read-only. + assert.Equal(t, "NOT_SERVING", tablet.VttabletProcess.GetTabletStatus()) status := tablet.VttabletProcess.GetStatusDetails() - assert.Contains(t, status, "healthy") + assert.Contains(t, status, "read-only") // Switch to read-write and verify that we go serving. - // Note: for TabletExternallyReparented, we expect SetReadWrite to be called by the user err = clusterInstance.VtctlclientProcess.ExecuteCommand("SetReadWrite", tablet.Alias) require.NoError(t, err) err = tablet.VttabletProcess.WaitForTabletStatus("SERVING") From 0a4f29e281b612c17667cdf67631174b3fc074f0 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Sun, 29 Jan 2023 18:13:35 -0800 Subject: [PATCH 31/65] code review part-2 Signed-off-by: Rameez Sajwani --- config/init_testserver_db.sql | 6 +- config/init_unit_test_db.sql | 6 +- go/cmd/vtbackup/vtbackup.go | 8 +- go/cmd/vtcombo/main.go | 1 + go/mysql/fakesqldb/server.go | 29 +++----- go/mysql/query.go | 74 +++++++------------ .../backup/vtbackup/backup_only_test.go | 4 - go/test/endtoend/backup/vtbackup/main_test.go | 2 +- go/test/endtoend/cluster/cluster_process.go | 2 +- go/test/endtoend/cluster/vttablet_process.go | 16 ++-- go/test/endtoend/vault/vault_test.go | 2 +- go/vt/mysqlctl/builtinbackupengine.go | 4 +- go/vt/mysqlctl/replication.go | 15 ++-- go/vt/vtexplain/vtexplain_vttablet.go | 11 ++- go/vt/vttablet/endtoend/main_test.go | 2 +- .../vttablet/tabletmanager/rpc_replication.go | 2 +- go/vt/vttablet/tabletmanager/tm_init.go | 2 - go/vt/vttablet/tabletserver/schema/engine.go | 1 - go/vt/vttest/local_cluster.go | 12 --- 19 files changed, 78 insertions(+), 121 deletions(-) diff --git a/config/init_testserver_db.sql b/config/init_testserver_db.sql index 09ce6789ffa..0464104a648 100644 --- a/config/init_testserver_db.sql +++ b/config/init_testserver_db.sql @@ -1,5 +1,7 @@ -# This file is executed immediately after mysql_install_db, -# to initialize a fresh data directory. +# This file is executed immediately after mysql_install_db, to initialize a fresh data +# directory. This sql is similar to init_db.sql. The only difference is, it is for +# testing purpose and specifically for vttestserver where we do not want super-read-only +# mode for mysql. It should always represent prod sql minus super-read-only. ############################################################################### # WARNING: This sql is *NOT* safe for production use, diff --git a/config/init_unit_test_db.sql b/config/init_unit_test_db.sql index 09ce6789ffa..2b450b1a47b 100644 --- a/config/init_unit_test_db.sql +++ b/config/init_unit_test_db.sql @@ -1,5 +1,7 @@ -# This file is executed immediately after mysql_install_db, -# to initialize a fresh data directory. +# This file is executed immediately after mysql_install_db, to initialize a fresh data +# directory. This sql is similar to init_db.sql. The only difference is, it is for +# testing purpose and specifically for Unit-Tests where we do not want super-read-only +# mode for mysql. It should always represent prod sql minus super-read-only. ############################################################################### # WARNING: This sql is *NOT* safe for production use, diff --git a/go/cmd/vtbackup/vtbackup.go b/go/cmd/vtbackup/vtbackup.go index 1eebc275601..e8ab7be7843 100644 --- a/go/cmd/vtbackup/vtbackup.go +++ b/go/cmd/vtbackup/vtbackup.go @@ -304,9 +304,13 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back return fmt.Errorf("can't reset replication: %v", err) } // We need to switch off super-read-only before we create database. - _ = mysqld.SetSuperReadOnly(false) + if err = mysqld.SetSuperReadOnly(false); err != nil { + return fmt.Errorf("can't turn-off super-read-only during backup: %v", err) + } defer func() { - _ = mysqld.SetSuperReadOnly(true) + if err := mysqld.SetSuperReadOnly(true); err != nil { + log.Errorf("Not able to set super-read-only during backup: %v", err) + } }() cmd := mysqlctl.GenerateInitialBinlogEntry() if err := mysqld.ExecuteSuperQueryList(ctx, []string{cmd}); err != nil { diff --git a/go/cmd/vtcombo/main.go b/go/cmd/vtcombo/main.go index 837887b192b..52cf2f0c8d2 100644 --- a/go/cmd/vtcombo/main.go +++ b/go/cmd/vtcombo/main.go @@ -190,6 +190,7 @@ func main() { servenv.Init() tabletenv.Init() + mysqld := &vtcomboMysqld{} var cnf *mysqlctl.Mycnf if *startMysql { diff --git a/go/mysql/fakesqldb/server.go b/go/mysql/fakesqldb/server.go index d9b9fe51905..e870b391f97 100644 --- a/go/mysql/fakesqldb/server.go +++ b/go/mysql/fakesqldb/server.go @@ -802,29 +802,20 @@ func (db *DB) GetQueryResult(key string) *ExpectedResult { return nil } -func (db *DB) GetQueryPatternResult(key string) (ExprResult, bool) { +func (db *DB) GetQueryPatternResult(key string) (func(string), ExpectedResult, bool, error) { for _, pat := range db.patternData { - if pat.Expr.MatchString(key) || strings.Contains(key, pat.QueryPattern) { - return pat, true - /*userCallback, ok := db.queryPatternUserCallback[pat.expr] + if pat.expr.MatchString(key) || strings.Contains(key, pat.queryPattern) { + userCallback, ok := db.queryPatternUserCallback[pat.expr] if ok { - userCallback(query) - } - if pat.err != "" { - return fmt.Errorf(pat.err) + if pat.err != "" { + return userCallback, ExpectedResult{pat.result, nil}, true, fmt.Errorf(pat.err) + } + return userCallback, ExpectedResult{pat.result, nil}, true, nil } - return callback(pat.result)*/ - } - } - - return ExprResult{}, false -} -func (db *DB) GetQueryPatternUserCallBack(exp *regexp.Regexp) (func(string), bool) { - userCallback, ok := db.queryPatternUserCallback[exp] - if ok { - return userCallback, true + return nil, ExpectedResult{nil, nil}, false, nil + } } - return nil, false + return nil, ExpectedResult{nil, nil}, false, nil } diff --git a/go/mysql/query.go b/go/mysql/query.go index 69c21b2429a..f969fd0d4eb 100644 --- a/go/mysql/query.go +++ b/go/mysql/query.go @@ -328,13 +328,13 @@ func (c *Conn) ExecuteFetchMulti(query string, maxrows int, wantfields bool) (re return res, more, err } -// ExecuteFetchWithSuperReadOnlyHandling should be used if you are executing a write query -// on a tablet that may NOT be a primary and you want to execute it regardless of -// tablet type. This function will temporarily make the mysql instance read-write and +// ExecuteFetchWithSuperReadOnlyHandling should be used if you are executing a query +// on any tablet regardless of tablet type. +// This function will temporarily make the mysql instance read-write and // re-enable read-only mode after the query is executed if needed. func (c *Conn) ExecuteFetchWithSuperReadOnlyHandling(query string, maxrows int, wantfields bool) (result *sqltypes.Result, err error) { // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ - turnSuperReadOnly := false + superReadOnlyEnabled := false if !c.IsMariaDB() { if err := c.WriteComQuery("SELECT @@global.super_read_only"); err != nil { return nil, err @@ -343,7 +343,7 @@ func (c *Conn) ExecuteFetchWithSuperReadOnlyHandling(query string, maxrows int, if err == nil && len(res.Rows) == 1 { sro := res.Rows[0][0].ToString() if sro == "1" || sro == "ON" { - turnSuperReadOnly = true + superReadOnlyEnabled = true if _, err = c.ExecuteFetch("SET GLOBAL super_read_only='OFF'", 1, false); err != nil { return nil, err } @@ -352,7 +352,8 @@ func (c *Conn) ExecuteFetchWithSuperReadOnlyHandling(query string, maxrows int, } result, _, err = c.ExecuteFetchMulti(query, maxrows, wantfields) - if turnSuperReadOnly { + // TODO: may be use it in defer() + if superReadOnlyEnabled { if _, err := c.ExecuteFetch("SET GLOBAL super_read_only='ON'", 1, false); err != nil { return nil, err } @@ -360,62 +361,37 @@ func (c *Conn) ExecuteFetchWithSuperReadOnlyHandling(query string, maxrows int, return result, err } -// ExecuteUnSetSuperReadOnly tries to set super-read-only to false only if it is currently enable -func (c *Conn) ExecuteUnSetSuperReadOnly() (result *sqltypes.Result, err error) { +// SetSuperReadOnly tries to set super-read-only either `true` or `false` +// Since setting global super-read-only is idempotent we set them with finding current status +func (c *Conn) SetSuperReadOnly(enableSuperReadOnly bool) (result *sqltypes.Result, err error) { + var val = "OFF" + if enableSuperReadOnly { + val = "ON" + } // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ if !c.IsMariaDB() { - if err := c.WriteComQuery("SELECT @@global.super_read_only"); err != nil { + query := fmt.Sprintf("SET GLOBAL super_read_only='%s'", val) + if err = c.WriteComQuery(query); err != nil { return nil, err } - res, _, _, err := c.ReadQueryResult(1, false) - if err == nil && len(res.Rows) == 1 { - sro := res.Rows[0][0].ToString() - if sro == "1" || sro == "ON" { - if err = c.WriteComQuery("SET GLOBAL super_read_only='OFF'"); err != nil { - return nil, err - } - } - } + } else { + return nil, fmt.Errorf("MariaDB not supported for super-read-only") } return result, err } -// ExecuteSetSuperReadOnly tries to set super-read-only to true only if it is currently disable -func (c *Conn) ExecuteSetSuperReadOnly() (result *sqltypes.Result, err error) { - // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ - if !c.IsMariaDB() { - if err := c.WriteComQuery("SELECT @@global.super_read_only"); err != nil { - return nil, err - } - res, _, _, err := c.ReadQueryResult(1, false) - if err == nil && len(res.Rows) == 1 { - sro := res.Rows[0][0].ToString() - if sro == "0" || sro == "OFF" { - if err = c.WriteComQuery("SET GLOBAL super_read_only='ON'"); err != nil { - return nil, err - } - } - } +// SetReadOnly tries to set read-only to false only if it is currently enable +func (c *Conn) SetReadOnly(enableReadOnly bool) (result *sqltypes.Result, err error) { + var val = "OFF" + if enableReadOnly { + val = "ON" } - return result, err -} - -// ExecuteUnSetReadOnly tries to set read-only to false only if it is currently enable -func (c *Conn) ExecuteUnSetReadOnly() (result *sqltypes.Result, err error) { - if err := c.WriteComQuery("SELECT @@global.read_only"); err != nil { + query := fmt.Sprintf("SET GLOBAL read_only='%s'", val) + if err = c.WriteComQuery(query); err != nil { return nil, err } - res, _, _, err := c.ReadQueryResult(1, false) - if err == nil && len(res.Rows) == 1 { - sro := res.Rows[0][0].ToString() - if sro == "1" || sro == "ON" { - if err = c.WriteComQuery("SET GLOBAL read_only='OFF'"); err != nil { - return nil, err - } - } - } return result, err } diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index 250fa09d778..61c16603806 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -187,18 +187,14 @@ func vtBackup(t *testing.T, initialBackup bool, restartBeforeBackup, disableRedo _, err = getVTExecVersion("vtbackup") require.NoError(t, err) if disableRedoLog { - //if ver > 15 { extraArgs = append(extraArgs, "--disable-redo-log") - //} } ctx, cancel := context.WithCancel(context.Background()) defer cancel() if !initialBackup && disableRedoLog { - //if ver > 15 { go verifyDisableEnableRedoLogs(ctx, t, mysqlSocket.Name()) - //} } log.Infof("starting backup tablet %s", time.Now()) diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index 30b6c9e0b2e..54240296fa9 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -143,7 +143,7 @@ func TestMain(m *testing.M) { // Therefore we are explicitly setting super-read-only to `false` here. if vtTabletVersion <= 15 { for _, tablet := range []cluster.Vttablet{*primary, *replica1, *replica2} { - if err := tablet.VttabletProcess.UnsetSuperReadOnly(""); err != nil { + if err := tablet.VttabletProcess.SetSuperReadOnly("", false); err != nil { return 1, err } } diff --git a/go/test/endtoend/cluster/cluster_process.go b/go/test/endtoend/cluster/cluster_process.go index 61e2a3252f5..cbc4140b904 100644 --- a/go/test/endtoend/cluster/cluster_process.go +++ b/go/test/endtoend/cluster/cluster_process.go @@ -681,7 +681,7 @@ func NewBareCluster(cell string, hostname string) *LocalProcessCluster { } else { err = createDirectory(cluster.CurrentVTDATAROOT, 0700) if err != nil { - log.Infof("err in creating file : %s", err.Error()) + log.Fatal(err) } } _ = os.Setenv("VTDATAROOT", cluster.CurrentVTDATAROOT) diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index 1300240fccf..b0f617876bd 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -636,29 +636,29 @@ func VttabletProcessInstance(port, grpcPort, tabletUID int, cell, shard, keyspac return vttablet } -// UnsetSuperReadOnly switch-off super-read-only flag in db -func (vttablet *VttabletProcess) UnsetSuperReadOnly(dbname string) error { - conn, err := vttablet.defaultConn("") +// SetSuperReadOnly switch-off super-read-only flag in db +func (vttablet *VttabletProcess) SetSuperReadOnly(dbname string, enableSuperReadOnly bool) error { + conn, err := vttablet.defaultConn(dbname) if err != nil { log.Infof("error in getting connection object %s", err) return err } defer conn.Close() - _, err = conn.ExecuteUnSetSuperReadOnly() + _, err = conn.SetSuperReadOnly(enableSuperReadOnly) return err } -// UnsetReadOnly switch-off read-only flag in db -func (vttablet *VttabletProcess) UnsetReadOnly(dbname string) error { - conn, err := vttablet.defaultConn("") +// SetReadOnly switch-off read-only flag in db +func (vttablet *VttabletProcess) SetReadOnly(dbname string, enableReadOnly bool) error { + conn, err := vttablet.defaultConn(dbname) if err != nil { log.Infof("error in getting connection object %s", err) return err } defer conn.Close() - _, err = conn.ExecuteUnSetReadOnly() + _, err = conn.SetReadOnly(enableReadOnly) return err } diff --git a/go/test/endtoend/vault/vault_test.go b/go/test/endtoend/vault/vault_test.go index dbebd66a0c4..f2c053cd7de 100644 --- a/go/test/endtoend/vault/vault_test.go +++ b/go/test/endtoend/vault/vault_test.go @@ -269,7 +269,7 @@ func initializeClusterLate(t *testing.T) { for _, tablet := range shard.Vttablets { // remove super read-only from vttablet - tablet.VttabletProcess.UnsetReadOnly("") + tablet.VttabletProcess.SetReadOnly("", false) } // TODO: Try moving this after InitPrimary. May be thats a better place. diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index 23bc42015b1..45771d64028 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -330,9 +330,9 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac // get the replication position if sourceIsPrimary { if !readOnly { - params.Logger.Infof("turning primary read-only before backup") + params.Logger.Infof("turning primary super-read-only before backup") if err = params.Mysqld.SetSuperReadOnly(true); err != nil { - return false, vterrors.Wrap(err, "can't set read-only status") + return false, vterrors.Wrap(err, "can't set super-read-only status") } } replicationPosition, err = params.Mysqld.PrimaryPosition() diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index d29bc14f235..2c086f7c7ee 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -233,16 +233,17 @@ func (mysqld *Mysqld) IsReadOnly() (bool, error) { // IsSuperReadOnly return true if the instance is super read only func (mysqld *Mysqld) IsSuperReadOnly() (bool, error) { - qr, err := mysqld.FetchSuperQuery(context.TODO(), "SHOW VARIABLES LIKE 'super_read_only'") + qr, err := mysqld.FetchSuperQuery(context.TODO(), "SELECT @@global.super_read_only") if err != nil { - return true, err - } - if len(qr.Rows) != 1 { - return true, errors.New("no super_read_only variable in mysql") + return false, err } - if qr.Rows[0][1].ToString() == "ON" { - return true, nil + if err == nil && len(qr.Rows) == 1 { + sro := qr.Rows[0][0].ToString() + if sro == "1" || sro == "ON" { + return true, nil + } } + return false, nil } diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 16b0efdb99e..0cd1838b809 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -516,15 +516,14 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* } // return result if query is part of defined pattern. - if pat, ok := t.db.GetQueryPatternResult(query); ok { - userCallback, ok := t.db.GetQueryPatternUserCallBack(pat.Expr) - if ok { + if userCallback, expResult, ok, err := t.db.GetQueryPatternResult(query); ok { + if userCallback != nil { userCallback(query) } - if pat.Err != "" { - return fmt.Errorf(pat.Err) + if err != nil { + return err } - return callback(pat.Result) + return callback(expResult.Result) } switch sqlparser.Preview(query) { diff --git a/go/vt/vttablet/endtoend/main_test.go b/go/vt/vttablet/endtoend/main_test.go index 4d9f5002635..193e0db1b21 100644 --- a/go/vt/vttablet/endtoend/main_test.go +++ b/go/vt/vttablet/endtoend/main_test.go @@ -96,7 +96,7 @@ func TestMain(m *testing.M) { fmt.Fprintf(os.Stderr, "%v", err) return 1 } - cluster.UnsetReadOnly("") + //cluster.SetReadOnly("") return m.Run() }() os.Exit(exitCode) diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index b89065bfe6c..6b8501854c8 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -112,7 +112,7 @@ func (tm *TabletManager) FullStatus(ctx context.Context) (*replicationdatapb.Ful return nil, err } - // Read only - "SHOW VARIABLES LIKE 'read_only'" + // Super read only - "SELECT @@global.super_read_only" superReadOnly, err := tm.MysqlDaemon.IsSuperReadOnly() if err != nil { return nil, err diff --git a/go/vt/vttablet/tabletmanager/tm_init.go b/go/vt/vttablet/tabletmanager/tm_init.go index 7db04e48293..c79f357a668 100644 --- a/go/vt/vttablet/tabletmanager/tm_init.go +++ b/go/vt/vttablet/tabletmanager/tm_init.go @@ -406,13 +406,11 @@ func (tm *TabletManager) Start(tablet *topodatapb.Tablet, healthCheckInterval ti // of updating the tablet state and initializing replication. return nil } - log.Infof("calling initializeReplication") // We should be re-read the tablet from tabletManager and use the type specified there. // We shouldn't use the base tablet type directly, since the type could have changed to PRIMARY // earlier in tm.checkPrimaryShip code. _, err = tm.initializeReplication(ctx, tm.Tablet().Type) tm.tmState.Open() - log.Infof("TabletManager End") return err } diff --git a/go/vt/vttablet/tabletserver/schema/engine.go b/go/vt/vttablet/tabletserver/schema/engine.go index 75f8576b59c..0f3907685ac 100644 --- a/go/vt/vttablet/tabletserver/schema/engine.go +++ b/go/vt/vttablet/tabletserver/schema/engine.go @@ -170,7 +170,6 @@ func (se *Engine) EnsureConnectionAndDB(tabletType topodatapb.TabletType) error // We use AllPrivs since syncSidecarDB() might need to upgrade the schema conn, err := dbconnpool.NewDBConnection(ctx, se.env.Config().DB.AllPrivsWithDB()) if err == nil { - log.Infof("inside EnsureConnectionAndDB with TabletType %v...", tabletType) se.dbCreationFailed = false // upgrade _vt if required, for a tablet with an existing database if tabletType == topodatapb.TabletType_PRIMARY { diff --git a/go/vt/vttest/local_cluster.go b/go/vt/vttest/local_cluster.go index f36f202ea06..88ea58187ad 100644 --- a/go/vt/vttest/local_cluster.go +++ b/go/vt/vttest/local_cluster.go @@ -748,15 +748,3 @@ func LoadSQLFile(filename, sourceroot string) ([]string, error) { return sql, nil } - -func (db *LocalCluster) UnsetReadOnly(dbname string) error { - params := db.mysql.Params(dbname) - conn, err := mysql.Connect(context.Background(), ¶ms) - if err != nil { - return err - } - defer conn.Close() - - _, err = conn.ExecuteUnSetSuperReadOnly() - return err -} From e8a9851e47454a4a0d842c89f7ac60556740a2fe Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 30 Jan 2023 00:42:35 -0800 Subject: [PATCH 32/65] Remove setSuperReadOnly checks Signed-off-by: Rameez Sajwani --- .../vttablet/tabletmanager/rpc_replication.go | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index 6b8501854c8..d75c7e7599e 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -317,14 +317,12 @@ func (tm *TabletManager) InitPrimary(ctx context.Context, semiSync bool) (string // Initializing as primary implies undoing any previous "do not replicate". tm.replManager.reset() - if setSuperReadOnly { - // Setting super_read_only off so that we can run the DDL commands - if err := tm.MysqlDaemon.SetSuperReadOnly(false); err != nil { - if strings.Contains(err.Error(), strconv.Itoa(mysql.ERUnknownSystemVariable)) { - log.Warningf("server does not know about super_read_only, continuing anyway...") - } else { - return "", err - } + // Setting super_read_only off so that we can run the DDL commands + if err := tm.MysqlDaemon.SetSuperReadOnly(false); err != nil { + if strings.Contains(err.Error(), strconv.Itoa(mysql.ERUnknownSystemVariable)) { + log.Warningf("server does not know about super_read_only, continuing anyway...") + } else { + return "", err } } @@ -484,23 +482,17 @@ func (tm *TabletManager) demotePrimary(ctx context.Context, revertPartialFailure } // Now that we know no writes are in-flight and no new writes can occur, - // set MySQL to read-only mode. If we are already read-only because of a + // set MySQL to super_read_only mode. If we are already super_read_only because of a // previous demotion, or because we are not primary anyway, this should be // idempotent. - if setSuperReadOnly { - // Setting super_read_only also sets read_only - if err := tm.MysqlDaemon.SetSuperReadOnly(true); err != nil { - if strings.Contains(err.Error(), strconv.Itoa(mysql.ERUnknownSystemVariable)) { - log.Warningf("server does not know about super_read_only, continuing anyway...") - } else { - return nil, err - } - } - } else { - if err := tm.MysqlDaemon.SetSuperReadOnly(true); err != nil { + if err := tm.MysqlDaemon.SetSuperReadOnly(true); err != nil { + if strings.Contains(err.Error(), strconv.Itoa(mysql.ERUnknownSystemVariable)) { + log.Warningf("server does not know about super_read_only, continuing anyway...") + } else { return nil, err } } + defer func() { if finalErr != nil && revertPartialFailure && !wasReadOnly { // setting read_only OFF will also set super_read_only OFF if it was set From cc37e73abe226712d5f48495e3b086e374d69fb3 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 30 Jan 2023 13:43:39 -0800 Subject: [PATCH 33/65] code review part-3 Signed-off-by: Rameez Sajwani --- config/embed.go | 3 - config/init_maria_db.sql | 83 ----------------- config/init_testserver_db.sql | 32 +++---- config/init_unit_test_db.sql | 91 ------------------- go/mysql/fakesqldb/server.go | 2 +- .../backup/vtbackup/backup_only_test.go | 23 +---- go/test/endtoend/cluster/mysqlctl_process.go | 3 +- go/test/endtoend/cluster/mysqlctld_process.go | 3 +- .../reparent/plannedreparent/reparent_test.go | 15 +-- go/vt/vttest/environment.go | 3 +- 10 files changed, 30 insertions(+), 228 deletions(-) delete mode 100644 config/init_maria_db.sql delete mode 100644 config/init_unit_test_db.sql diff --git a/config/embed.go b/config/embed.go index 56d5ac416b1..b2a9333e6de 100644 --- a/config/embed.go +++ b/config/embed.go @@ -16,6 +16,3 @@ var MycnfMySQL57 string //go:embed mycnf/mysql80.cnf var MycnfMySQL80 string - -//go:embed init_maria_db.sql -var DefaultInitMariaDB string diff --git a/config/init_maria_db.sql b/config/init_maria_db.sql deleted file mode 100644 index 4cd3744ea34..00000000000 --- a/config/init_maria_db.sql +++ /dev/null @@ -1,83 +0,0 @@ -# This file is executed immediately after mysql_install_db, -# to initialize a fresh data directory. It is mariaDB equivalent of init_db.sql. -# Since init_db.sql is for mysql which has super_read_only related stuff, and mariaDB -# does not recognize super_read_only, therefore we end up creating this file - -############################################################################### -# WARNING: This sql is *NOT* safe for production use, -# as it contains default well-known users and passwords. -# Care should be taken to change these users and passwords -# for production. -############################################################################### - -############################################################################### -# Equivalent of mysql_secure_installation -############################################################################### -# Changes during the init db should not make it to the binlog. -# They could potentially create errant transactions on replicas. -SET sql_log_bin = 0; -# Remove anonymous users. -DELETE FROM mysql.user WHERE User = ''; - -# Disable remote root access (only allow UNIX socket). -DELETE FROM mysql.user WHERE User = 'root' AND Host != 'localhost'; - -# Remove test database. -DROP DATABASE IF EXISTS test; - -############################################################################### -# Vitess defaults -############################################################################### - -# Admin user with all privileges. -CREATE USER 'vt_dba'@'localhost'; -GRANT ALL ON *.* TO 'vt_dba'@'localhost'; -GRANT GRANT OPTION ON *.* TO 'vt_dba'@'localhost'; - -# User for app traffic, with global read-write access. -CREATE USER 'vt_app'@'localhost'; -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, - REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, - LOCK TABLES, EXECUTE, REPLICATION CLIENT, CREATE VIEW, - SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER - ON *.* TO 'vt_app'@'localhost'; - -# User for app debug traffic, with global read access. -CREATE USER 'vt_appdebug'@'localhost'; -GRANT SELECT, SHOW DATABASES, PROCESS ON *.* TO 'vt_appdebug'@'localhost'; - -# User for administrative operations that need to be executed as non-SUPER. -# Same permissions as vt_app here. -CREATE USER 'vt_allprivs'@'localhost'; -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, - REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, - LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, - SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER - ON *.* TO 'vt_allprivs'@'localhost'; - -# User for slave replication connections. -CREATE USER 'vt_repl'@'%'; -GRANT REPLICATION SLAVE ON *.* TO 'vt_repl'@'%'; - -# User for Vitess VReplication (base vstreamers and vplayer). -CREATE USER 'vt_filtered'@'localhost'; -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, - REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, - LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, - SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER - ON *.* TO 'vt_filtered'@'localhost'; - -# User for general MySQL monitoring. -CREATE USER 'vt_monitoring'@'localhost'; -GRANT SELECT, PROCESS, SUPER, REPLICATION CLIENT, RELOAD - ON *.* TO 'vt_monitoring'@'localhost'; -GRANT SELECT, UPDATE, DELETE, DROP - ON performance_schema.* TO 'vt_monitoring'@'localhost'; - -FLUSH PRIVILEGES; - -RESET SLAVE ALL; -RESET MASTER; - -# custom sql is used to add custom scripts like creating users/passwords. We use it in our tests -# add custom sql here diff --git a/config/init_testserver_db.sql b/config/init_testserver_db.sql index 0464104a648..e79083e400e 100644 --- a/config/init_testserver_db.sql +++ b/config/init_testserver_db.sql @@ -1,7 +1,11 @@ -# This file is executed immediately after mysql_install_db, to initialize a fresh data -# directory. This sql is similar to init_db.sql. The only difference is, it is for -# testing purpose and specifically for vttestserver where we do not want super-read-only -# mode for mysql. It should always represent prod sql minus super-read-only. +# This file is for testing purpose only. +# This file is executed immediately after mysql_install_db, to initialize a fresh data directory. +# It is equivalent of init_db.sql. Given init_db.sql is for mysql which has super_read_only +# related stuff therefore for testing purpose we avoid setting `super_read_only` during initialization. + +############################################################################### +# WARNING: Any change to init_db.sql should gets reflected in this file as well. +############################################################################### ############################################################################### # WARNING: This sql is *NOT* safe for production use, @@ -41,9 +45,9 @@ GRANT GRANT OPTION ON *.* TO 'vt_dba'@'localhost'; # User for app traffic, with global read-write access. CREATE USER 'vt_app'@'localhost'; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, - REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION CLIENT, CREATE VIEW, - SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER ON *.* TO 'vt_app'@'localhost'; # User for app debug traffic, with global read access. @@ -54,9 +58,9 @@ GRANT SELECT, SHOW DATABASES, PROCESS ON *.* TO 'vt_appdebug'@'localhost'; # Same permissions as vt_app here. CREATE USER 'vt_allprivs'@'localhost'; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, - REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, - SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER ON *.* TO 'vt_allprivs'@'localhost'; # User for slave replication connections. @@ -66,22 +70,18 @@ GRANT REPLICATION SLAVE ON *.* TO 'vt_repl'@'%'; # User for Vitess VReplication (base vstreamers and vplayer). CREATE USER 'vt_filtered'@'localhost'; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, - REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, - SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER ON *.* TO 'vt_filtered'@'localhost'; # User for general MySQL monitoring. CREATE USER 'vt_monitoring'@'localhost'; GRANT SELECT, PROCESS, SUPER, REPLICATION CLIENT, RELOAD - ON *.* TO 'vt_monitoring'@'localhost'; + ON *.* TO 'vt_monitoring'@'localhost'; GRANT SELECT, UPDATE, DELETE, DROP - ON performance_schema.* TO 'vt_monitoring'@'localhost'; + ON performance_schema.* TO 'vt_monitoring'@'localhost'; -# User for Orchestrator (https://github.com/openark/orchestrator). -CREATE USER 'orc_client_user'@'%' IDENTIFIED BY 'orc_client_user_password'; -GRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD - ON *.* TO 'orc_client_user'@'%'; FLUSH PRIVILEGES; RESET SLAVE ALL; diff --git a/config/init_unit_test_db.sql b/config/init_unit_test_db.sql deleted file mode 100644 index 2b450b1a47b..00000000000 --- a/config/init_unit_test_db.sql +++ /dev/null @@ -1,91 +0,0 @@ -# This file is executed immediately after mysql_install_db, to initialize a fresh data -# directory. This sql is similar to init_db.sql. The only difference is, it is for -# testing purpose and specifically for Unit-Tests where we do not want super-read-only -# mode for mysql. It should always represent prod sql minus super-read-only. - -############################################################################### -# WARNING: This sql is *NOT* safe for production use, -# as it contains default well-known users and passwords. -# Care should be taken to change these users and passwords -# for production. -############################################################################### - -############################################################################### -# Equivalent of mysql_secure_installation -############################################################################### -# We need to ensure that read_only is disabled so that we can execute -# these commands. -SET GLOBAL read_only='OFF'; - -# Changes during the init db should not make it to the binlog. -# They could potentially create errant transactions on replicas. -SET sql_log_bin = 0; -# Remove anonymous users. -DELETE FROM mysql.user WHERE User = ''; - -# Disable remote root access (only allow UNIX socket). -DELETE FROM mysql.user WHERE User = 'root' AND Host != 'localhost'; - -# Remove test database. -DROP DATABASE IF EXISTS test; - -############################################################################### -# Vitess defaults -############################################################################### - -# Admin user with all privileges. -CREATE USER 'vt_dba'@'localhost'; -GRANT ALL ON *.* TO 'vt_dba'@'localhost'; -GRANT GRANT OPTION ON *.* TO 'vt_dba'@'localhost'; - -# User for app traffic, with global read-write access. -CREATE USER 'vt_app'@'localhost'; -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, - REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, - LOCK TABLES, EXECUTE, REPLICATION CLIENT, CREATE VIEW, - SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER - ON *.* TO 'vt_app'@'localhost'; - -# User for app debug traffic, with global read access. -CREATE USER 'vt_appdebug'@'localhost'; -GRANT SELECT, SHOW DATABASES, PROCESS ON *.* TO 'vt_appdebug'@'localhost'; - -# User for administrative operations that need to be executed as non-SUPER. -# Same permissions as vt_app here. -CREATE USER 'vt_allprivs'@'localhost'; -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, - REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, - LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, - SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER - ON *.* TO 'vt_allprivs'@'localhost'; - -# User for slave replication connections. -CREATE USER 'vt_repl'@'%'; -GRANT REPLICATION SLAVE ON *.* TO 'vt_repl'@'%'; - -# User for Vitess VReplication (base vstreamers and vplayer). -CREATE USER 'vt_filtered'@'localhost'; -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, - REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, - LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, - SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER - ON *.* TO 'vt_filtered'@'localhost'; - -# User for general MySQL monitoring. -CREATE USER 'vt_monitoring'@'localhost'; -GRANT SELECT, PROCESS, SUPER, REPLICATION CLIENT, RELOAD - ON *.* TO 'vt_monitoring'@'localhost'; -GRANT SELECT, UPDATE, DELETE, DROP - ON performance_schema.* TO 'vt_monitoring'@'localhost'; - -# User for Orchestrator (https://github.com/openark/orchestrator). -CREATE USER 'orc_client_user'@'%' IDENTIFIED BY 'orc_client_user_password'; -GRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD - ON *.* TO 'orc_client_user'@'%'; -FLUSH PRIVILEGES; - -RESET SLAVE ALL; -RESET MASTER; - -# custom sql is used to add custom scripts like creating users/passwords. We use it in our tests -# add custom sql here diff --git a/go/mysql/fakesqldb/server.go b/go/mysql/fakesqldb/server.go index e870b391f97..935797378c2 100644 --- a/go/mysql/fakesqldb/server.go +++ b/go/mysql/fakesqldb/server.go @@ -804,7 +804,7 @@ func (db *DB) GetQueryResult(key string) *ExpectedResult { func (db *DB) GetQueryPatternResult(key string) (func(string), ExpectedResult, bool, error) { for _, pat := range db.patternData { - if pat.expr.MatchString(key) || strings.Contains(key, pat.queryPattern) { + if pat.expr.MatchString(key) { userCallback, ok := db.queryPatternUserCallback[pat.expr] if ok { if pat.err != "" { diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index 61c16603806..a4fd4a5db65 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -62,10 +62,10 @@ func TestTabletInitialBackup(t *testing.T) { // Initialize the tablets initTablets(t, false, false) - ver, err := getVTExecVersion("vttablet") + vtTabletVersion, err := cluster.GetMajorVersion("vttablet") require.NoError(t, err) // For all version above v15, each replica will start in super-read-only mode. - if ver > 15 { + if vtTabletVersion > 15 { err := primary.VttabletProcess.CreateDB("testDB") require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") err = replica1.VttabletProcess.CreateDB("testDB") @@ -184,8 +184,6 @@ func vtBackup(t *testing.T, initialBackup bool, restartBeforeBackup, disableRedo if restartBeforeBackup { extraArgs = append(extraArgs, "--restart_before_backup") } - _, err = getVTExecVersion("vtbackup") - require.NoError(t, err) if disableRedoLog { extraArgs = append(extraArgs, "--disable-redo-log") } @@ -269,15 +267,15 @@ func restore(t *testing.T, tablet *cluster.Vttablet, tabletType string, waitForS log.Infof("restoring tablet %s", time.Now()) resetTabletDirectory(t, *tablet, true) - err := tablet.VttabletProcess.CreateDBWithSuperReadOnly(keyspaceName) - require.Nil(t, err) + //err := tablet.VttabletProcess.CreateDBWithSuperReadOnly(keyspaceName) + //require.Nil(t, err) // Start tablets tablet.VttabletProcess.ExtraArgs = []string{"--db-credentials-file", dbCredentialFile} tablet.VttabletProcess.TabletType = tabletType tablet.VttabletProcess.ServingStatus = waitForState tablet.VttabletProcess.SupportsBackup = true - err = tablet.VttabletProcess.Setup() + err := tablet.VttabletProcess.Setup() require.Nil(t, err) } @@ -378,14 +376,3 @@ func verifyDisableEnableRedoLogs(ctx context.Context, t *testing.T, mysqlSocket } } } - -// Get the version of `vttablet` in the cluster. -func getVTExecVersion(binaryName string) (int, error) { - vtTabletVersion := 0 - vtTabletVersion, err := cluster.GetMajorVersion(binaryName) - if err != nil { - return 0, err - } - log.Infof("cluster.VtTabletMajorVersion: %d", vtTabletVersion) - return vtTabletVersion, nil -} diff --git a/go/test/endtoend/cluster/mysqlctl_process.go b/go/test/endtoend/cluster/mysqlctl_process.go index f8642a32c5b..cd857d13e6a 100644 --- a/go/test/endtoend/cluster/mysqlctl_process.go +++ b/go/test/endtoend/cluster/mysqlctl_process.go @@ -240,7 +240,8 @@ func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirect var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value if isSQL, err := isSQLFlavor(); err == nil { if !isSQL { - initFile = path.Join(os.Getenv("VTROOT"), "config/init_maria_db.sql") + // execute init_db without `super_read_only` + initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") } } mysqlctl := &MysqlctlProcess{ diff --git a/go/test/endtoend/cluster/mysqlctld_process.go b/go/test/endtoend/cluster/mysqlctld_process.go index 5e05a665ac1..e111cc9f7f0 100644 --- a/go/test/endtoend/cluster/mysqlctld_process.go +++ b/go/test/endtoend/cluster/mysqlctld_process.go @@ -148,7 +148,8 @@ func MysqlCtldProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value if isSQL, err := isSQLFlavor(); err == nil { if !isSQL { - initFile = path.Join(os.Getenv("VTROOT"), "config/init_maria_db.sql") + // execute init_db without `super_read_only` + initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") } } mysqlctld := &MysqlctldProcess{ diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go index 6a476b183ed..e8afdcce75e 100644 --- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go +++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go @@ -379,10 +379,10 @@ func TestReparentDoesntHangIfPrimaryFails(t *testing.T) { // Perform a planned reparent operation, the primary will fail the // insert. The replicas should then abort right away. - ver, err := getVTExecVersion("vttablet") + vtTabletVersion, err := cluster.GetMajorVersion("vttablet") require.NoError(t, err) out, err := utils.Prs(t, clusterInstance, tablets[1]) - if ver <= 15 { + if vtTabletVersion <= 15 { require.Error(t, err) assert.Contains(t, out, "primary failed to PopulateReparentJournal") } else { @@ -559,14 +559,3 @@ func rowNumberFromPosition(pos string) int { rowNum, _ := strconv.Atoi(rowNumStr) return rowNum } - -// insert should not work for any of the replicas and primary -func getVTExecVersion(binaryName string) (int, error) { - vtTabletVersion := 0 - vtTabletVersion, err := cluster.GetMajorVersion(binaryName) - if err != nil { - return 0, err - } - log.Infof("cluster.VtTabletMajorVersion: %d", vtTabletVersion) - return vtTabletVersion, nil -} diff --git a/go/vt/vttest/environment.go b/go/vt/vttest/environment.go index 182550a452e..34ae84389ca 100644 --- a/go/vt/vttest/environment.go +++ b/go/vt/vttest/environment.go @@ -149,7 +149,8 @@ func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLMan // maria db doesn't recognize super-read-only, therefore we have separate sql for that. var initFile = path.Join(os.Getenv("VTROOT"), "config/init_db.sql") if isRunningMariaDB() { - initFile = path.Join(os.Getenv("VTROOT"), "config/init_maria_db.sql") + // execute init_db without `super_read_only` + initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") } return &Mysqlctl{ Binary: env.BinaryPath("mysqlctl"), From dac1d4692f32fa428e23da6de62d4a16ee852f75 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Tue, 31 Jan 2023 00:07:18 -0800 Subject: [PATCH 34/65] Try restoring without super_read_only Signed-off-by: Rameez Sajwani --- .../backup/vtbackup/backup_only_test.go | 4 --- go/test/endtoend/cluster/vttablet_process.go | 7 ----- .../reparent/plannedreparent/reparent_test.go | 27 ------------------- go/test/endtoend/tabletmanager/tablet_test.go | 2 +- go/vt/mysqlctl/builtinbackupengine.go | 4 ++- go/vt/mysqlctl/mysqld.go | 14 ++++++---- 6 files changed, 13 insertions(+), 45 deletions(-) diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index a4fd4a5db65..aca83fe77fe 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -263,13 +263,9 @@ func initTablets(t *testing.T, startTablet bool, initShardPrimary bool) { func restore(t *testing.T, tablet *cluster.Vttablet, tabletType string, waitForState string) { // Erase mysql/tablet dir, then start tablet with restore enabled. - log.Infof("restoring tablet %s", time.Now()) resetTabletDirectory(t, *tablet, true) - //err := tablet.VttabletProcess.CreateDBWithSuperReadOnly(keyspaceName) - //require.Nil(t, err) - // Start tablets tablet.VttabletProcess.ExtraArgs = []string{"--db-credentials-file", dbCredentialFile} tablet.VttabletProcess.TabletType = tabletType diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index b0f617876bd..9285a541e64 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -410,13 +410,6 @@ func (vttablet *VttabletProcess) CreateDB(keyspace string) error { return err } -// CreateDBWithSuperReadOnly creates the database for keyspace -func (vttablet *VttabletProcess) CreateDBWithSuperReadOnly(keyspace string) error { - _, _ = vttablet.QueryTabletWithSuperReadOnlyHandling(fmt.Sprintf("drop database IF EXISTS vt_%s", keyspace), keyspace, false) - _, err := vttablet.QueryTabletWithSuperReadOnlyHandling(fmt.Sprintf("create database IF NOT EXISTS vt_%s", keyspace), keyspace, false) - return err -} - // QueryTablet lets you execute a query in this tablet and get the result func (vttablet *VttabletProcess) QueryTablet(query string, keyspace string, useDb bool) (*sqltypes.Result, error) { if !useDb { diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go index e8afdcce75e..de7e6a0368b 100644 --- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go +++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go @@ -363,33 +363,6 @@ func TestChangeTypeSemiSync(t *testing.T) { utils.CheckDBstatus(ctx, t, rdonly2, "Rpl_semi_sync_slave_status", "ON") } -func TestReparentDoesntHangIfPrimaryFails(t *testing.T) { - //FIXME: need to rewrite this test: how? - t.Skip("since the new schema init approach will automatically heal mismatched schemas, the approach in this test doesn't work now") - defer cluster.PanicHandler(t) - clusterInstance := utils.SetupReparentCluster(t, "semi_sync") - defer utils.TeardownCluster(clusterInstance) - tablets := clusterInstance.Keyspaces[0].Shards[0].Vttablets - - // Change the schema of the _vt.reparent_journal table, so that - // inserts into it will fail. That will make the primary fail. - _, err := tablets[0].VttabletProcess.QueryTabletWithDB( - "ALTER TABLE reparent_journal DROP COLUMN replication_position", "_vt") - require.NoError(t, err) - - // Perform a planned reparent operation, the primary will fail the - // insert. The replicas should then abort right away. - vtTabletVersion, err := cluster.GetMajorVersion("vttablet") - require.NoError(t, err) - out, err := utils.Prs(t, clusterInstance, tablets[1]) - if vtTabletVersion <= 15 { - require.Error(t, err) - assert.Contains(t, out, "primary failed to PopulateReparentJournal") - } else { - require.NoError(t, err, "PRS should not fail.") - } -} - // TestCrossCellDurability tests 2 things - // 1. When PRS is run with the cross_cell durability policy setup, then the semi-sync settings on all the tablets are as expected // 2. Bringing up a new vttablet should have its replication and semi-sync setup correctly without any manual intervention diff --git a/go/test/endtoend/tabletmanager/tablet_test.go b/go/test/endtoend/tabletmanager/tablet_test.go index 233631bd536..1ac69b1726c 100644 --- a/go/test/endtoend/tabletmanager/tablet_test.go +++ b/go/test/endtoend/tabletmanager/tablet_test.go @@ -44,7 +44,7 @@ func TestEnsureDB(t *testing.T) { require.NoError(t, err) // Make it the primary. - // primary will fail with `--read-only` since in external re-parenting we expect caller to set DB to read-write mode. + // primary will fail with `--super_read-only` since in external re-parenting we expect caller to set DB to read-write mode. err = clusterInstance.VtctlclientProcess.ExecuteCommand("TabletExternallyReparented", tablet.Alias) require.EqualError(t, err, "exit status 1") diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index 45771d64028..dfdd3130b52 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -778,7 +778,7 @@ func (be *BuiltinBackupEngine) executeRestoreIncrementalBackup(ctx context.Conte func (be *BuiltinBackupEngine) ExecuteRestore(ctx context.Context, params RestoreParams, bh backupstorage.BackupHandle) (*BackupManifest, error) { var bm builtinBackupManifest - + //time.Sleep(10 * time.Second) if err := getBackupManifestInto(ctx, bh, &bm); err != nil { return nil, err } @@ -790,8 +790,10 @@ func (be *BuiltinBackupEngine) ExecuteRestore(ctx context.Context, params Restor var err error if bm.Incremental { + log.Infof("inside executeRestoreIncrementalBackup...") err = be.executeRestoreIncrementalBackup(ctx, params, bh, bm) } else { + log.Infof("inside executeRestoreIncrementalBackup...") err = be.executeRestoreFullBackup(ctx, params, bh, bm) } if err != nil { diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index 040d14656d5..cbd587e5db8 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -1218,12 +1218,16 @@ func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTID return err } args := []string{} - if gtids := includeGTIDs.String(); gtids != "" { - args = append(args, - "--include-gtids", - gtids, - ) + if includeGTIDs != nil { + log.Infof("includeGTIDs.String() are %s", includeGTIDs.String()) + if gtids := includeGTIDs.String(); gtids != "" { + args = append(args, + "--include-gtids", + gtids, + ) + } } + args = append(args, binlogFile) mysqlbinlogCmd = exec.Command(name, args...) From 36f36280ea9ef9730f0df8ee4e31ce805ede60e9 Mon Sep 17 00:00:00 2001 From: Manan Gupta Date: Tue, 31 Jan 2023 14:50:32 +0530 Subject: [PATCH 35/65] test: simplify vtorc test to not require turning off super-read-only Signed-off-by: Manan Gupta --- .../vtorc/readtopologyinstance/main_test.go | 4 ++-- go/test/endtoend/vtorc/utils/utils.go | 22 ++----------------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/go/test/endtoend/vtorc/readtopologyinstance/main_test.go b/go/test/endtoend/vtorc/readtopologyinstance/main_test.go index 872a1fcdc87..9b51cc2d1e8 100644 --- a/go/test/endtoend/vtorc/readtopologyinstance/main_test.go +++ b/go/test/endtoend/vtorc/readtopologyinstance/main_test.go @@ -105,7 +105,7 @@ func TestReadTopologyInstanceBufferable(t *testing.T) { assert.Equal(t, primaryInstance.ReplicationSQLThreadState, inst.ReplicationThreadStateNoThread) // insert an errant GTID in the replica - _, err = utils.RunSQLWithSuperReadOnly(t, "insert into vt_insert_test(id, msg) values (10173, 'test 178342')", replica, "vt_ks", true) + _, err = utils.RunSQL(t, `set global gtid_purged='12345678-1234-1234-1234-123456789012:1'`, replica, "") require.NoError(t, err) replicaInstance, err := inst.ReadTopologyInstanceBufferable(&inst.InstanceKey{ @@ -136,7 +136,7 @@ func TestReadTopologyInstanceBufferable(t *testing.T) { assert.EqualValues(t, 1000000000000000000, replicaInstance.SemiSyncPrimaryTimeout) assert.NotEmpty(t, replicaInstance.ExecutedGtidSet) assert.Contains(t, replicaInstance.ExecutedGtidSet, primaryInstance.ServerUUID) - assert.Empty(t, replicaInstance.GtidPurged) + assert.Equal(t, "12345678-1234-1234-1234-123456789012:1", replicaInstance.GtidPurged) assert.Regexp(t, ".{8}-.{4}-.{4}-.{4}-.{12}:.*", replicaInstance.GtidErrant) assert.True(t, replicaInstance.HasReplicationCredentials) assert.Equal(t, replicaInstance.ReplicationIOThreadState, inst.ReplicationThreadStateRunning) diff --git a/go/test/endtoend/vtorc/utils/utils.go b/go/test/endtoend/vtorc/utils/utils.go index 9bb75cb723b..d4f23c0de70 100644 --- a/go/test/endtoend/vtorc/utils/utils.go +++ b/go/test/endtoend/vtorc/utils/utils.go @@ -582,29 +582,11 @@ func RunSQL(t *testing.T, sql string, tablet *cluster.Vttablet, db string) (*sql defer conn.Close() // RunSQL - return RunSQLWithSuperReadOnly(t, sql, tablet, db, false) + return execute(t, conn, sql) } -// RunSQLWithSuperReadOnly is used to run a SQL statement on the given tablet with super read only set to true or false -func RunSQLWithSuperReadOnly(t *testing.T, sql string, tablet *cluster.Vttablet, db string, withSuperReadOnly bool) (*sqltypes.Result, error) { - // Get Connection - tabletParams := getMysqlConnParam(tablet, db) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - conn, err := mysql.Connect(ctx, &tabletParams) - require.Nil(t, err) - defer conn.Close() - - // RunSQL - return execute(t, conn, sql, withSuperReadOnly) -} - -func execute(t *testing.T, conn *mysql.Conn, query string, withSuperReadOnly bool) (*sqltypes.Result, error) { +func execute(t *testing.T, conn *mysql.Conn, query string) (*sqltypes.Result, error) { t.Helper() - if withSuperReadOnly { - return conn.ExecuteFetchWithSuperReadOnlyHandling(query, 1000, true) - } - return conn.ExecuteFetch(query, 1000, true) } From d94f977bf7114c7a3ef546fa48f3385ea053c43b Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 1 Feb 2023 00:20:45 -0800 Subject: [PATCH 36/65] code review part-4 Signed-off-by: Rameez Sajwani --- go/cmd/vtbackup/vtbackup.go | 16 ++++--- go/vt/mysqlctl/backup.go | 13 +++++- go/vt/mysqlctl/builtinbackupengine.go | 13 ++++-- .../fakemysqldaemon/fakemysqldaemon.go | 4 +- go/vt/mysqlctl/mysql_daemon.go | 2 +- go/vt/mysqlctl/mysqld.go | 13 +++++- go/vt/mysqlctl/replication.go | 46 +++++++++++++++++-- .../vttablet/tabletmanager/rpc_replication.go | 4 +- 8 files changed, 88 insertions(+), 23 deletions(-) diff --git a/go/cmd/vtbackup/vtbackup.go b/go/cmd/vtbackup/vtbackup.go index e8ab7be7843..de67f24925f 100644 --- a/go/cmd/vtbackup/vtbackup.go +++ b/go/cmd/vtbackup/vtbackup.go @@ -304,14 +304,18 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back return fmt.Errorf("can't reset replication: %v", err) } // We need to switch off super-read-only before we create database. - if err = mysqld.SetSuperReadOnly(false); err != nil { + resetFunc, err := mysqld.SetSuperReadOnly(false) + if err != nil { return fmt.Errorf("can't turn-off super-read-only during backup: %v", err) } - defer func() { - if err := mysqld.SetSuperReadOnly(true); err != nil { - log.Errorf("Not able to set super-read-only during backup: %v", err) - } - }() + if resetFunc != nil { + defer func() { + err := resetFunc() + if err != nil { + log.Info("not able to set super_read_only to its original value during backup") + } + }() + } cmd := mysqlctl.GenerateInitialBinlogEntry() if err := mysqld.ExecuteSuperQueryList(ctx, []string{cmd}); err != nil { return err diff --git a/go/vt/mysqlctl/backup.go b/go/vt/mysqlctl/backup.go index 4a7781c1be9..88ccbddddbf 100644 --- a/go/vt/mysqlctl/backup.go +++ b/go/vt/mysqlctl/backup.go @@ -350,14 +350,23 @@ func Restore(ctx context.Context, params RestoreParams) (*BackupManifest, error) // this will fail on MariaDB, which doesn't have super_read_only // This is safe, since we're restarting MySQL after the restore anyway params.Logger.Infof("Restore: disabling super_read_only") - if err := params.Mysqld.SetSuperReadOnly(false); err != nil { + resetFunc, err := params.Mysqld.SetSuperReadOnly(false) + if err != nil { if strings.Contains(err.Error(), strconv.Itoa(mysql.ERUnknownSystemVariable)) { - params.Logger.Warningf("Restore: server does not know about super_read_only, continuing anyway...") + params.Logger.Warningf("Restore: server does not know about super_read_only, continuing anyway.") } else { params.Logger.Errorf("Restore: unexpected error while trying to set super_read_only: %v", err) return nil, err } } + if resetFunc != nil { + defer func() { + err := resetFunc() + if err != nil { + params.Logger.Errorf("Not able to set super_read_only to its original value during restore.") + } + }() + } params.Logger.Infof("Restore: running mysql_upgrade") if err := params.Mysqld.RunMysqlUpgrade(); err != nil { diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index dfdd3130b52..34d9fe8316d 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -324,14 +324,19 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac // get the read-only flag readOnly, err = params.Mysqld.IsReadOnly() if err != nil { - return false, vterrors.Wrap(err, "can't get read-only status") + return false, vterrors.Wrap(err, "can't get read_only status") } + sReadOnly, err := params.Mysqld.IsSuperReadOnly() + if err != nil { + return false, vterrors.Wrap(err, "can't get super_read_only status") + } + log.Infof("Flag values during full backup, read_only: %v, super_read_only:%v", readOnly, sReadOnly) // get the replication position if sourceIsPrimary { if !readOnly { params.Logger.Infof("turning primary super-read-only before backup") - if err = params.Mysqld.SetSuperReadOnly(true); err != nil { + if _, err = params.Mysqld.SetSuperReadOnly(true); err != nil { return false, vterrors.Wrap(err, "can't set super-read-only status") } } @@ -391,7 +396,7 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac return usable, err } } else { - if err := params.Mysqld.SetSuperReadOnly(readOnly); err != nil { + if _, err := params.Mysqld.SetSuperReadOnly(readOnly); err != nil { return usable, err } } @@ -793,7 +798,7 @@ func (be *BuiltinBackupEngine) ExecuteRestore(ctx context.Context, params Restor log.Infof("inside executeRestoreIncrementalBackup...") err = be.executeRestoreIncrementalBackup(ctx, params, bh, bm) } else { - log.Infof("inside executeRestoreIncrementalBackup...") + log.Infof("inside executeRestoreFullBackup...") err = be.executeRestoreFullBackup(ctx, params, bh, bm) } if err != nil { diff --git a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go index ff478693d73..0fb2a96a59f 100644 --- a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go +++ b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go @@ -378,10 +378,10 @@ func (fmd *FakeMysqlDaemon) SetReadOnly(on bool) error { } // SetSuperReadOnly is part of the MysqlDaemon interface -func (fmd *FakeMysqlDaemon) SetSuperReadOnly(on bool) error { +func (fmd *FakeMysqlDaemon) SetSuperReadOnly(on bool) (mysqlctl.ResetSuperReadOnlyFunc, error) { fmd.SuperReadOnly = on fmd.ReadOnly = on - return nil + return nil, nil } // StartReplication is part of the MysqlDaemon interface. diff --git a/go/vt/mysqlctl/mysql_daemon.go b/go/vt/mysqlctl/mysql_daemon.go index f88dce2cf30..18929eb86c0 100644 --- a/go/vt/mysqlctl/mysql_daemon.go +++ b/go/vt/mysqlctl/mysql_daemon.go @@ -74,7 +74,7 @@ type MysqlDaemon interface { IsReadOnly() (bool, error) IsSuperReadOnly() (bool, error) SetReadOnly(on bool) error - SetSuperReadOnly(on bool) error + SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) SetReplicationPosition(ctx context.Context, pos mysql.Position) error SetReplicationSource(ctx context.Context, host string, port int, stopReplicationBefore bool, startReplicationAfter bool) error WaitForReparentJournal(ctx context.Context, timeCreatedNS int64) error diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index cbd587e5db8..3938dafd3ab 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -1260,8 +1260,9 @@ func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTID // We disable super_read_only, in case it is in the default MySQL startup // parameters. We do it blindly, since this will fail on MariaDB, which doesn't // have super_read_only This is safe, since we're restarting MySQL after the restore anyway - log.Infof("Restore: disabling super_read_only") - if err := mysqld.SetSuperReadOnly(false); err != nil { + log.Infof("applyBinlogFile: disabling super_read_only") + resetFunc, err := mysqld.SetSuperReadOnly(false) + if err != nil { if strings.Contains(err.Error(), strconv.Itoa(mysql.ERUnknownSystemVariable)) { log.Warningf("Restore: server does not know about super_read_only, continuing anyway...") } else { @@ -1269,6 +1270,14 @@ func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTID return err } } + if resetFunc != nil { + defer func() { + err := resetFunc() + if err != nil { + log.Error("Not able to set super_read_only to its original value during applyBinlogFile.") + } + }() + } mysqlCmd = exec.Command(name, args...) mysqlCmd.Dir = dir diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index 2c086f7c7ee..5b1601914f9 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -38,6 +38,8 @@ import ( "vitess.io/vitess/go/vt/log" ) +type ResetSuperReadOnlyFunc func() error + // WaitForReplicationStart waits until the deadline for replication to start. // This validates the current primary is correct and can be connected to. func WaitForReplicationStart(mysqld MysqlDaemon, replicaStartDeadline int) error { @@ -270,14 +272,50 @@ func (mysqld *Mysqld) SetReadOnly(on bool) error { } // SetSuperReadOnly set/unset the super_read_only flag -func (mysqld *Mysqld) SetSuperReadOnly(on bool) error { +func (mysqld *Mysqld) SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) { + // return function for switching `OFF` super_read_only + var returnFunc ResetSuperReadOnlyFunc + var resetFunc = func() error { + query := "SET GLOBAL super_read_only = 'OFF'" + err := mysqld.ExecuteSuperQuery(context.TODO(), query) + return err + } + + // return function for switching `ON` super_read_only + var setFunc = func() error { + query := "SET GLOBAL super_read_only = 'ON'" + err := mysqld.ExecuteSuperQuery(context.TODO(), query) + return err + } + + //var err error = nil + superReadOnlyEnabled, err := mysqld.IsSuperReadOnly() + if err != nil { + return nil, err + } + + // if non-idempotent then set the right call-back + if on && !superReadOnlyEnabled { + returnFunc = resetFunc + } + if !on && superReadOnlyEnabled { + returnFunc = setFunc + } + query := "SET GLOBAL super_read_only = " if on { - query += "ON" + query += "'ON'" } else { - query += "OFF" + query += "'OFF'q" } - return mysqld.ExecuteSuperQuery(context.TODO(), query) + if err := mysqld.ExecuteSuperQuery(context.TODO(), query); err != nil { + return nil, err + } + if superReadOnlyEnabled { + return returnFunc, nil + } + + return nil, nil } // WaitSourcePos lets replicas wait to given replication position diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index d75c7e7599e..a6d8d408ae2 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -318,7 +318,7 @@ func (tm *TabletManager) InitPrimary(ctx context.Context, semiSync bool) (string tm.replManager.reset() // Setting super_read_only off so that we can run the DDL commands - if err := tm.MysqlDaemon.SetSuperReadOnly(false); err != nil { + if _, err := tm.MysqlDaemon.SetSuperReadOnly(false); err != nil { if strings.Contains(err.Error(), strconv.Itoa(mysql.ERUnknownSystemVariable)) { log.Warningf("server does not know about super_read_only, continuing anyway...") } else { @@ -485,7 +485,7 @@ func (tm *TabletManager) demotePrimary(ctx context.Context, revertPartialFailure // set MySQL to super_read_only mode. If we are already super_read_only because of a // previous demotion, or because we are not primary anyway, this should be // idempotent. - if err := tm.MysqlDaemon.SetSuperReadOnly(true); err != nil { + if _, err := tm.MysqlDaemon.SetSuperReadOnly(true); err != nil { if strings.Contains(err.Error(), strconv.Itoa(mysql.ERUnknownSystemVariable)) { log.Warningf("server does not know about super_read_only, continuing anyway...") } else { From e31ec3159208bf4f4c8fb273977f94a44862e383 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 1 Feb 2023 08:43:16 -0800 Subject: [PATCH 37/65] Fixing typo Signed-off-by: Rameez Sajwani --- go/vt/mysqlctl/replication.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index 5b1601914f9..02ad605fd80 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -306,7 +306,7 @@ func (mysqld *Mysqld) SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) if on { query += "'ON'" } else { - query += "'OFF'q" + query += "'OFF'" } if err := mysqld.ExecuteSuperQuery(context.TODO(), query); err != nil { return nil, err From 5b32fd40fba63455ce6430b8108847d03d92ffe4 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 1 Feb 2023 16:38:14 -0800 Subject: [PATCH 38/65] code review part-5 Signed-off-by: Rameez Sajwani --- .../backup/vtbackup/backup_only_test.go | 46 +++++++++++++++++-- .../recovery/pitr/shardedpitr_test.go | 1 + go/test/endtoend/vault/vault_test.go | 11 ++--- go/vt/vtexplain/vtexplain_vttablet.go | 5 +- go/vt/vttablet/endtoend/main_test.go | 1 - 5 files changed, 47 insertions(+), 17 deletions(-) diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index aca83fe77fe..a69828d1947 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -18,6 +18,7 @@ package vtbackup import ( "context" + "encoding/json" "fmt" "os" "path" @@ -299,6 +300,11 @@ func resetTabletDirectory(t *testing.T, tablet cluster.Vttablet, initMysql bool) func tearDown(t *testing.T, initMysql bool) { // reset replication + for _, db := range []string{"_vt", "vt_insert_test"} { + _, err := primary.VttabletProcess.QueryTablet(fmt.Sprintf("drop database if exists %s", db), keyspaceName, true) + require.Nil(t, err) + } + waitForReplicationToCatchup([]cluster.Vttablet{*replica1, *replica2}) promoteCommands := "STOP SLAVE; RESET SLAVE ALL; RESET MASTER;" disableSemiSyncCommands := "SET GLOBAL rpl_semi_sync_master_enabled = false; SET GLOBAL rpl_semi_sync_slave_enabled = false" for _, tablet := range []cluster.Vttablet{*primary, *replica1, *replica2} { @@ -306,10 +312,6 @@ func tearDown(t *testing.T, initMysql bool) { require.Nil(t, err) _, err = tablet.VttabletProcess.QueryTablet(disableSemiSyncCommands, keyspaceName, true) require.Nil(t, err) - for _, db := range []string{"_vt", "vt_insert_test"} { - _, err = tablet.VttabletProcess.QueryTabletWithSuperReadOnlyHandling(fmt.Sprintf("drop database if exists %s", db), keyspaceName, true) - require.Nil(t, err) - } } // TODO: Ideally we should not be resetting the mysql. @@ -372,3 +374,39 @@ func verifyDisableEnableRedoLogs(ctx context.Context, t *testing.T, mysqlSocket } } } + +// This helper function wait for all replicas to catch-up the replication. +// It does this by querying the status detail url of each replica and find the lag. +func waitForReplicationToCatchup(tablets []cluster.Vttablet) bool { + endTime := time.Now().Add(time.Second * 30) + timeout := time.After(time.Until(endTime)) + // key-value structure returned by status url. + type kv struct { + Key string + Class string + Value string + } + // defining a struct instance + var statuslst []kv + for { + select { + case <-timeout: + return false + default: + var replicaCount = 0 + for _, tablet := range tablets { + status := tablet.VttabletProcess.GetStatusDetails() + json.Unmarshal([]byte(status), &statuslst) + for _, obj := range statuslst { + if obj.Key == "Replication Lag" && obj.Value == "0s" { + replicaCount++ + } + } + if replicaCount == len(tablets) { + return true + } + } + time.Sleep(time.Second * 1) + } + } +} diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go index 295c5afbc4f..fdb6259e168 100644 --- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go +++ b/go/test/endtoend/recovery/pitr/shardedpitr_test.go @@ -446,6 +446,7 @@ func initializeCluster(t *testing.T) { "FLUSH PRIVILEGES;", } + // Executing these queries with super_read_only since these are additional DMLs outside init_db.sql for _, shard := range clusterInstance.Keyspaces[0].Shards { for _, tablet := range shard.Vttablets { diff --git a/go/test/endtoend/vault/vault_test.go b/go/test/endtoend/vault/vault_test.go index f2c053cd7de..fc7712f9932 100644 --- a/go/test/endtoend/vault/vault_test.go +++ b/go/test/endtoend/vault/vault_test.go @@ -267,21 +267,16 @@ func initializeClusterLate(t *testing.T) { require.NoError(t, err) } - for _, tablet := range shard.Vttablets { - // remove super read-only from vttablet - tablet.VttabletProcess.SetReadOnly("", false) - } - - // TODO: Try moving this after InitPrimary. May be thats a better place. + // TODO: may be put them in init_db at runtime, then we don't need superReadOnly handling for _, tablet := range []*cluster.Vttablet{primary, replica} { for _, user := range mysqlUsers { query := fmt.Sprintf("ALTER USER '%s'@'%s' IDENTIFIED BY '%s';", user, hostname, mysqlPassword) - _, err = tablet.VttabletProcess.QueryTablet(query, keyspace.Name, false) + _, err = tablet.VttabletProcess.QueryTabletWithSuperReadOnlyHandling(query, keyspace.Name, false) // Reset after the first ALTER, or we lock ourselves out. tablet.VttabletProcess.DbPassword = mysqlPassword if err != nil { query = fmt.Sprintf("ALTER USER '%s'@'%%' IDENTIFIED BY '%s';", user, mysqlPassword) - _, err = tablet.VttabletProcess.QueryTablet(query, keyspace.Name, false) + _, err = tablet.VttabletProcess.QueryTabletWithSuperReadOnlyHandling(query, keyspace.Name, false) require.NoError(t, err) } } diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 0cd1838b809..3f64562209b 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -494,10 +494,7 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* // return the pre-computed results for any schema introspection queries tEnv := t.vte.getGlobalTabletEnv() result := tEnv.getResult(query) - emptyResult := &sqltypes.Result{} - if sidecardb.MatchesInitQuery(query) { - return callback(emptyResult) - } + if result != nil { return callback(result) } diff --git a/go/vt/vttablet/endtoend/main_test.go b/go/vt/vttablet/endtoend/main_test.go index 193e0db1b21..1f6bffa1699 100644 --- a/go/vt/vttablet/endtoend/main_test.go +++ b/go/vt/vttablet/endtoend/main_test.go @@ -96,7 +96,6 @@ func TestMain(m *testing.M) { fmt.Fprintf(os.Stderr, "%v", err) return 1 } - //cluster.SetReadOnly("") return m.Run() }() os.Exit(exitCode) From 272814fce2a2953cc5abe29d28e6b0e9e57cd83c Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Thu, 2 Feb 2023 11:45:42 -0800 Subject: [PATCH 39/65] clean up some code Signed-off-by: Rameez Sajwani --- go/vt/mysqlctl/backup.go | 26 -------------------------- go/vt/mysqlctl/builtinbackupengine.go | 25 +++++++++++-------------- go/vt/mysqlctl/mysqld.go | 13 +++++-------- 3 files changed, 16 insertions(+), 48 deletions(-) diff --git a/go/vt/mysqlctl/backup.go b/go/vt/mysqlctl/backup.go index 88ccbddddbf..8be2602069f 100644 --- a/go/vt/mysqlctl/backup.go +++ b/go/vt/mysqlctl/backup.go @@ -21,7 +21,6 @@ import ( "fmt" "os" "path/filepath" - "strconv" "strings" "time" @@ -31,7 +30,6 @@ import ( "context" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/stats" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/mysqlctl/backupstorage" @@ -344,30 +342,6 @@ func Restore(ctx context.Context, params RestoreParams) (*BackupManifest, error) return nil, err } - // We disable super_read_only, in case it is in the default MySQL startup - // parameters and will be blocking the writes we need to do in - // PopulateMetadataTables(). We do it blindly, since - // this will fail on MariaDB, which doesn't have super_read_only - // This is safe, since we're restarting MySQL after the restore anyway - params.Logger.Infof("Restore: disabling super_read_only") - resetFunc, err := params.Mysqld.SetSuperReadOnly(false) - if err != nil { - if strings.Contains(err.Error(), strconv.Itoa(mysql.ERUnknownSystemVariable)) { - params.Logger.Warningf("Restore: server does not know about super_read_only, continuing anyway.") - } else { - params.Logger.Errorf("Restore: unexpected error while trying to set super_read_only: %v", err) - return nil, err - } - } - if resetFunc != nil { - defer func() { - err := resetFunc() - if err != nil { - params.Logger.Errorf("Not able to set super_read_only to its original value during restore.") - } - }() - } - params.Logger.Infof("Restore: running mysql_upgrade") if err := params.Mysqld.RunMysqlUpgrade(); err != nil { return nil, vterrors.Wrap(err, "mysql_upgrade failed") diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index 34d9fe8316d..1a7795a5d7a 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -304,8 +304,9 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac // Save initial state so we can restore. replicaStartRequired := false sourceIsPrimary := false - readOnly := true //nolint + superReadOnly := true //nolint var replicationPosition mysql.Position + var resetSuperReadOnlyFunc ResetSuperReadOnlyFunc semiSyncSource, semiSyncReplica := params.Mysqld.SemiSyncEnabled() // See if we need to restart replication after backup. @@ -322,21 +323,21 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac } // get the read-only flag - readOnly, err = params.Mysqld.IsReadOnly() + readOnly, err := params.Mysqld.IsReadOnly() if err != nil { return false, vterrors.Wrap(err, "can't get read_only status") } - sReadOnly, err := params.Mysqld.IsSuperReadOnly() + superReadOnly, err = params.Mysqld.IsSuperReadOnly() if err != nil { return false, vterrors.Wrap(err, "can't get super_read_only status") } - log.Infof("Flag values during full backup, read_only: %v, super_read_only:%v", readOnly, sReadOnly) + log.Infof("Flag values during full backup, read_only: %v, super_read_only:%v", readOnly, superReadOnly) // get the replication position if sourceIsPrimary { - if !readOnly { + if !superReadOnly { params.Logger.Infof("turning primary super-read-only before backup") - if _, err = params.Mysqld.SetSuperReadOnly(true); err != nil { + if resetSuperReadOnlyFunc, err = params.Mysqld.SetSuperReadOnly(true); err != nil { return false, vterrors.Wrap(err, "can't set super-read-only status") } } @@ -390,14 +391,10 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac } // And set read-only mode - params.Logger.Infof("resetting mysqld read-only to %v", readOnly) - if !readOnly { - if err := params.Mysqld.SetReadOnly(readOnly); err != nil { - return usable, err - } - } else { - if _, err := params.Mysqld.SetSuperReadOnly(readOnly); err != nil { - return usable, err + if resetSuperReadOnlyFunc != nil { + err := resetSuperReadOnlyFunc() + if err != nil { + log.Info("not able to set super_read_only to its original value during backup") } } diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index 3938dafd3ab..f3f36e7aa14 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -1218,14 +1218,11 @@ func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTID return err } args := []string{} - if includeGTIDs != nil { - log.Infof("includeGTIDs.String() are %s", includeGTIDs.String()) - if gtids := includeGTIDs.String(); gtids != "" { - args = append(args, - "--include-gtids", - gtids, - ) - } + if gtids := includeGTIDs.String(); gtids != "" { + args = append(args, + "--include-gtids", + gtids, + ) } args = append(args, binlogFile) From fd9df61a4b1bbb1359eac37f432ada870c14ce31 Mon Sep 17 00:00:00 2001 From: Manan Gupta Date: Thu, 2 Feb 2023 22:30:41 +0530 Subject: [PATCH 40/65] test: fix vtorc test Signed-off-by: Manan Gupta --- .../vtorc/readtopologyinstance/main_test.go | 18 +++++++++++++++--- go/test/endtoend/vtorc/utils/utils.go | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/go/test/endtoend/vtorc/readtopologyinstance/main_test.go b/go/test/endtoend/vtorc/readtopologyinstance/main_test.go index 9b51cc2d1e8..e7ae4385aab 100644 --- a/go/test/endtoend/vtorc/readtopologyinstance/main_test.go +++ b/go/test/endtoend/vtorc/readtopologyinstance/main_test.go @@ -27,6 +27,7 @@ import ( "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/vtorc/config" "vitess.io/vitess/go/vt/vtorc/inst" + "vitess.io/vitess/go/vt/vtorc/logic" "vitess.io/vitess/go/vt/vtorc/server" _ "github.com/go-sql-driver/mysql" @@ -104,8 +105,19 @@ func TestReadTopologyInstanceBufferable(t *testing.T) { assert.Equal(t, primaryInstance.ReplicationIOThreadState, inst.ReplicationThreadStateNoThread) assert.Equal(t, primaryInstance.ReplicationSQLThreadState, inst.ReplicationThreadStateNoThread) - // insert an errant GTID in the replica - _, err = utils.RunSQL(t, `set global gtid_purged='12345678-1234-1234-1234-123456789012:1'`, replica, "") + // Insert an errant GTID in the replica + // The way to do this is to disable global recoveries, stop replication and inject an errant GTID. + // After this we restart the replication and enable the recoveries again. + err = logic.DisableRecovery() + require.NoError(t, err) + err = utils.RunSQLs(t, []string{`STOP SLAVE;`, + `SET GTID_NEXT="12345678-1234-1234-1234-123456789012:1";`, + `BEGIN;`, `COMMIT;`, + `SET GTID_NEXT="AUTOMATIC";`, + `START SLAVE;`, + }, replica, "") + require.NoError(t, err) + err = logic.EnableRecovery() require.NoError(t, err) replicaInstance, err := inst.ReadTopologyInstanceBufferable(&inst.InstanceKey{ @@ -136,7 +148,7 @@ func TestReadTopologyInstanceBufferable(t *testing.T) { assert.EqualValues(t, 1000000000000000000, replicaInstance.SemiSyncPrimaryTimeout) assert.NotEmpty(t, replicaInstance.ExecutedGtidSet) assert.Contains(t, replicaInstance.ExecutedGtidSet, primaryInstance.ServerUUID) - assert.Equal(t, "12345678-1234-1234-1234-123456789012:1", replicaInstance.GtidPurged) + assert.Empty(t, replicaInstance.GtidPurged) assert.Regexp(t, ".{8}-.{4}-.{4}-.{4}-.{12}:.*", replicaInstance.GtidErrant) assert.True(t, replicaInstance.HasReplicationCredentials) assert.Equal(t, replicaInstance.ReplicationIOThreadState, inst.ReplicationThreadStateRunning) diff --git a/go/test/endtoend/vtorc/utils/utils.go b/go/test/endtoend/vtorc/utils/utils.go index d4f23c0de70..ebc04fd8fa6 100644 --- a/go/test/endtoend/vtorc/utils/utils.go +++ b/go/test/endtoend/vtorc/utils/utils.go @@ -585,6 +585,25 @@ func RunSQL(t *testing.T, sql string, tablet *cluster.Vttablet, db string) (*sql return execute(t, conn, sql) } +// RunSQLs is used to run a list of SQL statements on the given tablet +func RunSQLs(t *testing.T, sqls []string, tablet *cluster.Vttablet, db string) error { + // Get Connection + tabletParams := getMysqlConnParam(tablet, db) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + conn, err := mysql.Connect(ctx, &tabletParams) + require.Nil(t, err) + defer conn.Close() + + // Run SQLs + for _, sql := range sqls { + if _, err := execute(t, conn, sql); err != nil { + return err + } + } + return nil +} + func execute(t *testing.T, conn *mysql.Conn, query string) (*sqltypes.Result, error) { t.Helper() return conn.ExecuteFetch(query, 1000, true) From 89c1b4be3a3848a39f7f67e9e917ba4ed0d31df0 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Thu, 2 Feb 2023 15:43:33 -0800 Subject: [PATCH 41/65] Code clean up - part 2 Signed-off-by: Rameez Sajwani --- go/test/endtoend/backup/vtbackup/main_test.go | 14 ++++---- go/vt/mysqlctl/builtinbackupengine.go | 1 - go/vt/vttablet/endtoend/main_test.go | 2 +- go/vt/vttest/local_cluster.go | 32 ++----------------- 4 files changed, 10 insertions(+), 39 deletions(-) diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index 7bc605ebf3c..920ccb92d15 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -141,13 +141,13 @@ func TestMain(m *testing.M) { log.Infof("cluster.VtTabletMajorVersion: %d", vtTabletVersion) // For downgrade / upgrade test, tablet version < 16 will not have super read only code handling // Therefore we are explicitly setting super-read-only to `false` here. - if vtTabletVersion <= 15 { - for _, tablet := range []cluster.Vttablet{*primary, *replica1, *replica2} { - if err := tablet.VttabletProcess.SetSuperReadOnly("", false); err != nil { - return 1, err - } - } - } + //if vtTabletVersion <= 15 { + //for _, tablet := range []cluster.Vttablet{*primary, *replica1, *replica2} { + // if err := tablet.VttabletProcess.SetSuperReadOnly("", false); err != nil { + // return 1, err + // } + //} + //} if localCluster.VtTabletMajorVersion >= 16 { // If vttablets are any lower than version 16, then they are running the replication manager. diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index 1a7795a5d7a..f1bba6a0dce 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -780,7 +780,6 @@ func (be *BuiltinBackupEngine) executeRestoreIncrementalBackup(ctx context.Conte func (be *BuiltinBackupEngine) ExecuteRestore(ctx context.Context, params RestoreParams, bh backupstorage.BackupHandle) (*BackupManifest, error) { var bm builtinBackupManifest - //time.Sleep(10 * time.Second) if err := getBackupManifestInto(ctx, bh, &bm); err != nil { return nil, err } diff --git a/go/vt/vttablet/endtoend/main_test.go b/go/vt/vttablet/endtoend/main_test.go index 1f6bffa1699..a809e7e42ae 100644 --- a/go/vt/vttablet/endtoend/main_test.go +++ b/go/vt/vttablet/endtoend/main_test.go @@ -75,7 +75,7 @@ func TestMain(m *testing.M) { fmt.Fprintf(os.Stderr, "could not launch mysql: %v\n", err) return 1 } - err := cluster.ExecuteWithSuperReadOnly(procSQL, "vttest") + err := cluster.Execute(procSQL, "vttest") if err != nil { fmt.Fprintf(os.Stderr, "%v", err) return 1 diff --git a/go/vt/vttest/local_cluster.go b/go/vt/vttest/local_cluster.go index 88ea58187ad..3d954de860d 100644 --- a/go/vt/vttest/local_cluster.go +++ b/go/vt/vttest/local_cluster.go @@ -483,7 +483,7 @@ func (db *LocalCluster) loadSchema(shouldRunDatabaseMigrations bool) error { } for _, dbname := range db.shardNames(kpb) { - if err := db.ExecuteWithSuperReadOnly(cmds, dbname); err != nil { + if err := db.Execute(cmds, dbname); err != nil { return err } } @@ -533,7 +533,7 @@ func (db *LocalCluster) createDatabases() error { sql = append(sql, fmt.Sprintf("create database `%s`", dbname)) } } - return db.ExecuteWithSuperReadOnly(sql, "") + return db.Execute(sql, "") } // Execute runs a series of SQL statements on the MySQL instance backing @@ -564,34 +564,6 @@ func (db *LocalCluster) Execute(sql []string, dbname string) error { return err } -// ExecuteWithSuperReadOnly runs a series of SQL statements with super-read-only permission -// on the MySQL instance backing this local cluster. This is provided for debug/introspection purposes; -// normal cluster access should be performed through the Vitess GRPC interface. -func (db *LocalCluster) ExecuteWithSuperReadOnly(sql []string, dbname string) error { - params := db.mysql.Params(dbname) - conn, err := mysql.Connect(context.Background(), ¶ms) - if err != nil { - return err - } - defer conn.Close() - - _, err = conn.ExecuteFetch("START TRANSACTION", 0, false) - if err != nil { - return err - } - - for _, cmd := range sql { - log.Infof("Execute(%s): \"%s\"", dbname, cmd) - _, err := conn.ExecuteFetchWithSuperReadOnlyHandling(cmd, 0, false) - if err != nil { - return err - } - } - - _, err = conn.ExecuteFetch("COMMIT", 0, false) - return err -} - // Query runs a SQL query on the MySQL instance backing this local cluster and returns // its result. This is provided for debug/introspection purposes; // normal cluster access should be performed through the Vitess GRPC interface. From 8e158e26881a7600d906abb37d4a849bd8334322 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Thu, 2 Feb 2023 18:15:59 -0800 Subject: [PATCH 42/65] Adding summary Signed-off-by: Rameez Sajwani --- doc/releasenotes/17_0_0_summary.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 doc/releasenotes/17_0_0_summary.md diff --git a/doc/releasenotes/17_0_0_summary.md b/doc/releasenotes/17_0_0_summary.md new file mode 100644 index 00000000000..7ff59430fe0 --- /dev/null +++ b/doc/releasenotes/17_0_0_summary.md @@ -0,0 +1,17 @@ +## Summary + +- [New command line flags and behavior](#new-command-line-flags-and-behavior) + +## Known Issues + +## Major Changes + +### New command line flags and behavior + +#### VTTablet: Initializing all replica DB with super_read_only +In order to prevent SUPER privileged users like `root` or `vt_dba` to produce errant GTIDs anywhere anytime, all the replica DBs are initialized with the Mysql +global variable `super_read_only` value set to `ON`. During re-parenting, we set `super_read_only` to `OFF` for the promoted primary tablet. This will allow the +primary to accept writes. All replica except the primary will still have their global variable `super_read_only` set to `ON`. This will make sure that apart from +the replication no other component or offline system can mutate replica DB resulting in errant GTIDs that are then lying in wait to cause later failures. + +Reference PR for this change is [PR #12206](https://github.com/vitessio/vitess/pull/12206) From b81b354e407775a873956513d8f8156f2d99496b Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 6 Feb 2023 11:57:13 -0800 Subject: [PATCH 43/65] code cleanup Signed-off-by: Rameez Sajwani --- go/test/endtoend/backup/vtbackup/main_test.go | 9 --------- go/vt/mysqlctl/builtinbackupengine.go | 2 -- 2 files changed, 11 deletions(-) diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index 920ccb92d15..36dbbe11ffe 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -139,15 +139,6 @@ func TestMain(m *testing.M) { return 1, err } log.Infof("cluster.VtTabletMajorVersion: %d", vtTabletVersion) - // For downgrade / upgrade test, tablet version < 16 will not have super read only code handling - // Therefore we are explicitly setting super-read-only to `false` here. - //if vtTabletVersion <= 15 { - //for _, tablet := range []cluster.Vttablet{*primary, *replica1, *replica2} { - // if err := tablet.VttabletProcess.SetSuperReadOnly("", false); err != nil { - // return 1, err - // } - //} - //} if localCluster.VtTabletMajorVersion >= 16 { // If vttablets are any lower than version 16, then they are running the replication manager. diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index f1bba6a0dce..da146c42a7a 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -791,10 +791,8 @@ func (be *BuiltinBackupEngine) ExecuteRestore(ctx context.Context, params Restor var err error if bm.Incremental { - log.Infof("inside executeRestoreIncrementalBackup...") err = be.executeRestoreIncrementalBackup(ctx, params, bh, bm) } else { - log.Infof("inside executeRestoreFullBackup...") err = be.executeRestoreFullBackup(ctx, params, bh, bm) } if err != nil { From 7fe7a89aa387f5aa934f742f529de91b31aed9fe Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Sat, 11 Feb 2023 00:39:46 -0800 Subject: [PATCH 44/65] Removing init_testserver to test its dependenciesy Signed-off-by: Rameez Sajwani --- go/test/endtoend/cluster/mysqlctl_process.go | 4 ++-- go/test/endtoend/cluster/mysqlctld_process.go | 4 ++-- go/vt/dbconfigs/dbconfigs.go | 4 ++-- go/vt/vttest/environment.go | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go/test/endtoend/cluster/mysqlctl_process.go b/go/test/endtoend/cluster/mysqlctl_process.go index cd857d13e6a..03067e16c43 100644 --- a/go/test/endtoend/cluster/mysqlctl_process.go +++ b/go/test/endtoend/cluster/mysqlctl_process.go @@ -238,12 +238,12 @@ func (mysqlctl *MysqlctlProcess) Connect(ctx context.Context, username string) ( // configured with the given Config. func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirectory string, initMySQL bool) *MysqlctlProcess { var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value - if isSQL, err := isSQLFlavor(); err == nil { + /*if isSQL, err := isSQLFlavor(); err == nil { if !isSQL { // execute init_db without `super_read_only` initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") } - } + }*/ mysqlctl := &MysqlctlProcess{ Name: "mysqlctl", Binary: "mysqlctl", diff --git a/go/test/endtoend/cluster/mysqlctld_process.go b/go/test/endtoend/cluster/mysqlctld_process.go index e111cc9f7f0..4a71816d3f4 100644 --- a/go/test/endtoend/cluster/mysqlctld_process.go +++ b/go/test/endtoend/cluster/mysqlctld_process.go @@ -146,12 +146,12 @@ func (mysqlctld *MysqlctldProcess) CleanupFiles(tabletUID int) { // configured with the given Config. func MysqlCtldProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) *MysqlctldProcess { var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value - if isSQL, err := isSQLFlavor(); err == nil { + /*if isSQL, err := isSQLFlavor(); err == nil { if !isSQL { // execute init_db without `super_read_only` initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") } - } + }*/ mysqlctld := &MysqlctldProcess{ Name: "mysqlctld", Binary: "mysqlctld", diff --git a/go/vt/dbconfigs/dbconfigs.go b/go/vt/dbconfigs/dbconfigs.go index cfcbf19ad9e..7d2d8c0ba0b 100644 --- a/go/vt/dbconfigs/dbconfigs.go +++ b/go/vt/dbconfigs/dbconfigs.go @@ -216,12 +216,12 @@ func (dbcfgs *DBConfigs) AppDebugWithDB() Connector { return dbcfgs.makeParams(&dbcfgs.appdebugParams, true) } -// AllPrivsConnector returns connection parameters for all privileges with no dbname set. +// AllPrivsConnector returns connection parameters for allPrivs with no dbname set. func (dbcfgs *DBConfigs) AllPrivsConnector() Connector { return dbcfgs.makeParams(&dbcfgs.allprivsParams, false) } -// AllPrivsWithDB returns connection parameters for all privileges with dbname set. +// AllPrivsWithDB returns connection parameters for allPrivs with dbname set. func (dbcfgs *DBConfigs) AllPrivsWithDB() Connector { return dbcfgs.makeParams(&dbcfgs.allprivsParams, true) } diff --git a/go/vt/vttest/environment.go b/go/vt/vttest/environment.go index 34ae84389ca..ea423a488a4 100644 --- a/go/vt/vttest/environment.go +++ b/go/vt/vttest/environment.go @@ -148,10 +148,10 @@ func (env *LocalTestEnv) BinaryPath(binary string) string { func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLManager, error) { // maria db doesn't recognize super-read-only, therefore we have separate sql for that. var initFile = path.Join(os.Getenv("VTROOT"), "config/init_db.sql") - if isRunningMariaDB() { + /*if isRunningMariaDB() { // execute init_db without `super_read_only` initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") - } + }*/ return &Mysqlctl{ Binary: env.BinaryPath("mysqlctl"), InitFile: initFile, From 402b4490759f160341b961b744b2914bf4c7c3f5 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Sat, 11 Feb 2023 15:07:12 -0800 Subject: [PATCH 45/65] fixing downgrade/upgrade and bringing back mariadb check Signed-off-by: Rameez Sajwani --- go/test/endtoend/backup/vtbackup/backup_only_test.go | 2 +- go/test/endtoend/cluster/mysqlctl_process.go | 4 ++-- go/test/endtoend/cluster/mysqlctld_process.go | 4 ++-- go/vt/mysqlctl/mysqld.go | 3 ++- go/vt/vttest/environment.go | 4 ++-- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index a69828d1947..4e09e3ab250 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -66,7 +66,7 @@ func TestTabletInitialBackup(t *testing.T) { vtTabletVersion, err := cluster.GetMajorVersion("vttablet") require.NoError(t, err) // For all version above v15, each replica will start in super-read-only mode. - if vtTabletVersion > 15 { + if vtTabletVersion > 16 { err := primary.VttabletProcess.CreateDB("testDB") require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") err = replica1.VttabletProcess.CreateDB("testDB") diff --git a/go/test/endtoend/cluster/mysqlctl_process.go b/go/test/endtoend/cluster/mysqlctl_process.go index 03067e16c43..cd857d13e6a 100644 --- a/go/test/endtoend/cluster/mysqlctl_process.go +++ b/go/test/endtoend/cluster/mysqlctl_process.go @@ -238,12 +238,12 @@ func (mysqlctl *MysqlctlProcess) Connect(ctx context.Context, username string) ( // configured with the given Config. func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirectory string, initMySQL bool) *MysqlctlProcess { var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value - /*if isSQL, err := isSQLFlavor(); err == nil { + if isSQL, err := isSQLFlavor(); err == nil { if !isSQL { // execute init_db without `super_read_only` initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") } - }*/ + } mysqlctl := &MysqlctlProcess{ Name: "mysqlctl", Binary: "mysqlctl", diff --git a/go/test/endtoend/cluster/mysqlctld_process.go b/go/test/endtoend/cluster/mysqlctld_process.go index 4a71816d3f4..e111cc9f7f0 100644 --- a/go/test/endtoend/cluster/mysqlctld_process.go +++ b/go/test/endtoend/cluster/mysqlctld_process.go @@ -146,12 +146,12 @@ func (mysqlctld *MysqlctldProcess) CleanupFiles(tabletUID int) { // configured with the given Config. func MysqlCtldProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) *MysqlctldProcess { var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value - /*if isSQL, err := isSQLFlavor(); err == nil { + if isSQL, err := isSQLFlavor(); err == nil { if !isSQL { // execute init_db without `super_read_only` initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") } - }*/ + } mysqlctld := &MysqlctldProcess{ Name: "mysqlctld", Binary: "mysqlctld", diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index 11cceabc879..56bdcf63efa 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -35,6 +35,7 @@ import ( "path" "path/filepath" "regexp" + "runtime/debug" "strconv" "strings" "sync" @@ -696,7 +697,7 @@ func (mysqld *Mysqld) Init(ctx context.Context, cnf *Mycnf, initDBSQLFile string return err } - log.Infof("InitDBSQLFile: %s", initDBSQLFile) + log.Infof("InitDBSQLFile: %s %s", initDBSQLFile, debug.Stack()) if initDBSQLFile == "" { // default to built-in if err := mysqld.executeMysqlScript(params, strings.NewReader(config.DefaultInitDB)); err != nil { return fmt.Errorf("failed to initialize mysqld: %v", err) diff --git a/go/vt/vttest/environment.go b/go/vt/vttest/environment.go index ea423a488a4..34ae84389ca 100644 --- a/go/vt/vttest/environment.go +++ b/go/vt/vttest/environment.go @@ -148,10 +148,10 @@ func (env *LocalTestEnv) BinaryPath(binary string) string { func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLManager, error) { // maria db doesn't recognize super-read-only, therefore we have separate sql for that. var initFile = path.Join(os.Getenv("VTROOT"), "config/init_db.sql") - /*if isRunningMariaDB() { + if isRunningMariaDB() { // execute init_db without `super_read_only` initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") - }*/ + } return &Mysqlctl{ Binary: env.BinaryPath("mysqlctl"), InitFile: initFile, From 3d1435d0da038954957f5e4ee0f21daa908ac0a5 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Sat, 11 Feb 2023 16:42:35 -0800 Subject: [PATCH 46/65] Removing mariadb check from vttest Signed-off-by: Rameez Sajwani --- go/vt/vttest/environment.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/vttest/environment.go b/go/vt/vttest/environment.go index 34ae84389ca..ea423a488a4 100644 --- a/go/vt/vttest/environment.go +++ b/go/vt/vttest/environment.go @@ -148,10 +148,10 @@ func (env *LocalTestEnv) BinaryPath(binary string) string { func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLManager, error) { // maria db doesn't recognize super-read-only, therefore we have separate sql for that. var initFile = path.Join(os.Getenv("VTROOT"), "config/init_db.sql") - if isRunningMariaDB() { + /*if isRunningMariaDB() { // execute init_db without `super_read_only` initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") - } + }*/ return &Mysqlctl{ Binary: env.BinaryPath("mysqlctl"), InitFile: initFile, From 8997da5946ca17bdd65ad3c503c16c3d5216e833 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Sat, 11 Feb 2023 20:41:35 -0800 Subject: [PATCH 47/65] deprecating `use_super_read_only` flag Signed-off-by: Rameez Sajwani --- go/flags/endtoend/vttablet.txt | 1 - go/test/endtoend/cluster/vttablet_process.go | 26 ------------------- go/test/endtoend/tabletmanager/tablet_test.go | 2 +- .../vttablet/tabletmanager/rpc_replication.go | 4 +-- go/vt/vttablet/tabletmanager/tm_init.go | 15 ++++++----- 5 files changed, 11 insertions(+), 37 deletions(-) diff --git a/go/flags/endtoend/vttablet.txt b/go/flags/endtoend/vttablet.txt index ab125542eb4..82ff98f98c9 100644 --- a/go/flags/endtoend/vttablet.txt +++ b/go/flags/endtoend/vttablet.txt @@ -347,7 +347,6 @@ Usage of vttablet: --tx_throttler_config string The configuration of the transaction throttler as a text formatted throttlerdata.Configuration protocol buffer message (default "target_replication_lag_sec: 2\nmax_replication_lag_sec: 10\ninitial_rate: 100\nmax_increase: 1\nemergency_decrease: 0.5\nmin_duration_between_increases_sec: 40\nmax_duration_between_increases_sec: 62\nmin_duration_between_decreases_sec: 20\nspread_backlog_across_sec: 20\nage_bad_rate_after_sec: 180\nbad_rate_increase: 0.1\nmax_rate_approach_threshold: 0.9\n") --tx_throttler_healthcheck_cells strings A comma-separated list of cells. Only tabletservers running in these cells will be monitored for replication lag by the transaction throttler. --unhealthy_threshold duration replication lag after which a replica is considered unhealthy (default 2h0m0s) - --use_super_read_only Set super_read_only flag when performing planned failover. (default true) --v Level log level for V logs -v, --version print binary version --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index 9285a541e64..4347a072a2a 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -629,32 +629,6 @@ func VttabletProcessInstance(port, grpcPort, tabletUID int, cell, shard, keyspac return vttablet } -// SetSuperReadOnly switch-off super-read-only flag in db -func (vttablet *VttabletProcess) SetSuperReadOnly(dbname string, enableSuperReadOnly bool) error { - conn, err := vttablet.defaultConn(dbname) - if err != nil { - log.Infof("error in getting connection object %s", err) - return err - } - defer conn.Close() - - _, err = conn.SetSuperReadOnly(enableSuperReadOnly) - return err -} - -// SetReadOnly switch-off read-only flag in db -func (vttablet *VttabletProcess) SetReadOnly(dbname string, enableReadOnly bool) error { - conn, err := vttablet.defaultConn(dbname) - if err != nil { - log.Infof("error in getting connection object %s", err) - return err - } - defer conn.Close() - - _, err = conn.SetReadOnly(enableReadOnly) - return err -} - // QueryTabletWithSuperReadOnlyHandling lets you execute a query in this tablet while disabling super-read-only and get the result // It will enable super-read-only once its done executing the query. func (vttablet *VttabletProcess) QueryTabletWithSuperReadOnlyHandling(query string, keyspace string, useDb bool) (*sqltypes.Result, error) { diff --git a/go/test/endtoend/tabletmanager/tablet_test.go b/go/test/endtoend/tabletmanager/tablet_test.go index 1ac69b1726c..3c597e97981 100644 --- a/go/test/endtoend/tabletmanager/tablet_test.go +++ b/go/test/endtoend/tabletmanager/tablet_test.go @@ -44,7 +44,6 @@ func TestEnsureDB(t *testing.T) { require.NoError(t, err) // Make it the primary. - // primary will fail with `--super_read-only` since in external re-parenting we expect caller to set DB to read-write mode. err = clusterInstance.VtctlclientProcess.ExecuteCommand("TabletExternallyReparented", tablet.Alias) require.EqualError(t, err, "exit status 1") @@ -54,6 +53,7 @@ func TestEnsureDB(t *testing.T) { assert.Contains(t, status, "read-only") // Switch to read-write and verify that we go serving. + // Note: for TabletExternallyReparented, we expect SetReadWrite to be called by the user err = clusterInstance.VtctlclientProcess.ExecuteCommand("SetReadWrite", tablet.Alias) require.NoError(t, err) err = tablet.VttabletProcess.WaitForTabletStatus("SERVING") diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index 0f99ca8c421..6d7db9fd5cf 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -37,11 +37,11 @@ import ( topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) -var setSuperReadOnly = true var disableReplicationManager bool func registerReplicationFlags(fs *pflag.FlagSet) { - fs.BoolVar(&setSuperReadOnly, "use_super_read_only", setSuperReadOnly, "Set super_read_only flag when performing planned failover.") + fs.Bool("use_super_read_only", true, "Set super_read_only flag when performing planned failover.") + fs.MarkDeprecated("use_super_read_only", "From v17 onwards MySQL server will always starts as super_read_only=`true`") fs.BoolVar(&disableReplicationManager, "disable-replication-manager", disableReplicationManager, "Disable replication manager to prevent replication repairs.") fs.MarkDeprecated("disable-replication-manager", "Replication manager is deleted") } diff --git a/go/vt/vttablet/tabletmanager/tm_init.go b/go/vt/vttablet/tabletmanager/tm_init.go index 0f697586029..8b9e2ffb0ef 100644 --- a/go/vt/vttablet/tabletmanager/tm_init.go +++ b/go/vt/vttablet/tabletmanager/tm_init.go @@ -76,13 +76,14 @@ const denyListQueryList string = "DenyListQueryRules" var ( // The following flags initialize the tablet record. - tabletHostname string - initKeyspace string - initShard string - initTabletType string - initDbNameOverride string - skipBuildInfoTags = "/.*/" - initTags flagutil.StringMapValue + tabletHostname string + initKeyspace string + initShard string + initTabletType string + initDbNameOverride string + skipBuildInfoTags = "/.*/" + initTags flagutil.StringMapValue + initPopulateMetadata bool initTimeout = 1 * time.Minute ) From 85568798cee1052e561c97f59e680c2ca317db33 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Sun, 12 Feb 2023 22:40:38 -0800 Subject: [PATCH 48/65] Modify FullStatus test Signed-off-by: Rameez Sajwani --- go/test/endtoend/reparent/plannedreparent/reparent_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go index de7e6a0368b..adb22f9bf04 100644 --- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go +++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go @@ -427,6 +427,7 @@ func TestFullStatus(t *testing.T) { assert.Contains(t, primaryStatus.PrimaryStatus.String(), "vt-0000000101-bin") assert.Equal(t, primaryStatus.GtidPurged, "MySQL56/") assert.False(t, primaryStatus.ReadOnly) + assert.False(t, primaryStatus.SuperReadOnly) assert.True(t, primaryStatus.SemiSyncPrimaryEnabled) assert.True(t, primaryStatus.SemiSyncReplicaEnabled) assert.True(t, primaryStatus.SemiSyncPrimaryStatus) @@ -479,6 +480,7 @@ func TestFullStatus(t *testing.T) { assert.Contains(t, replicaStatus.PrimaryStatus.String(), "vt-0000000102-bin") assert.Equal(t, replicaStatus.GtidPurged, "MySQL56/") assert.True(t, replicaStatus.ReadOnly) + assert.True(t, replicaStatus.SuperReadOnly) assert.False(t, replicaStatus.SemiSyncPrimaryEnabled) assert.True(t, replicaStatus.SemiSyncReplicaEnabled) assert.False(t, replicaStatus.SemiSyncPrimaryStatus) From 12ddd1776a9111146538f0a43e803c8fb9f179a3 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 13 Feb 2023 11:35:51 -0800 Subject: [PATCH 49/65] code clean-up Signed-off-by: Rameez Sajwani --- .../collations/integration/helpers_test.go | 2 +- go/test/endtoend/backup/vtbackup/main_test.go | 5 ----- go/vt/vtexplain/vtexplain_test.go | 7 +++--- go/vt/vttest/environment.go | 22 ------------------- 4 files changed, 4 insertions(+), 32 deletions(-) diff --git a/go/mysql/collations/integration/helpers_test.go b/go/mysql/collations/integration/helpers_test.go index c2601421bc2..d185168d9d1 100644 --- a/go/mysql/collations/integration/helpers_test.go +++ b/go/mysql/collations/integration/helpers_test.go @@ -137,7 +137,7 @@ func verifyWeightString(t *testing.T, local collations.Collation, remote *remote } func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { - res, err := conn.ExecuteFetchWithSuperReadOnlyHandling(query, -1, true) + res, err := conn.ExecuteFetch(query, -1, true) require.NoError(t, err, "failed to execute %q: %v", query, err) return res diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index 36dbbe11ffe..9f7bf844c98 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -134,11 +134,6 @@ func TestMain(m *testing.M) { return 1, err } } - vtTabletVersion, err := cluster.GetMajorVersion("vttablet") - if err != nil { - return 1, err - } - log.Infof("cluster.VtTabletMajorVersion: %d", vtTabletVersion) if localCluster.VtTabletMajorVersion >= 16 { // If vttablets are any lower than version 16, then they are running the replication manager. diff --git a/go/vt/vtexplain/vtexplain_test.go b/go/vt/vtexplain/vtexplain_test.go index 256f9be048d..3ba417778da 100644 --- a/go/vt/vtexplain/vtexplain_test.go +++ b/go/vt/vtexplain/vtexplain_test.go @@ -24,16 +24,15 @@ import ( "strings" "testing" - querypb "vitess.io/vitess/go/vt/proto/query" - - "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv/tabletenvtest" - "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv/tabletenvtest" + + querypb "vitess.io/vitess/go/vt/proto/query" ) func defaultTestOpts() *Options { diff --git a/go/vt/vttest/environment.go b/go/vt/vttest/environment.go index ea423a488a4..b5349a09ebe 100644 --- a/go/vt/vttest/environment.go +++ b/go/vt/vttest/environment.go @@ -24,8 +24,6 @@ import ( "strings" "time" - "vitess.io/vitess/go/vt/mysqlctl" - "vitess.io/vitess/go/vt/proto/vttest" // we use gRPC everywhere, so import the vtgate client. @@ -148,10 +146,6 @@ func (env *LocalTestEnv) BinaryPath(binary string) string { func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLManager, error) { // maria db doesn't recognize super-read-only, therefore we have separate sql for that. var initFile = path.Join(os.Getenv("VTROOT"), "config/init_db.sql") - /*if isRunningMariaDB() { - // execute init_db without `super_read_only` - initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") - }*/ return &Mysqlctl{ Binary: env.BinaryPath("mysqlctl"), InitFile: initFile, @@ -163,22 +157,6 @@ func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLMan }, nil } -func isRunningMariaDB() bool { - mysqldVersionStr, err := mysqlctl.GetVersionString() - if err != nil { - return false - } - flavor, _, err := mysqlctl.ParseVersionString(mysqldVersionStr) - if err != nil { - return false - } - if flavor == mysqlctl.FlavorMariaDB { - return true - } - - return false -} - // TopoManager implements TopoManager for LocalTestEnv func (env *LocalTestEnv) TopoManager(topoImplementation, topoServerAddress, topoRoot string, topology *vttest.VTTestTopology) TopoManager { return &Topoctl{ From d4e9ef1e595587f933d5c978546df9968c351e5e Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 13 Feb 2023 13:50:30 -0800 Subject: [PATCH 50/65] code cleanup - part 2 Signed-off-by: Rameez Sajwani --- go/mysql/query.go | 35 ------------------- .../reparent/plannedreparent/reparent_test.go | 12 +++++-- go/vt/vttest/environment.go | 4 +-- 3 files changed, 11 insertions(+), 40 deletions(-) diff --git a/go/mysql/query.go b/go/mysql/query.go index f969fd0d4eb..58ab33789bd 100644 --- a/go/mysql/query.go +++ b/go/mysql/query.go @@ -361,41 +361,6 @@ func (c *Conn) ExecuteFetchWithSuperReadOnlyHandling(query string, maxrows int, return result, err } -// SetSuperReadOnly tries to set super-read-only either `true` or `false` -// Since setting global super-read-only is idempotent we set them with finding current status -func (c *Conn) SetSuperReadOnly(enableSuperReadOnly bool) (result *sqltypes.Result, err error) { - var val = "OFF" - if enableSuperReadOnly { - val = "ON" - } - // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ - if !c.IsMariaDB() { - query := fmt.Sprintf("SET GLOBAL super_read_only='%s'", val) - if err = c.WriteComQuery(query); err != nil { - return nil, err - } - } else { - return nil, fmt.Errorf("MariaDB not supported for super-read-only") - } - - return result, err -} - -// SetReadOnly tries to set read-only to false only if it is currently enable -func (c *Conn) SetReadOnly(enableReadOnly bool) (result *sqltypes.Result, err error) { - var val = "OFF" - if enableReadOnly { - val = "ON" - } - - query := fmt.Sprintf("SET GLOBAL read_only='%s'", val) - if err = c.WriteComQuery(query); err != nil { - return nil, err - } - - return result, err -} - // ExecuteFetchWithWarningCount is for fetching results and a warning count // Note: In a future iteration this should be abolished and merged into the // ExecuteFetch API. diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go index adb22f9bf04..055f423fa09 100644 --- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go +++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go @@ -427,7 +427,12 @@ func TestFullStatus(t *testing.T) { assert.Contains(t, primaryStatus.PrimaryStatus.String(), "vt-0000000101-bin") assert.Equal(t, primaryStatus.GtidPurged, "MySQL56/") assert.False(t, primaryStatus.ReadOnly) - assert.False(t, primaryStatus.SuperReadOnly) + vtTabletVersion, err := cluster.GetMajorVersion("vttablet") + require.NoError(t, err) + // For all version above v15, each replica will start in super-read-only mode. + if vtTabletVersion > 16 { + assert.False(t, primaryStatus.SuperReadOnly) + } assert.True(t, primaryStatus.SemiSyncPrimaryEnabled) assert.True(t, primaryStatus.SemiSyncReplicaEnabled) assert.True(t, primaryStatus.SemiSyncPrimaryStatus) @@ -480,7 +485,10 @@ func TestFullStatus(t *testing.T) { assert.Contains(t, replicaStatus.PrimaryStatus.String(), "vt-0000000102-bin") assert.Equal(t, replicaStatus.GtidPurged, "MySQL56/") assert.True(t, replicaStatus.ReadOnly) - assert.True(t, replicaStatus.SuperReadOnly) + // For all version above v15, each replica will start in super-read-only mode. + if vtTabletVersion > 16 { + assert.True(t, replicaStatus.SuperReadOnly) + } assert.False(t, replicaStatus.SemiSyncPrimaryEnabled) assert.True(t, replicaStatus.SemiSyncReplicaEnabled) assert.False(t, replicaStatus.SemiSyncPrimaryStatus) diff --git a/go/vt/vttest/environment.go b/go/vt/vttest/environment.go index b5349a09ebe..f58d9d48944 100644 --- a/go/vt/vttest/environment.go +++ b/go/vt/vttest/environment.go @@ -144,11 +144,9 @@ func (env *LocalTestEnv) BinaryPath(binary string) string { // MySQLManager implements MySQLManager for LocalTestEnv func (env *LocalTestEnv) MySQLManager(mycnf []string, snapshot string) (MySQLManager, error) { - // maria db doesn't recognize super-read-only, therefore we have separate sql for that. - var initFile = path.Join(os.Getenv("VTROOT"), "config/init_db.sql") return &Mysqlctl{ Binary: env.BinaryPath("mysqlctl"), - InitFile: initFile, + InitFile: path.Join(os.Getenv("VTROOT"), "config/init_db.sql"), Directory: env.TmpPath, Port: env.PortForProtocol("mysql", ""), MyCnf: append(env.DefaultMyCnf, mycnf...), From 5c5ca78cb26016891acd41d5c4eb4f8a4002a27f Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 13 Feb 2023 17:08:08 -0800 Subject: [PATCH 51/65] fixing fullstatus test Signed-off-by: Rameez Sajwani --- go/test/endtoend/reparent/plannedreparent/reparent_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go index 055f423fa09..0a2b606e4f2 100644 --- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go +++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go @@ -429,8 +429,10 @@ func TestFullStatus(t *testing.T) { assert.False(t, primaryStatus.ReadOnly) vtTabletVersion, err := cluster.GetMajorVersion("vttablet") require.NoError(t, err) + vtcltlVersion, err := cluster.GetMajorVersion("vtctl") + require.NoError(t, err) // For all version above v15, each replica will start in super-read-only mode. - if vtTabletVersion > 16 { + if vtTabletVersion > 16 && vtcltlVersion > 16 { assert.False(t, primaryStatus.SuperReadOnly) } assert.True(t, primaryStatus.SemiSyncPrimaryEnabled) @@ -486,7 +488,7 @@ func TestFullStatus(t *testing.T) { assert.Equal(t, replicaStatus.GtidPurged, "MySQL56/") assert.True(t, replicaStatus.ReadOnly) // For all version above v15, each replica will start in super-read-only mode. - if vtTabletVersion > 16 { + if vtTabletVersion > 16 && vtcltlVersion > 16 { assert.True(t, replicaStatus.SuperReadOnly) } assert.False(t, replicaStatus.SemiSyncPrimaryEnabled) From 9153e19b1613342a4c1b39b14549a162b53911f8 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 15 Feb 2023 13:22:42 -0800 Subject: [PATCH 52/65] code review feedback Signed-off-by: Rameez Sajwani --- doc/releasenotes/17_0_0_summary.md | 2 + go/mysql/collations/local.go | 5 +- go/test/endtoend/backup/vtbackup/main_test.go | 10 ++-- .../backup/vtctlbackup/backup_utils.go | 18 +++---- go/test/endtoend/cluster/mysqlctl_process.go | 19 +++---- go/test/endtoend/cluster/mysqlctld_process.go | 8 ++- .../recovery/unshardedrecovery/recovery.go | 15 ++---- go/test/endtoend/utils/mysql.go | 17 ++++--- go/test/endtoend/utils/mysql_test.go | 50 +++++++++++++++++-- go/test/endtoend/utils/utils.go | 24 +++++++-- go/vt/mysqlctl/replication.go | 11 ++-- 11 files changed, 114 insertions(+), 65 deletions(-) diff --git a/doc/releasenotes/17_0_0_summary.md b/doc/releasenotes/17_0_0_summary.md index 0482d2584f9..a053a6344ab 100644 --- a/doc/releasenotes/17_0_0_summary.md +++ b/doc/releasenotes/17_0_0_summary.md @@ -34,3 +34,5 @@ the replication no other component or offline system can mutate replica DB resul Reference PR for this change is [PR #12206](https://github.com/vitessio/vitess/pull/12206) +### VTTablet flags: +The flag `use_super_read_only` is deprecated and will be removed in a later release. diff --git a/go/mysql/collations/local.go b/go/mysql/collations/local.go index c0d3c10da09..19aab141465 100644 --- a/go/mysql/collations/local.go +++ b/go/mysql/collations/local.go @@ -21,7 +21,6 @@ package collations import ( "sync" - "vitess.io/vitess/go/internal/flag" "vitess.io/vitess/go/vt/servenv" ) @@ -32,9 +31,9 @@ var defaultEnvInit sync.Once // on the value of the `mysql_server_version` flag passed to this Vitess process. func Local() *Environment { defaultEnvInit.Do(func() { - if !flag.Parsed() { + /*if !flag.Parsed() { panic("collations.Local() called too early") - } + }*/ defaultEnv = NewEnvironment(servenv.MySQLServerVersion()) }) return defaultEnv diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index 9f7bf844c98..1ea6eddfbed 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -22,10 +22,10 @@ import ( "os" "os/exec" "path" - "strings" "testing" "vitess.io/vitess/go/test/endtoend/cluster" + "vitess.io/vitess/go/test/endtoend/utils" "vitess.io/vitess/go/vt/log" ) @@ -92,12 +92,10 @@ func TestMain(m *testing.M) { sql := string(initDb) // Since password update is DML we need to insert it before we disable // super-read-only therefore doing the split below. - splitString := strings.Split(sql, "# add custom sql here") - if len(splitString) < 2 { - return 1, fmt.Errorf("missing `# add custom sql here` in init_db.sql file") + sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(localCluster), "") + if err != nil { + return 1, err } - firstPart := splitString[0] + cluster.GetPasswordUpdateSQL(localCluster) - sql = firstPart + splitString[1] newInitDBFile = path.Join(localCluster.TmpDirectory, "init_db_with_passwords.sql") err = os.WriteFile(newInitDBFile, []byte(sql), 0666) if err != nil { diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 6d0b759a0be..55ba3857d30 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -28,19 +28,19 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/test/endtoend/cluster" + "vitess.io/vitess/go/test/endtoend/utils" "vitess.io/vitess/go/textutil" "vitess.io/vitess/go/vt/mysqlctl" "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vterrors" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "vitess.io/vitess/go/test/endtoend/cluster" ) // constants for test variants @@ -120,12 +120,10 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp sql := string(initDb) // Since password update is DML we need to insert it before we disable // super-read-only therefore doing the split below. - splitString := strings.Split(sql, "# add custom sql here") - if len(splitString) < 2 { - return 1, fmt.Errorf("missing `# add custom sql here` in init_db.sql file") + sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(localCluster), "") + if err != nil { + return 1, err } - firstPart := splitString[0] + cluster.GetPasswordUpdateSQL(localCluster) - sql = firstPart + splitString[1] newInitDBFile = path.Join(localCluster.TmpDirectory, "init_db_with_passwords.sql") err = os.WriteFile(newInitDBFile, []byte(sql), 0666) if err != nil { diff --git a/go/test/endtoend/cluster/mysqlctl_process.go b/go/test/endtoend/cluster/mysqlctl_process.go index cd857d13e6a..715be4fe564 100644 --- a/go/test/endtoend/cluster/mysqlctl_process.go +++ b/go/test/endtoend/cluster/mysqlctl_process.go @@ -238,11 +238,9 @@ func (mysqlctl *MysqlctlProcess) Connect(ctx context.Context, username string) ( // configured with the given Config. func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirectory string, initMySQL bool) *MysqlctlProcess { var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value - if isSQL, err := isSQLFlavor(); err == nil { - if !isSQL { - // execute init_db without `super_read_only` - initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") - } + updatedInitFile, err := getInitDBFile() + if err == nil { + initFile = updatedInitFile } mysqlctl := &MysqlctlProcess{ Name: "mysqlctl", @@ -257,20 +255,19 @@ func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirect return mysqlctl } -func isSQLFlavor() (bool, error) { +func getInitDBFile() (string, error) { versionStr, err := mysqlctl.GetVersionString() if err != nil { - return false, err + return "", err } flavor, _, err := mysqlctl.ParseVersionString(versionStr) if err != nil { - return false, err + return "", err } if flavor == mysqlctl.FlavorMySQL || flavor == mysqlctl.FlavorPercona { - return true, nil + return path.Join(os.Getenv("VTROOT"), "/config/init_db.sql"), err } - - return false, nil + return path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql"), err } // MysqlCtlProcessInstance returns a Mysqlctl handle for mysqlctl process diff --git a/go/test/endtoend/cluster/mysqlctld_process.go b/go/test/endtoend/cluster/mysqlctld_process.go index e111cc9f7f0..eef1afc83a5 100644 --- a/go/test/endtoend/cluster/mysqlctld_process.go +++ b/go/test/endtoend/cluster/mysqlctld_process.go @@ -146,11 +146,9 @@ func (mysqlctld *MysqlctldProcess) CleanupFiles(tabletUID int) { // configured with the given Config. func MysqlCtldProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) *MysqlctldProcess { var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value - if isSQL, err := isSQLFlavor(); err == nil { - if !isSQL { - // execute init_db without `super_read_only` - initFile = path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql") - } + updatedInitFile, err := getInitDBFile() + if err == nil { + initFile = updatedInitFile } mysqlctld := &MysqlctldProcess{ Name: "mysqlctld", diff --git a/go/test/endtoend/recovery/unshardedrecovery/recovery.go b/go/test/endtoend/recovery/unshardedrecovery/recovery.go index ff387c3809a..e1a4ff81952 100644 --- a/go/test/endtoend/recovery/unshardedrecovery/recovery.go +++ b/go/test/endtoend/recovery/unshardedrecovery/recovery.go @@ -23,7 +23,6 @@ import ( "os" "os/exec" "path" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -31,6 +30,7 @@ import ( "vitess.io/vitess/go/test/endtoend/cluster" "vitess.io/vitess/go/test/endtoend/recovery" + "vitess.io/vitess/go/test/endtoend/utils" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/vtgate/vtgateconn" ) @@ -97,16 +97,11 @@ func TestMainImpl(m *testing.M) { sql := string(initDb) // Since password update is DML we need to insert it before we disable // super-read-only therefore doing the split below. - splitString := strings.Split(sql, "# add custom sql here") - if len(splitString) < 2 { - return 1, fmt.Errorf("missing `# add custom sql here` in init_db.sql file") - } - firstPart := splitString[0] + cluster.GetPasswordUpdateSQL(localCluster) - - // https://github.com/vitessio/vitess/issues/8315 oldAlterTableMode := `SET GLOBAL old_alter_table = ON;` - sql = firstPart + oldAlterTableMode - sql = sql + splitString[1] + sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(localCluster), oldAlterTableMode) + if err != nil { + return 1, err + } newInitDBFile = path.Join(localCluster.TmpDirectory, "init_db_with_passwords.sql") os.WriteFile(newInitDBFile, []byte(sql), 0666) diff --git a/go/test/endtoend/utils/mysql.go b/go/test/endtoend/utils/mysql.go index edc15ed8926..97fa1cd0c36 100644 --- a/go/test/endtoend/utils/mysql.go +++ b/go/test/endtoend/utils/mysql.go @@ -40,7 +40,8 @@ import ( // The mysql.ConnParams to connect to the new database is returned, along with a function to // teardown the database. func NewMySQL(cluster *cluster.LocalProcessCluster, dbName string, schemaSQL ...string) (mysql.ConnParams, func(), error) { - return NewMySQLWithDetails(cluster.GetAndReservePort(), cluster.Hostname, dbName, schemaSQL...) + mysqlParam, _, closer, error := NewMySQLWithDetails(cluster.GetAndReservePort(), cluster.Hostname, dbName, schemaSQL...) + return mysqlParam, closer, error } // CreateMysqldAndMycnf returns a Mysqld and a Mycnf object to use for working with a MySQL @@ -60,24 +61,24 @@ func CreateMysqldAndMycnf(tabletUID uint32, mysqlSocket string, mysqlPort int) ( return mysqlctl.NewMysqld(&cfg), mycnf, nil } -func NewMySQLWithDetails(port int, hostname, dbName string, schemaSQL ...string) (mysql.ConnParams, func(), error) { +func NewMySQLWithDetails(port int, hostname, dbName string, schemaSQL ...string) (mysql.ConnParams, *mysqlctl.Mysqld, func(), error) { mysqlDir, err := createMySQLDir() if err != nil { - return mysql.ConnParams{}, nil, err + return mysql.ConnParams{}, nil, nil, err } initMySQLFile, err := createInitSQLFile(mysqlDir, dbName) if err != nil { - return mysql.ConnParams{}, nil, err + return mysql.ConnParams{}, nil, nil, err } mysqlPort := port mysqld, mycnf, err := CreateMysqldAndMycnf(0, "", mysqlPort) if err != nil { - return mysql.ConnParams{}, nil, err + return mysql.ConnParams{}, nil, nil, err } err = initMysqld(mysqld, mycnf, initMySQLFile) if err != nil { - return mysql.ConnParams{}, nil, err + return mysql.ConnParams{}, nil, nil, err } params := mysql.ConnParams{ @@ -89,10 +90,10 @@ func NewMySQLWithDetails(port int, hostname, dbName string, schemaSQL ...string) for _, sql := range schemaSQL { err = prepareMySQLWithSchema(params, sql) if err != nil { - return mysql.ConnParams{}, nil, err + return mysql.ConnParams{}, nil, nil, err } } - return params, func() { + return params, mysqld, func() { ctx := context.Background() _ = mysqld.Teardown(ctx, mycnf, true) }, nil diff --git a/go/test/endtoend/utils/mysql_test.go b/go/test/endtoend/utils/mysql_test.go index d2816cb1227..fd120a4b075 100644 --- a/go/test/endtoend/utils/mysql_test.go +++ b/go/test/endtoend/utils/mysql_test.go @@ -22,6 +22,10 @@ import ( "os" "testing" + "github.com/stretchr/testify/assert" + + "vitess.io/vitess/go/vt/mysqlctl" + "github.com/stretchr/testify/require" "vitess.io/vitess/go/mysql" @@ -31,6 +35,7 @@ import ( var ( clusterInstance *cluster.LocalProcessCluster mysqlParams mysql.ConnParams + mysqld *mysqlctl.Mysqld keyspaceName = "ks" cell = "test" schemaSQL = `create table t1( @@ -48,13 +53,14 @@ func TestMain(m *testing.M) { clusterInstance = cluster.NewCluster(cell, "localhost") defer clusterInstance.Teardown() - conn, closer, err := NewMySQL(clusterInstance, keyspaceName, schemaSQL) + var closer func() + var err error + mysqlParams, mysqld, closer, err = NewMySQLWithDetails(clusterInstance.GetAndReservePort(), clusterInstance.Hostname, keyspaceName, schemaSQL) if err != nil { fmt.Println(err) return 1 } defer closer() - mysqlParams = conn return m.Run() }() os.Exit(exitCode) @@ -64,9 +70,47 @@ func TestCreateMySQL(t *testing.T) { ctx := context.Background() conn, err := mysql.Connect(ctx, &mysqlParams) require.NoError(t, err) - + require.NoError(t, clusterInstance.Err()) AssertMatches(t, conn, "show databases;", `[[VARCHAR("information_schema")] [VARCHAR("ks")] [VARCHAR("mysql")] [VARCHAR("performance_schema")] [VARCHAR("sys")]]`) AssertMatches(t, conn, "show tables;", `[[VARCHAR("t1")]]`) Exec(t, conn, "insert into t1(id1, id2, id3) values (1, 1, 1), (2, 2, 2), (3, 3, 3)") AssertMatches(t, conn, "select * from t1;", `[[INT64(1) INT64(1) INT64(1)] [INT64(2) INT64(2) INT64(2)] [INT64(3) INT64(3) INT64(3)]]`) } + +func TestSetSuperReadOnlyMySQL(t *testing.T) { + retFunc1, err := mysqld.SetSuperReadOnly(true) + assert.NotNil(t, retFunc1, "SetSuperReadOnly is suppose to return a defer function") + assert.Nil(t, err, "SetSuperReadOnly should not have failed") + + // if value is already true then there is no retFunc being returned. + retFunc2, err := mysqld.SetSuperReadOnly(true) + assert.Nil(t, retFunc2, "SetSuperReadOnly is suppose to return a nil function") + assert.Nil(t, err, "SetSuperReadOnly should not have failed") + + retFunc1() + isSuperReadOnly, _ := mysqld.IsSuperReadOnly() + assert.False(t, isSuperReadOnly, "super_read_only should be set to False") + isReadOnly, _ := mysqld.IsReadOnly() + assert.True(t, isReadOnly, "read_only should be set to True") + + retFunc1, err = mysqld.SetSuperReadOnly(false) + assert.Nil(t, retFunc1, "SetSuperReadOnly is suppose to return a nil function") + assert.Nil(t, err, "SetSuperReadOnly should not have failed") + + _, _ = mysqld.SetSuperReadOnly(true) + + retFunc1, err = mysqld.SetSuperReadOnly(false) + assert.NotNil(t, retFunc1, "SetSuperReadOnly is suppose to return a defer function") + assert.Nil(t, err, "SetSuperReadOnly should not have failed") + + // if value is already true then there is no retFunc being returned. + retFunc2, err = mysqld.SetSuperReadOnly(false) + assert.Nil(t, retFunc2, "SetSuperReadOnly is suppose to return a nil function") + assert.Nil(t, err, "SetSuperReadOnly should not have failed") + + retFunc1() + isSuperReadOnly, _ = mysqld.IsSuperReadOnly() + assert.True(t, isSuperReadOnly, "super_read_only should be set to True") + isReadOnly, _ = mysqld.IsReadOnly() + assert.True(t, isReadOnly, "read_only should be set to True") +} diff --git a/go/test/endtoend/utils/utils.go b/go/test/endtoend/utils/utils.go index 7b37c1b0ecf..c9b38b5a245 100644 --- a/go/test/endtoend/utils/utils.go +++ b/go/test/endtoend/utils/utils.go @@ -22,16 +22,14 @@ import ( "testing" "time" - "vitess.io/vitess/go/test/endtoend/cluster" - - "vitess.io/vitess/go/test/utils" - "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/test/endtoend/cluster" + "vitess.io/vitess/go/test/utils" ) // AssertContains ensures the given query result contains the expected results. @@ -289,3 +287,21 @@ func convertToMap(input interface{}) map[string]interface{} { output := input.(map[string]interface{}) return output } + +func GetInitDBSQL(initDBSQL string, updatedPasswords string, oldAlterTableMode string) (string, error) { + splitString := strings.Split(initDBSQL, "# add custom sql here") + if len(splitString) < 2 { + return "", fmt.Errorf("missing `# add custom sql here` in init_db.sql file") + } + var builder strings.Builder + builder.WriteString(splitString[0]) + builder.WriteString(updatedPasswords) + + // https://github.com/vitessio/vitess/issues/8315 + if oldAlterTableMode != "" { + builder.WriteString(oldAlterTableMode) + } + builder.WriteString(splitString[1]) + + return builder.String(), nil +} diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index 1d6b905d874..b3e19dd9438 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -293,10 +293,14 @@ func (mysqld *Mysqld) SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) return nil, err } - // if non-idempotent then set the right call-back + // If non-idempotent then set the right call-back + // We are asked to turn on super_read_only but original value is false + // then return resetFunc, that can be used as defer by caller if on && !superReadOnlyEnabled { returnFunc = resetFunc } + // We are asked to turn off super_read_only but original value is true + // then return setFunc, that can be used as defer by caller if !on && superReadOnlyEnabled { returnFunc = setFunc } @@ -310,11 +314,8 @@ func (mysqld *Mysqld) SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) if err := mysqld.ExecuteSuperQuery(context.TODO(), query); err != nil { return nil, err } - if superReadOnlyEnabled { - return returnFunc, nil - } - return nil, nil + return returnFunc, nil } // WaitSourcePos lets replicas wait to given replication position From 234d89c6986a7baa2ea71f260e003f5ac1261bf1 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 15 Feb 2023 15:05:50 -0800 Subject: [PATCH 53/65] fixing summary and some minor cleanup Signed-off-by: Rameez Sajwani --- doc/releasenotes/17_0_0_summary.md | 8 ++++++-- go/mysql/collations/local.go | 5 +++-- go/test/endtoend/backup/vtbackup/main_test.go | 3 +-- go/test/endtoend/backup/vtctlbackup/backup_utils.go | 3 +-- go/test/endtoend/recovery/unshardedrecovery/recovery.go | 3 +-- .../endtoend/reparent/plannedreparent/reparent_test.go | 2 +- go/test/endtoend/utils/mysql_test.go | 5 +---- go/test/endtoend/utils/utils.go | 2 ++ go/vt/mysqlctl/replication.go | 1 + 9 files changed, 17 insertions(+), 15 deletions(-) diff --git a/doc/releasenotes/17_0_0_summary.md b/doc/releasenotes/17_0_0_summary.md index 6d0a5076089..0dbaf395387 100644 --- a/doc/releasenotes/17_0_0_summary.md +++ b/doc/releasenotes/17_0_0_summary.md @@ -9,6 +9,9 @@ - [Builtin backup: read buffering flags](#builtin-backup-read-buffering-flags) - **[New stats](#new-stats)** - [Detailed backup and restore stats](#detailed-backup-and-restore-stats) + - **[VTTablet](#vttablet)** + - [VTTablet: Initializing all replica DB with super_read_only](#vttablet-initialization) + - [Deprecated Flags](#deprecated-flags) ## Major Changes @@ -161,7 +164,8 @@ Some notes to help understand these metrics: * `DurationByPhaseSeconds["RestoreLastBackup"]` measures to the duration of the restore phase. * `RestoreDurationNanoseconds["-.-.Restore"]` also measures to the duration of the restore phase. -#### VTTablet: Initializing all replica DB with super_read_only +### VTTablet +#### Initializing all replica DB with super_read_only In order to prevent SUPER privileged users like `root` or `vt_dba` to produce errant GTIDs anywhere anytime, all the replica DBs are initialized with the Mysql global variable `super_read_only` value set to `ON`. During re-parenting, we set `super_read_only` to `OFF` for the promoted primary tablet. This will allow the primary to accept writes. All replica except the primary will still have their global variable `super_read_only` set to `ON`. This will make sure that apart from @@ -169,5 +173,5 @@ the replication no other component or offline system can mutate replica DB resul Reference PR for this change is [PR #12206](https://github.com/vitessio/vitess/pull/12206) -### VTTablet flags: +#### Deprecated Flags The flag `use_super_read_only` is deprecated and will be removed in a later release. diff --git a/go/mysql/collations/local.go b/go/mysql/collations/local.go index 19aab141465..c0d3c10da09 100644 --- a/go/mysql/collations/local.go +++ b/go/mysql/collations/local.go @@ -21,6 +21,7 @@ package collations import ( "sync" + "vitess.io/vitess/go/internal/flag" "vitess.io/vitess/go/vt/servenv" ) @@ -31,9 +32,9 @@ var defaultEnvInit sync.Once // on the value of the `mysql_server_version` flag passed to this Vitess process. func Local() *Environment { defaultEnvInit.Do(func() { - /*if !flag.Parsed() { + if !flag.Parsed() { panic("collations.Local() called too early") - }*/ + } defaultEnv = NewEnvironment(servenv.MySQLServerVersion()) }) return defaultEnv diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index 1ea6eddfbed..8fe628459c0 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -90,8 +90,7 @@ func TestMain(m *testing.M) { dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) - // Since password update is DML we need to insert it before we disable - // super-read-only therefore doing the split below. + // since original initDb does not have updated passwords. Therefore, update the init file with passwords SQL. sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(localCluster), "") if err != nil { return 1, err diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 55ba3857d30..8325b4a65c5 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -118,8 +118,7 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) - // Since password update is DML we need to insert it before we disable - // super-read-only therefore doing the split below. + // since original initDb does not have updated passwords. Therefore, update the init file with passwords SQL. sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(localCluster), "") if err != nil { return 1, err diff --git a/go/test/endtoend/recovery/unshardedrecovery/recovery.go b/go/test/endtoend/recovery/unshardedrecovery/recovery.go index e1a4ff81952..6a1e327f0f8 100644 --- a/go/test/endtoend/recovery/unshardedrecovery/recovery.go +++ b/go/test/endtoend/recovery/unshardedrecovery/recovery.go @@ -95,8 +95,7 @@ func TestMainImpl(m *testing.M) { dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) - // Since password update is DML we need to insert it before we disable - // super-read-only therefore doing the split below. + // since original initDb does not have updated passwords. Therefore, update the init file with passwords SQL. oldAlterTableMode := `SET GLOBAL old_alter_table = ON;` sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(localCluster), oldAlterTableMode) if err != nil { diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go index 0a2b606e4f2..c43239c0579 100644 --- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go +++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go @@ -431,7 +431,7 @@ func TestFullStatus(t *testing.T) { require.NoError(t, err) vtcltlVersion, err := cluster.GetMajorVersion("vtctl") require.NoError(t, err) - // For all version above v15, each replica will start in super-read-only mode. + // For all version above v16, each replica will start in super-read-only mode. if vtTabletVersion > 16 && vtcltlVersion > 16 { assert.False(t, primaryStatus.SuperReadOnly) } diff --git a/go/test/endtoend/utils/mysql_test.go b/go/test/endtoend/utils/mysql_test.go index fd120a4b075..84a79f861d2 100644 --- a/go/test/endtoend/utils/mysql_test.go +++ b/go/test/endtoend/utils/mysql_test.go @@ -23,13 +23,11 @@ import ( "testing" "github.com/stretchr/testify/assert" - - "vitess.io/vitess/go/vt/mysqlctl" - "github.com/stretchr/testify/require" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/test/endtoend/cluster" + "vitess.io/vitess/go/vt/mysqlctl" ) var ( @@ -70,7 +68,6 @@ func TestCreateMySQL(t *testing.T) { ctx := context.Background() conn, err := mysql.Connect(ctx, &mysqlParams) require.NoError(t, err) - require.NoError(t, clusterInstance.Err()) AssertMatches(t, conn, "show databases;", `[[VARCHAR("information_schema")] [VARCHAR("ks")] [VARCHAR("mysql")] [VARCHAR("performance_schema")] [VARCHAR("sys")]]`) AssertMatches(t, conn, "show tables;", `[[VARCHAR("t1")]]`) Exec(t, conn, "insert into t1(id1, id2, id3) values (1, 1, 1), (2, 2, 2), (3, 3, 3)") diff --git a/go/test/endtoend/utils/utils.go b/go/test/endtoend/utils/utils.go index c77ccd5a470..0cc3480faa0 100644 --- a/go/test/endtoend/utils/utils.go +++ b/go/test/endtoend/utils/utils.go @@ -289,6 +289,8 @@ func convertToMap(input interface{}) map[string]interface{} { } func GetInitDBSQL(initDBSQL string, updatedPasswords string, oldAlterTableMode string) (string, error) { + // Since password update is DML we need to insert it before we disable + // super-read-only therefore doing the split below. splitString := strings.Split(initDBSQL, "# add custom sql here") if len(splitString) < 2 { return "", fmt.Errorf("missing `# add custom sql here` in init_db.sql file") diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index b3e19dd9438..556a99da2fa 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -271,6 +271,7 @@ func (mysqld *Mysqld) SetReadOnly(on bool) error { } // SetSuperReadOnly set/unset the super_read_only flag +// Returns a function which is called to set super_read_only back to its original value. func (mysqld *Mysqld) SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) { // return function for switching `OFF` super_read_only var returnFunc ResetSuperReadOnlyFunc From a653287143aee5391c88eca0b91b136b514cfba9 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 15 Feb 2023 21:32:04 -0800 Subject: [PATCH 54/65] remove extra logging Signed-off-by: Rameez Sajwani --- go/cmd/vtbackup/vtbackup.go | 1 - go/test/endtoend/reparent/plannedreparent/reparent_test.go | 2 +- go/vt/mysqlctl/mysqld.go | 5 +---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/go/cmd/vtbackup/vtbackup.go b/go/cmd/vtbackup/vtbackup.go index 414b49b748b..b04bf9fe2ae 100644 --- a/go/cmd/vtbackup/vtbackup.go +++ b/go/cmd/vtbackup/vtbackup.go @@ -304,7 +304,6 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back } // In initial_backup mode, just take a backup of this empty database. if initialBackup { - log.Infof("Inside initialBackup creating initial binlog entry.") // Take a backup of this empty DB without restoring anything. // First, initialize it the way InitShardPrimary would, so this backup // produces a result that can be used to skip InitShardPrimary entirely. diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go index c43239c0579..b2a9660dace 100644 --- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go +++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go @@ -487,7 +487,7 @@ func TestFullStatus(t *testing.T) { assert.Contains(t, replicaStatus.PrimaryStatus.String(), "vt-0000000102-bin") assert.Equal(t, replicaStatus.GtidPurged, "MySQL56/") assert.True(t, replicaStatus.ReadOnly) - // For all version above v15, each replica will start in super-read-only mode. + // For all version above v16, each replica will start in super-read-only mode. if vtTabletVersion > 16 && vtcltlVersion > 16 { assert.True(t, replicaStatus.SuperReadOnly) } diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index 56bdcf63efa..f1af03b0848 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -35,7 +35,6 @@ import ( "path" "path/filepath" "regexp" - "runtime/debug" "strconv" "strings" "sync" @@ -668,7 +667,7 @@ func (mysqld *Mysqld) InitConfig(cnf *Mycnf) error { // generate / configure a my.cnf file install a skeleton database, // and apply the provided initial SQL file. func (mysqld *Mysqld) Init(ctx context.Context, cnf *Mycnf, initDBSQLFile string) error { - log.Infof("mysqlctl.Init") + log.Infof("mysqlctl.Init with %s", initDBSQLFile) err := mysqld.InitConfig(cnf) if err != nil { log.Errorf("%s", err.Error()) @@ -696,8 +695,6 @@ func (mysqld *Mysqld) Init(ctx context.Context, cnf *Mycnf, initDBSQLFile string log.Errorf("failed starting mysqld in time: %v\n%v", err, readTailOfMysqldErrorLog(cnf.ErrorLogPath)) return err } - - log.Infof("InitDBSQLFile: %s %s", initDBSQLFile, debug.Stack()) if initDBSQLFile == "" { // default to built-in if err := mysqld.executeMysqlScript(params, strings.NewReader(config.DefaultInitDB)); err != nil { return fmt.Errorf("failed to initialize mysqld: %v", err) From e3d160743ea344f0c4d95eb600575974a825e5b9 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Thu, 16 Feb 2023 12:57:43 -0800 Subject: [PATCH 55/65] moving init_testserver_db under test folder Signed-off-by: Rameez Sajwani --- go/test/endtoend/backup/vtbackup/main_test.go | 1 + go/test/endtoend/backup/vtctlbackup/backup_utils.go | 3 +++ go/test/endtoend/cluster/mysqlctl_process.go | 2 +- go/test/endtoend/recovery/unshardedrecovery/recovery.go | 3 +++ .../vreplication/testdata/config}/init_testserver_db.sql | 0 5 files changed, 8 insertions(+), 1 deletion(-) rename {config => go/test/endtoend/vreplication/testdata/config}/init_testserver_db.sql (100%) diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index 8fe628459c0..d4a1ce76308 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -87,6 +87,7 @@ func TestMain(m *testing.M) { // Create a new init_db.sql file that sets up passwords for all users. // Then we use a db-credentials-file with the passwords. + // We need these users during backup-restore process for example vt_repl is needed during ResetReplication while taking backup. dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 8325b4a65c5..0748e7d759d 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -115,6 +115,9 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp } shard := &localCluster.Keyspaces[0].Shards[0] + // Create a new init_db.sql file that sets up passwords for all users. + // Then we use a db-credentials-file with the passwords. + // We need these users during backup-restore process for example vt_repl is needed during ResetReplication while taking backup. dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) diff --git a/go/test/endtoend/cluster/mysqlctl_process.go b/go/test/endtoend/cluster/mysqlctl_process.go index 715be4fe564..ebad90681aa 100644 --- a/go/test/endtoend/cluster/mysqlctl_process.go +++ b/go/test/endtoend/cluster/mysqlctl_process.go @@ -267,7 +267,7 @@ func getInitDBFile() (string, error) { if flavor == mysqlctl.FlavorMySQL || flavor == mysqlctl.FlavorPercona { return path.Join(os.Getenv("VTROOT"), "/config/init_db.sql"), err } - return path.Join(os.Getenv("VTROOT"), "config/init_testserver_db.sql"), err + return path.Join(os.Getenv("VTROOT"), "go/test/endtoend/vreplication/testdata/config/init_testserver_db.sql"), err } // MysqlCtlProcessInstance returns a Mysqlctl handle for mysqlctl process diff --git a/go/test/endtoend/recovery/unshardedrecovery/recovery.go b/go/test/endtoend/recovery/unshardedrecovery/recovery.go index 6a1e327f0f8..29f1c8bbc46 100644 --- a/go/test/endtoend/recovery/unshardedrecovery/recovery.go +++ b/go/test/endtoend/recovery/unshardedrecovery/recovery.go @@ -92,6 +92,9 @@ func TestMainImpl(m *testing.M) { } localCluster.Keyspaces = append(localCluster.Keyspaces, *keyspace) + // Create a new init_db.sql file that sets up passwords for all users. + // Then we use a db-credentials-file with the passwords. + // We need these users during backup-restore process for example vt_repl is needed during ResetReplication while taking backup. dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) diff --git a/config/init_testserver_db.sql b/go/test/endtoend/vreplication/testdata/config/init_testserver_db.sql similarity index 100% rename from config/init_testserver_db.sql rename to go/test/endtoend/vreplication/testdata/config/init_testserver_db.sql From 2d7636f8643311659c79c8d5d4b52155d66bfa7d Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Thu, 16 Feb 2023 14:42:47 -0800 Subject: [PATCH 56/65] fixing code comment Signed-off-by: Rameez Sajwani --- config/mycnf/test-suite.cnf | 2 + doc/releasenotes/17_0_0_summary.md | 12 ++--- .../backup/vtbackup/backup_only_test.go | 4 +- go/test/endtoend/backup/vtbackup/main_test.go | 4 +- .../backup/vtctlbackup/backup_utils.go | 4 +- go/test/endtoend/cluster/mysqlctl_process.go | 6 +-- go/test/endtoend/cluster/vttablet_process.go | 51 +++++++++++++------ .../recovery/unshardedrecovery/recovery.go | 4 +- go/test/endtoend/utils/mysql.go | 9 ++-- go/test/endtoend/utils/mysql_test.go | 6 +-- go/vt/mysqlctl/builtinbackupengine.go | 17 +++---- go/vt/mysqlctl/mysqld.go | 4 +- .../vttablet/tabletmanager/rpc_replication.go | 2 +- 13 files changed, 75 insertions(+), 50 deletions(-) diff --git a/config/mycnf/test-suite.cnf b/config/mycnf/test-suite.cnf index d23efa54a30..5a1ada5a75b 100644 --- a/config/mycnf/test-suite.cnf +++ b/config/mycnf/test-suite.cnf @@ -23,4 +23,6 @@ sql_mode = STRICT_TRANS_TABLES # set a short heartbeat interval in order to detect failures quickly slave_net_timeout = 4 +# test-suite is mainly used for vttestserver, which does not need super-read-only. Therefore, +# we are disabling it. super-read-only = false diff --git a/doc/releasenotes/17_0_0_summary.md b/doc/releasenotes/17_0_0_summary.md index 0dbaf395387..1eb0e1a5429 100644 --- a/doc/releasenotes/17_0_0_summary.md +++ b/doc/releasenotes/17_0_0_summary.md @@ -10,7 +10,7 @@ - **[New stats](#new-stats)** - [Detailed backup and restore stats](#detailed-backup-and-restore-stats) - **[VTTablet](#vttablet)** - - [VTTablet: Initializing all replica DB with super_read_only](#vttablet-initialization) + - [VTTablet: Initializing all replicas with super_read_only](#vttablet-initialization) - [Deprecated Flags](#deprecated-flags) ## Major Changes @@ -165,11 +165,11 @@ Some notes to help understand these metrics: * `RestoreDurationNanoseconds["-.-.Restore"]` also measures to the duration of the restore phase. ### VTTablet -#### Initializing all replica DB with super_read_only -In order to prevent SUPER privileged users like `root` or `vt_dba` to produce errant GTIDs anywhere anytime, all the replica DBs are initialized with the Mysql -global variable `super_read_only` value set to `ON`. During re-parenting, we set `super_read_only` to `OFF` for the promoted primary tablet. This will allow the -primary to accept writes. All replica except the primary will still have their global variable `super_read_only` set to `ON`. This will make sure that apart from -the replication no other component or offline system can mutate replica DB resulting in errant GTIDs that are then lying in wait to cause later failures. +#### Initializing all replicas with super_read_only +In order to prevent SUPER privileged users like `root` or `vt_dba` from producing errant GTIDs on replicas, all the replica MySQL servers are initialized with the MySQL +global variable `super_read_only` value set to `ON`. During failovers, we set `super_read_only` to `OFF` for the promoted primary tablet. This will allow the +primary to accept writes. All replicas except the primary will still have their global variable `super_read_only` set to `ON`. This will make sure that apart from +MySQL replication no other component or offline system can write directly to a replica. Reference PR for this change is [PR #12206](https://github.com/vitessio/vitess/pull/12206) diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index 4e09e3ab250..8bd37af0733 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -65,8 +65,8 @@ func TestTabletInitialBackup(t *testing.T) { vtTabletVersion, err := cluster.GetMajorVersion("vttablet") require.NoError(t, err) - // For all version above v15, each replica will start in super-read-only mode. - if vtTabletVersion > 16 { + // For all version at or above v17.0.0, each replica will start in super-read-only mode. Let's verify that is working correctly. + if vtTabletVersion >= 17 { err := primary.VttabletProcess.CreateDB("testDB") require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") err = replica1.VttabletProcess.CreateDB("testDB") diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index d4a1ce76308..d7b158ae12a 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -87,11 +87,11 @@ func TestMain(m *testing.M) { // Create a new init_db.sql file that sets up passwords for all users. // Then we use a db-credentials-file with the passwords. - // We need these users during backup-restore process for example vt_repl is needed during ResetReplication while taking backup. + // We need these users/passwords during backup-restore process, for example vt_repl is needed during ResetReplication while taking backup. dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) - // since original initDb does not have updated passwords. Therefore, update the init file with passwords SQL. + // The original init_db.sql does not have any passwords. Here we update the init file with passwords sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(localCluster), "") if err != nil { return 1, err diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 0748e7d759d..7c491ca67f4 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -117,11 +117,11 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp // Create a new init_db.sql file that sets up passwords for all users. // Then we use a db-credentials-file with the passwords. - // We need these users during backup-restore process for example vt_repl is needed during ResetReplication while taking backup. + // We need these users/passwords during backup-restore process, for example vt_repl is needed during ResetReplication while taking backup. dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) - // since original initDb does not have updated passwords. Therefore, update the init file with passwords SQL. + // The original init_db.sql does not have any passwords. Here we update the init file with passwords sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(localCluster), "") if err != nil { return 1, err diff --git a/go/test/endtoend/cluster/mysqlctl_process.go b/go/test/endtoend/cluster/mysqlctl_process.go index ebad90681aa..d71e3c94a13 100644 --- a/go/test/endtoend/cluster/mysqlctl_process.go +++ b/go/test/endtoend/cluster/mysqlctl_process.go @@ -239,7 +239,7 @@ func (mysqlctl *MysqlctlProcess) Connect(ctx context.Context, username string) ( func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirectory string, initMySQL bool) *MysqlctlProcess { var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value updatedInitFile, err := getInitDBFile() - if err == nil { + if err != nil { initFile = updatedInitFile } mysqlctl := &MysqlctlProcess{ @@ -265,9 +265,9 @@ func getInitDBFile() (string, error) { return "", err } if flavor == mysqlctl.FlavorMySQL || flavor == mysqlctl.FlavorPercona { - return path.Join(os.Getenv("VTROOT"), "/config/init_db.sql"), err + return path.Join(os.Getenv("VTROOT"), "/config/init_db.sql"), nil } - return path.Join(os.Getenv("VTROOT"), "go/test/endtoend/vreplication/testdata/config/init_testserver_db.sql"), err + return path.Join(os.Getenv("VTROOT"), "go/test/endtoend/vreplication/testdata/config/init_testserver_db.sql"), nil } // MysqlCtlProcessInstance returns a Mysqlctl handle for mysqlctl process diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index 4347a072a2a..088a677703e 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -629,9 +629,13 @@ func VttabletProcessInstance(port, grpcPort, tabletUID int, cell, shard, keyspac return vttablet } -// QueryTabletWithSuperReadOnlyHandling lets you execute a query in this tablet while disabling super-read-only and get the result -// It will enable super-read-only once its done executing the query. +// QueryTabletWithSuperReadOnlyHandling will retry the query up to 10 times with a small sleep in between each try. +// This allows the tests to be more robust in the face of transient failures. It disables super-read-only during query execution. func (vttablet *VttabletProcess) QueryTabletWithSuperReadOnlyHandling(query string, keyspace string, useDb bool) (*sqltypes.Result, error) { + var ( + err error + result *sqltypes.Result + ) if !useDb { keyspace = "" } @@ -641,25 +645,14 @@ func (vttablet *VttabletProcess) QueryTabletWithSuperReadOnlyHandling(query stri return nil, err } defer conn.Close() - return executeQueryWithSuperReadOnlyHandling(conn, query) -} - -// executeQuery will retry the query up to 10 times with a small sleep in between each try. -// This allows the tests to be more robust in the face of transient failures. It disables -// super-read-only during query execution. -func executeQueryWithSuperReadOnlyHandling(dbConn *mysql.Conn, query string) (*sqltypes.Result, error) { - var ( - err error - result *sqltypes.Result - ) retries := 10 retryDelay := 1 * time.Second for i := 0; i < retries; i++ { if i > 0 { // We only audit from 2nd attempt and onwards, otherwise this is just too verbose. - log.Infof("Executing query %s (attempt %d of %d)", query, (i + 1), retries) + log.Infof("Executing query %s (attempt %d of %d)", query, i+1, retries) } - result, err = dbConn.ExecuteFetchWithSuperReadOnlyHandling(query, 10000, true) + result, err = executeFetchWithSuperReadOnlyHandling(conn, query, 10000, true) if err == nil { break } @@ -668,3 +661,31 @@ func executeQueryWithSuperReadOnlyHandling(dbConn *mysql.Conn, query string) (*s return result, err } + +// This function will temporarily turn `OFF` super_read_only global variable and reverts it back after query is executed. +func executeFetchWithSuperReadOnlyHandling(dbConn *mysql.Conn, query string, maxRows int, wantFields bool) (result *sqltypes.Result, err error) { + // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ + if !dbConn.IsMariaDB() { + if err := dbConn.WriteComQuery("SELECT @@global.super_read_only"); err != nil { + return nil, err + } + res, _, _, err := dbConn.ReadQueryResult(1, false) + if err == nil && len(res.Rows) == 1 { + sro := res.Rows[0][0].ToString() + if sro == "1" || sro == "ON" { + if _, err = dbConn.ExecuteFetch("SET GLOBAL super_read_only='OFF'", 1, false); err != nil { + return nil, err + } + defer func() { + if _, err := dbConn.ExecuteFetch("SET GLOBAL super_read_only='ON'", 1, false); err != nil { + log.Errorf("error setting super_read_only value %s", err.Error()) + } + }() + } + } + } + + result, _, err = dbConn.ExecuteFetchMulti(query, maxRows, wantFields) + + return result, err +} diff --git a/go/test/endtoend/recovery/unshardedrecovery/recovery.go b/go/test/endtoend/recovery/unshardedrecovery/recovery.go index 29f1c8bbc46..77d24d1aa13 100644 --- a/go/test/endtoend/recovery/unshardedrecovery/recovery.go +++ b/go/test/endtoend/recovery/unshardedrecovery/recovery.go @@ -94,11 +94,11 @@ func TestMainImpl(m *testing.M) { // Create a new init_db.sql file that sets up passwords for all users. // Then we use a db-credentials-file with the passwords. - // We need these users during backup-restore process for example vt_repl is needed during ResetReplication while taking backup. + // We need these users/passwords during backup-restore process, for example vt_repl is needed during ResetReplication while taking backup. dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) - // since original initDb does not have updated passwords. Therefore, update the init file with passwords SQL. + // The original init_db.sql does not have any passwords. Here we update the init file with passwords oldAlterTableMode := `SET GLOBAL old_alter_table = ON;` sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(localCluster), oldAlterTableMode) if err != nil { diff --git a/go/test/endtoend/utils/mysql.go b/go/test/endtoend/utils/mysql.go index 97fa1cd0c36..fc1a62d6736 100644 --- a/go/test/endtoend/utils/mysql.go +++ b/go/test/endtoend/utils/mysql.go @@ -40,7 +40,7 @@ import ( // The mysql.ConnParams to connect to the new database is returned, along with a function to // teardown the database. func NewMySQL(cluster *cluster.LocalProcessCluster, dbName string, schemaSQL ...string) (mysql.ConnParams, func(), error) { - mysqlParam, _, closer, error := NewMySQLWithDetails(cluster.GetAndReservePort(), cluster.Hostname, dbName, schemaSQL...) + mysqlParam, _, closer, error := NewMySQLWithMysqld(cluster.GetAndReservePort(), cluster.Hostname, dbName, schemaSQL...) return mysqlParam, closer, error } @@ -61,7 +61,7 @@ func CreateMysqldAndMycnf(tabletUID uint32, mysqlSocket string, mysqlPort int) ( return mysqlctl.NewMysqld(&cfg), mycnf, nil } -func NewMySQLWithDetails(port int, hostname, dbName string, schemaSQL ...string) (mysql.ConnParams, *mysqlctl.Mysqld, func(), error) { +func NewMySQLWithMysqld(port int, hostname, dbName string, schemaSQL ...string) (mysql.ConnParams, *mysqlctl.Mysqld, func(), error) { mysqlDir, err := createMySQLDir() if err != nil { return mysql.ConnParams{}, nil, nil, err @@ -115,7 +115,10 @@ func createInitSQLFile(mysqlDir, ksName string) (string, error) { return "", err } defer f.Close() - _, _ = f.WriteString("SET GLOBAL super_read_only='OFF';") + _, err = f.WriteString("SET GLOBAL super_read_only='OFF';") + if err != nil { + return "", err + } _, err = f.WriteString(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s;", ksName)) if err != nil { return "", err diff --git a/go/test/endtoend/utils/mysql_test.go b/go/test/endtoend/utils/mysql_test.go index 84a79f861d2..ad0317274b5 100644 --- a/go/test/endtoend/utils/mysql_test.go +++ b/go/test/endtoend/utils/mysql_test.go @@ -53,7 +53,7 @@ func TestMain(m *testing.M) { var closer func() var err error - mysqlParams, mysqld, closer, err = NewMySQLWithDetails(clusterInstance.GetAndReservePort(), clusterInstance.Hostname, keyspaceName, schemaSQL) + mysqlParams, mysqld, closer, err = NewMySQLWithMysqld(clusterInstance.GetAndReservePort(), clusterInstance.Hostname, keyspaceName, schemaSQL) if err != nil { fmt.Println(err) return 1 @@ -79,7 +79,7 @@ func TestSetSuperReadOnlyMySQL(t *testing.T) { assert.NotNil(t, retFunc1, "SetSuperReadOnly is suppose to return a defer function") assert.Nil(t, err, "SetSuperReadOnly should not have failed") - // if value is already true then there is no retFunc being returned. + // if value is already true then retFunc will be nil retFunc2, err := mysqld.SetSuperReadOnly(true) assert.Nil(t, retFunc2, "SetSuperReadOnly is suppose to return a nil function") assert.Nil(t, err, "SetSuperReadOnly should not have failed") @@ -100,7 +100,7 @@ func TestSetSuperReadOnlyMySQL(t *testing.T) { assert.NotNil(t, retFunc1, "SetSuperReadOnly is suppose to return a defer function") assert.Nil(t, err, "SetSuperReadOnly should not have failed") - // if value is already true then there is no retFunc being returned. + // if value is already false then retFunc will be nil retFunc2, err = mysqld.SetSuperReadOnly(false) assert.Nil(t, retFunc2, "SetSuperReadOnly is suppose to return a nil function") assert.Nil(t, err, "SetSuperReadOnly should not have failed") diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index 808fa104fab..6d482df1ba8 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -319,8 +319,8 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac replicaStartRequired := false sourceIsPrimary := false superReadOnly := true //nolint + readOnly := true //nolint var replicationPosition mysql.Position - var resetSuperReadOnlyFunc ResetSuperReadOnlyFunc semiSyncSource, semiSyncReplica := params.Mysqld.SemiSyncEnabled() // See if we need to restart replication after backup. @@ -337,7 +337,7 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac } // get the read-only flag - readOnly, err := params.Mysqld.IsReadOnly() + readOnly, err = params.Mysqld.IsReadOnly() if err != nil { return false, vterrors.Wrap(err, "can't get read_only status") } @@ -349,9 +349,10 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac // get the replication position if sourceIsPrimary { + // No need to set read_only because super_read_only will implicitly set read_only to true as well. if !superReadOnly { params.Logger.Infof("turning primary super-read-only before backup") - if resetSuperReadOnlyFunc, err = params.Mysqld.SetSuperReadOnly(true); err != nil { + if _, err = params.Mysqld.SetSuperReadOnly(true); err != nil { return false, vterrors.Wrap(err, "can't set super-read-only status") } } @@ -404,12 +405,10 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac return usable, vterrors.Wrap(err, "can't restart mysqld") } - // And set read-only mode - if resetSuperReadOnlyFunc != nil { - err := resetSuperReadOnlyFunc() - if err != nil { - log.Info("not able to set super_read_only to its original value during backup") - } + // Resetting super_read_only back to its original value + params.Logger.Infof("resetting mysqld super_read-only to %v", superReadOnly) + if _, err := params.Mysqld.SetSuperReadOnly(superReadOnly); err != nil { + return usable, err } // Restore original mysqld state that we saved above. diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index f1af03b0848..f7c345291b4 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -1259,9 +1259,9 @@ func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTID resetFunc, err := mysqld.SetSuperReadOnly(false) if err != nil { if strings.Contains(err.Error(), mysql.ERUnknownSystemVariable.ToString()) { - log.Warningf("Restore: server does not know about super_read_only, continuing anyway...") + log.Warningf("applyBinlogFile: server does not know about super_read_only, continuing anyway...") } else { - log.Errorf("Restore: unexpected error while trying to set super_read_only: %v", err) + log.Errorf("applyBinlogFile: unexpected error while trying to set super_read_only: %v", err) return err } } diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index 6d7db9fd5cf..a716639a4ad 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -41,7 +41,7 @@ var disableReplicationManager bool func registerReplicationFlags(fs *pflag.FlagSet) { fs.Bool("use_super_read_only", true, "Set super_read_only flag when performing planned failover.") - fs.MarkDeprecated("use_super_read_only", "From v17 onwards MySQL server will always starts as super_read_only=`true`") + fs.MarkDeprecated("use_super_read_only", "From v17 onwards MySQL server will always start with super_read_only=ON") fs.BoolVar(&disableReplicationManager, "disable-replication-manager", disableReplicationManager, "Disable replication manager to prevent replication repairs.") fs.MarkDeprecated("disable-replication-manager", "Replication manager is deleted") } From fdc2eef2a17bbd60ba95b1543fcab917390d9f3c Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Tue, 28 Feb 2023 18:46:36 -0800 Subject: [PATCH 57/65] trying out password db init file for PITR test Signed-off-by: Rameez Sajwani --- go/cmd/vtbackup/vtbackup.go | 4 +- go/mysql/query.go | 33 ----------- .../backup/vtbackup/backup_only_test.go | 2 +- go/test/endtoend/cluster/vttablet_process.go | 2 +- .../recovery/pitr/shardedpitr_test.go | 56 +++++++++++++------ .../reparent/plannedreparent/reparent_test.go | 4 +- go/test/endtoend/utils/utils.go | 2 +- go/test/endtoend/vtorc/utils/utils.go | 2 +- go/vt/mysqlctl/builtinbackupengine.go | 4 +- 9 files changed, 50 insertions(+), 59 deletions(-) diff --git a/go/cmd/vtbackup/vtbackup.go b/go/cmd/vtbackup/vtbackup.go index b04bf9fe2ae..c65db228685 100644 --- a/go/cmd/vtbackup/vtbackup.go +++ b/go/cmd/vtbackup/vtbackup.go @@ -312,10 +312,10 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back if err := mysqld.ResetReplication(ctx); err != nil { return fmt.Errorf("can't reset replication: %v", err) } - // We need to switch off super-read-only before we create database. + // We need to switch off super_read_only before we create database. resetFunc, err := mysqld.SetSuperReadOnly(false) if err != nil { - return fmt.Errorf("can't turn-off super-read-only during backup: %v", err) + return fmt.Errorf("can't turn-off super_read_only during backup: %v", err) } if resetFunc != nil { defer func() { diff --git a/go/mysql/query.go b/go/mysql/query.go index 58ab33789bd..0107e7606bc 100644 --- a/go/mysql/query.go +++ b/go/mysql/query.go @@ -328,39 +328,6 @@ func (c *Conn) ExecuteFetchMulti(query string, maxrows int, wantfields bool) (re return res, more, err } -// ExecuteFetchWithSuperReadOnlyHandling should be used if you are executing a query -// on any tablet regardless of tablet type. -// This function will temporarily make the mysql instance read-write and -// re-enable read-only mode after the query is executed if needed. -func (c *Conn) ExecuteFetchWithSuperReadOnlyHandling(query string, maxrows int, wantfields bool) (result *sqltypes.Result, err error) { - // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ - superReadOnlyEnabled := false - if !c.IsMariaDB() { - if err := c.WriteComQuery("SELECT @@global.super_read_only"); err != nil { - return nil, err - } - res, _, _, err := c.ReadQueryResult(1, false) - if err == nil && len(res.Rows) == 1 { - sro := res.Rows[0][0].ToString() - if sro == "1" || sro == "ON" { - superReadOnlyEnabled = true - if _, err = c.ExecuteFetch("SET GLOBAL super_read_only='OFF'", 1, false); err != nil { - return nil, err - } - } - } - } - - result, _, err = c.ExecuteFetchMulti(query, maxrows, wantfields) - // TODO: may be use it in defer() - if superReadOnlyEnabled { - if _, err := c.ExecuteFetch("SET GLOBAL super_read_only='ON'", 1, false); err != nil { - return nil, err - } - } - return result, err -} - // ExecuteFetchWithWarningCount is for fetching results and a warning count // Note: In a future iteration this should be abolished and merged into the // ExecuteFetch API. diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index 8bd37af0733..1cde6a85177 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -65,7 +65,7 @@ func TestTabletInitialBackup(t *testing.T) { vtTabletVersion, err := cluster.GetMajorVersion("vttablet") require.NoError(t, err) - // For all version at or above v17.0.0, each replica will start in super-read-only mode. Let's verify that is working correctly. + // For all version at or above v17.0.0, each replica will start in super_read_only mode. Let's verify that is working correctly. if vtTabletVersion >= 17 { err := primary.VttabletProcess.CreateDB("testDB") require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement") diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index 8e8d8b0cbfc..a8dbe6c65ff 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -630,7 +630,7 @@ func VttabletProcessInstance(port, grpcPort, tabletUID int, cell, shard, keyspac } // QueryTabletWithSuperReadOnlyHandling will retry the query up to 10 times with a small sleep in between each try. -// This allows the tests to be more robust in the face of transient failures. It disables super-read-only during query execution. +// This allows the tests to be more robust in the face of transient failures. It disables super_read_only during query execution. func (vttablet *VttabletProcess) QueryTabletWithSuperReadOnlyHandling(query string, keyspace string, useDb bool) (*sqltypes.Result, error) { var ( err error diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go index dbdde80a19a..c2927e63660 100644 --- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go +++ b/go/test/endtoend/recovery/pitr/shardedpitr_test.go @@ -19,7 +19,9 @@ package pitr import ( "context" "fmt" + "os" "os/exec" + "path" "testing" "time" @@ -29,6 +31,7 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/test/endtoend/cluster" + "vitess.io/vitess/go/test/endtoend/utils" "vitess.io/vitess/go/vt/log" ) @@ -63,7 +66,7 @@ var ( shard1Name = "80-" dbName = "vt_ks" mysqlUserName = "vt_dba" - mysqlPassword = "password" + mysqlPassword = "VtDbaPass" vSchema = `{ "sharded": true, "vindexes": { @@ -408,6 +411,10 @@ func initializeCluster(t *testing.T) { shard0.Vttablets = []*cluster.Vttablet{shard0Primary, shard0Replica1, shard0Replica2} shard1.Vttablets = []*cluster.Vttablet{shard1Primary, shard1Replica1, shard1Replica2} + dbCredentialFile := cluster.WriteDbCredentialToTmp(clusterInstance.TmpDirectory) + extraArgs := []string{"--db-credentials-file", dbCredentialFile} + commonTabletArg = append(commonTabletArg, "--db-credentials-file", dbCredentialFile) + clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs, commonTabletArg...) clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs, "--restore_from_backup") @@ -416,10 +423,27 @@ func initializeCluster(t *testing.T) { vtctldClientProcess := cluster.VtctldClientProcessInstance("localhost", clusterInstance.VtctldProcess.GrpcPort, clusterInstance.TmpDirectory) out, err := vtctldClientProcess.ExecuteCommandWithOutput("SetKeyspaceDurabilityPolicy", keyspaceName, "--durability-policy=semi_sync") require.NoError(t, err, out) + + initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) + sql := string(initDb) + // The original init_db.sql does not have any passwords. Here we update the init file with passwords + sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(clusterInstance), "") + if err != nil { + require.NoError(t, err, "expected to load init_db file") + } + newInitDBFile := path.Join(clusterInstance.TmpDirectory, "init_db_with_passwords.sql") + err = os.WriteFile(newInitDBFile, []byte(sql), 0666) + if err != nil { + require.NoError(t, err, "expected to load init_db file") + } + // Start MySql var mysqlCtlProcessList []*exec.Cmd for _, shard := range clusterInstance.Keyspaces[0].Shards { for _, tablet := range shard.Vttablets { + tablet.MysqlctlProcess.InitDBFile = newInitDBFile + tablet.VttabletProcess.DbPassword = mysqlPassword + tablet.MysqlctlProcess.ExtraArgs = extraArgs proc, err := tablet.MysqlctlProcess.StartProcess() require.NoError(t, err) mysqlCtlProcessList = append(mysqlCtlProcessList, proc) @@ -432,23 +456,8 @@ func initializeCluster(t *testing.T) { require.NoError(t, err) } - queryCmds := []string{ - fmt.Sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s';", mysqlUserName, mysqlPassword), - fmt.Sprintf("GRANT ALL ON *.* TO '%s'@'%%';", mysqlUserName), - fmt.Sprintf("GRANT GRANT OPTION ON *.* TO '%s'@'%%';", mysqlUserName), - fmt.Sprintf("create database %s;", "vt_ks"), - "FLUSH PRIVILEGES;", - } - - // Executing these queries with super_read_only since these are additional DMLs outside init_db.sql for _, shard := range clusterInstance.Keyspaces[0].Shards { for _, tablet := range shard.Vttablets { - - for _, query := range queryCmds { - _, err = tablet.VttabletProcess.QueryTabletWithSuperReadOnlyHandling(query, keyspace.Name, false) - require.NoError(t, err) - } - err = tablet.VttabletProcess.Setup() require.NoError(t, err) } @@ -463,6 +472,21 @@ func initializeCluster(t *testing.T) { err = clusterInstance.VtctlclientProcess.InitShardPrimary(keyspaceName, shard1.Name, cell, shard1Primary.TabletUID) require.NoError(t, err) + /*queryCmds := []string{ + fmt.Sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s';", mysqlUserName, mysqlPassword), + fmt.Sprintf("GRANT ALL ON *.* TO '%s'@'%%';", mysqlUserName), + fmt.Sprintf("GRANT GRANT OPTION ON *.* TO '%s'@'%%';", mysqlUserName), + "FLUSH PRIVILEGES;", + } + + // Run DMLs on primary and let replication takes care of changes on replica + for _, tablet := range []*cluster.Vttablet{primary, shard0Primary, shard1Primary} { + for _, query := range queryCmds { + _, err = tablet.VttabletProcess.QueryTablet(query, keyspace.Name, false) + require.NoError(t, err) + } + }*/ + err = clusterInstance.StartVTOrc(keyspaceName) require.NoError(t, err) diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go index b2a9660dace..a36e2489b75 100644 --- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go +++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go @@ -431,7 +431,7 @@ func TestFullStatus(t *testing.T) { require.NoError(t, err) vtcltlVersion, err := cluster.GetMajorVersion("vtctl") require.NoError(t, err) - // For all version above v16, each replica will start in super-read-only mode. + // For all version above v16, each replica will start in super_read_only mode. if vtTabletVersion > 16 && vtcltlVersion > 16 { assert.False(t, primaryStatus.SuperReadOnly) } @@ -487,7 +487,7 @@ func TestFullStatus(t *testing.T) { assert.Contains(t, replicaStatus.PrimaryStatus.String(), "vt-0000000102-bin") assert.Equal(t, replicaStatus.GtidPurged, "MySQL56/") assert.True(t, replicaStatus.ReadOnly) - // For all version above v16, each replica will start in super-read-only mode. + // For all version above v16, each replica will start in super_read_only mode. if vtTabletVersion > 16 && vtcltlVersion > 16 { assert.True(t, replicaStatus.SuperReadOnly) } diff --git a/go/test/endtoend/utils/utils.go b/go/test/endtoend/utils/utils.go index 0cc3480faa0..aaf1bcd6644 100644 --- a/go/test/endtoend/utils/utils.go +++ b/go/test/endtoend/utils/utils.go @@ -290,7 +290,7 @@ func convertToMap(input interface{}) map[string]interface{} { func GetInitDBSQL(initDBSQL string, updatedPasswords string, oldAlterTableMode string) (string, error) { // Since password update is DML we need to insert it before we disable - // super-read-only therefore doing the split below. + // super_read_only therefore doing the split below. splitString := strings.Split(initDBSQL, "# add custom sql here") if len(splitString) < 2 { return "", fmt.Errorf("missing `# add custom sql here` in init_db.sql file") diff --git a/go/test/endtoend/vtorc/utils/utils.go b/go/test/endtoend/vtorc/utils/utils.go index ebc04fd8fa6..7fd7b26ec6f 100644 --- a/go/test/endtoend/vtorc/utils/utils.go +++ b/go/test/endtoend/vtorc/utils/utils.go @@ -316,7 +316,7 @@ func SetupVttabletsAndVTOrcs(t *testing.T, clusterInfo *VTOrcClusterInfo, numRep // cleanAndStartVttablet cleans the MySQL instance underneath for running a new test. It also starts the vttablet. func cleanAndStartVttablet(t *testing.T, clusterInfo *VTOrcClusterInfo, vttablet *cluster.Vttablet) { t.Helper() - // set super-read-only to false + // set super_read_only to false _, err := RunSQL(t, "SET GLOBAL super_read_only = OFF", vttablet, "") require.NoError(t, err) // remove the databases if they exist diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index 522aa77e97e..c880a5252c6 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -351,9 +351,9 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac if sourceIsPrimary { // No need to set read_only because super_read_only will implicitly set read_only to true as well. if !superReadOnly { - params.Logger.Infof("turning primary super-read-only before backup") + params.Logger.Infof("turning primary super_read_only before backup") if _, err = params.Mysqld.SetSuperReadOnly(true); err != nil { - return false, vterrors.Wrap(err, "can't set super-read-only status") + return false, vterrors.Wrap(err, "can't set super_read_only status") } } replicationPosition, err = params.Mysqld.PrimaryPosition() From f7b3546fffbd7f403673d1edb057a769daf469eb Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Tue, 28 Feb 2023 23:20:02 -0800 Subject: [PATCH 58/65] remove read-only flag from default.cnf Signed-off-by: Rameez Sajwani --- config/mycnf/default.cnf | 3 -- .../recovery/pitr/shardedpitr_test.go | 54 +++++-------------- 2 files changed, 14 insertions(+), 43 deletions(-) diff --git a/config/mycnf/default.cnf b/config/mycnf/default.cnf index 0a375cb69c7..c17165f9959 100644 --- a/config/mycnf/default.cnf +++ b/config/mycnf/default.cnf @@ -14,9 +14,6 @@ port = {{.MysqlPort}} secure-file-priv = {{.SecureFilePriv}} {{end}} -# all db instances should start in read-only mode - once the db is started and -# fully functional, we'll push it into read-write mode -read-only server-id = {{.ServerID}} # all db instances should skip starting replication threads - that way we can do any diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go index c2927e63660..5a7ae3e1399 100644 --- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go +++ b/go/test/endtoend/recovery/pitr/shardedpitr_test.go @@ -19,9 +19,7 @@ package pitr import ( "context" "fmt" - "os" "os/exec" - "path" "testing" "time" @@ -31,7 +29,6 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/test/endtoend/cluster" - "vitess.io/vitess/go/test/endtoend/utils" "vitess.io/vitess/go/vt/log" ) @@ -66,7 +63,7 @@ var ( shard1Name = "80-" dbName = "vt_ks" mysqlUserName = "vt_dba" - mysqlPassword = "VtDbaPass" + mysqlPassword = "password" vSchema = `{ "sharded": true, "vindexes": { @@ -411,10 +408,6 @@ func initializeCluster(t *testing.T) { shard0.Vttablets = []*cluster.Vttablet{shard0Primary, shard0Replica1, shard0Replica2} shard1.Vttablets = []*cluster.Vttablet{shard1Primary, shard1Replica1, shard1Replica2} - dbCredentialFile := cluster.WriteDbCredentialToTmp(clusterInstance.TmpDirectory) - extraArgs := []string{"--db-credentials-file", dbCredentialFile} - commonTabletArg = append(commonTabletArg, "--db-credentials-file", dbCredentialFile) - clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs, commonTabletArg...) clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs, "--restore_from_backup") @@ -423,27 +416,10 @@ func initializeCluster(t *testing.T) { vtctldClientProcess := cluster.VtctldClientProcessInstance("localhost", clusterInstance.VtctldProcess.GrpcPort, clusterInstance.TmpDirectory) out, err := vtctldClientProcess.ExecuteCommandWithOutput("SetKeyspaceDurabilityPolicy", keyspaceName, "--durability-policy=semi_sync") require.NoError(t, err, out) - - initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) - sql := string(initDb) - // The original init_db.sql does not have any passwords. Here we update the init file with passwords - sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(clusterInstance), "") - if err != nil { - require.NoError(t, err, "expected to load init_db file") - } - newInitDBFile := path.Join(clusterInstance.TmpDirectory, "init_db_with_passwords.sql") - err = os.WriteFile(newInitDBFile, []byte(sql), 0666) - if err != nil { - require.NoError(t, err, "expected to load init_db file") - } - // Start MySql var mysqlCtlProcessList []*exec.Cmd for _, shard := range clusterInstance.Keyspaces[0].Shards { for _, tablet := range shard.Vttablets { - tablet.MysqlctlProcess.InitDBFile = newInitDBFile - tablet.VttabletProcess.DbPassword = mysqlPassword - tablet.MysqlctlProcess.ExtraArgs = extraArgs proc, err := tablet.MysqlctlProcess.StartProcess() require.NoError(t, err) mysqlCtlProcessList = append(mysqlCtlProcessList, proc) @@ -456,8 +432,21 @@ func initializeCluster(t *testing.T) { require.NoError(t, err) } + queryCmds := []string{ + fmt.Sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s';", mysqlUserName, mysqlPassword), + fmt.Sprintf("GRANT ALL ON *.* TO '%s'@'%%';", mysqlUserName), + fmt.Sprintf("GRANT GRANT OPTION ON *.* TO '%s'@'%%';", mysqlUserName), + fmt.Sprintf("create database %s;", "vt_ks"), + "FLUSH PRIVILEGES;", + } + for _, shard := range clusterInstance.Keyspaces[0].Shards { for _, tablet := range shard.Vttablets { + for _, query := range queryCmds { + _, err = tablet.VttabletProcess.QueryTablet(query, keyspace.Name, false) + require.NoError(t, err) + } + err = tablet.VttabletProcess.Setup() require.NoError(t, err) } @@ -472,21 +461,6 @@ func initializeCluster(t *testing.T) { err = clusterInstance.VtctlclientProcess.InitShardPrimary(keyspaceName, shard1.Name, cell, shard1Primary.TabletUID) require.NoError(t, err) - /*queryCmds := []string{ - fmt.Sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s';", mysqlUserName, mysqlPassword), - fmt.Sprintf("GRANT ALL ON *.* TO '%s'@'%%';", mysqlUserName), - fmt.Sprintf("GRANT GRANT OPTION ON *.* TO '%s'@'%%';", mysqlUserName), - "FLUSH PRIVILEGES;", - } - - // Run DMLs on primary and let replication takes care of changes on replica - for _, tablet := range []*cluster.Vttablet{primary, shard0Primary, shard1Primary} { - for _, query := range queryCmds { - _, err = tablet.VttabletProcess.QueryTablet(query, keyspace.Name, false) - require.NoError(t, err) - } - }*/ - err = clusterInstance.StartVTOrc(keyspaceName) require.NoError(t, err) From 47ee6ad9ad9d0ff8f57fadfe021202aa2eb75ba7 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Thu, 2 Mar 2023 18:26:41 -0800 Subject: [PATCH 59/65] Removing QueryTabletWithSuperReadOnlyHandling method Signed-off-by: Rameez Sajwani --- go/test/endtoend/backup/vtbackup/main_test.go | 4 +- .../backup/vtctlbackup/backup_utils.go | 3 +- go/test/endtoend/cluster/cluster_util.go | 1 + go/test/endtoend/cluster/vttablet_process.go | 61 ---------------- .../recovery/pitr/shardedpitr_test.go | 73 ++++++++++++------- .../recovery/unshardedrecovery/recovery.go | 3 +- go/test/endtoend/vault/dbcreds_secret.json | 16 ++-- go/test/endtoend/vault/vault_test.go | 30 ++++---- 8 files changed, 82 insertions(+), 109 deletions(-) diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index d7b158ae12a..53f42585eae 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -87,7 +87,9 @@ func TestMain(m *testing.M) { // Create a new init_db.sql file that sets up passwords for all users. // Then we use a db-credentials-file with the passwords. - // We need these users/passwords during backup-restore process, for example vt_repl is needed during ResetReplication while taking backup. + // We could have operated with empty password (which is default) here as well. + // TODO: Create a separate test to test --db-credentials-file functionality (@rsajwani) + // TODO: Create a separate test to test --db-credentials-file functionality (@rsajwani) dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 7c491ca67f4..008b7d4d613 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -117,7 +117,8 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp // Create a new init_db.sql file that sets up passwords for all users. // Then we use a db-credentials-file with the passwords. - // We need these users/passwords during backup-restore process, for example vt_repl is needed during ResetReplication while taking backup. + // We could have operated with empty password (which is default) here as well. + // TODO: Create a separate test to test --db-credentials-file functionality (@rsajwani) dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) diff --git a/go/test/endtoend/cluster/cluster_util.go b/go/test/endtoend/cluster/cluster_util.go index b7f3e33e716..d68df6a4afc 100644 --- a/go/test/endtoend/cluster/cluster_util.go +++ b/go/test/endtoend/cluster/cluster_util.go @@ -303,6 +303,7 @@ func GetPasswordUpdateSQL(localCluster *LocalProcessCluster) string { SET PASSWORD FOR 'vt_allprivs'@'localhost' = 'VtAllprivsPass'; SET PASSWORD FOR 'vt_repl'@'%' = 'VtReplPass'; SET PASSWORD FOR 'vt_filtered'@'localhost' = 'VtFilteredPass'; + SET PASSWORD FOR 'vt_appdebug'@'localhost' = 'VtDebugPass'; FLUSH PRIVILEGES; ` return pwdChangeCmd diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index a8dbe6c65ff..943a8750fa3 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -628,64 +628,3 @@ func VttabletProcessInstance(port, grpcPort, tabletUID int, cell, shard, keyspac return vttablet } - -// QueryTabletWithSuperReadOnlyHandling will retry the query up to 10 times with a small sleep in between each try. -// This allows the tests to be more robust in the face of transient failures. It disables super_read_only during query execution. -func (vttablet *VttabletProcess) QueryTabletWithSuperReadOnlyHandling(query string, keyspace string, useDb bool) (*sqltypes.Result, error) { - var ( - err error - result *sqltypes.Result - ) - if !useDb { - keyspace = "" - } - dbParams := NewConnParams(vttablet.DbPort, vttablet.DbPassword, path.Join(vttablet.Directory, "mysql.sock"), keyspace) - conn, err := vttablet.conn(&dbParams) - if err != nil { - return nil, err - } - defer conn.Close() - retries := 10 - retryDelay := 1 * time.Second - for i := 0; i < retries; i++ { - if i > 0 { - // We only audit from 2nd attempt and onwards, otherwise this is just too verbose. - log.Infof("Executing query %s (attempt %d of %d)", query, i+1, retries) - } - result, err = executeFetchWithSuperReadOnlyHandling(conn, query, 10000, true) - if err == nil { - break - } - time.Sleep(retryDelay) - } - - return result, err -} - -// This function will temporarily turn `OFF` super_read_only global variable and reverts it back after query is executed. -func executeFetchWithSuperReadOnlyHandling(dbConn *mysql.Conn, query string, maxRows int, wantFields bool) (result *sqltypes.Result, err error) { - // Note: MariaDB does not have super_read_only but support for it is EOL in v14.0+ - if !dbConn.IsMariaDB() { - if err := dbConn.WriteComQuery("SELECT @@global.super_read_only"); err != nil { - return nil, err - } - res, _, _, err := dbConn.ReadQueryResult(1, false) - if err == nil && len(res.Rows) == 1 { - sro := res.Rows[0][0].ToString() - if sro == "1" || sro == "ON" { - if _, err = dbConn.ExecuteFetch("SET GLOBAL super_read_only='OFF'", 1, false); err != nil { - return nil, err - } - defer func() { - if _, err := dbConn.ExecuteFetch("SET GLOBAL super_read_only='ON'", 1, false); err != nil { - log.Errorf("error setting super_read_only value %s", err.Error()) - } - }() - } - } - } - - result, _, err = dbConn.ExecuteFetchMulti(query, maxRows, wantFields) - - return result, err -} diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go index 5a7ae3e1399..c7962705dfb 100644 --- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go +++ b/go/test/endtoend/recovery/pitr/shardedpitr_test.go @@ -19,7 +19,9 @@ package pitr import ( "context" "fmt" + "os" "os/exec" + "path" "testing" "time" @@ -29,6 +31,7 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/test/endtoend/cluster" + "vitess.io/vitess/go/test/endtoend/utils" "vitess.io/vitess/go/vt/log" ) @@ -51,20 +54,22 @@ var ( shard1Replica1 *cluster.Vttablet shard1Replica2 *cluster.Vttablet - cell = "zone1" - hostname = "localhost" - binlogHost = "127.0.0.1" - keyspaceName = "ks" - restoreKS1Name = "restoreks1" - restoreKS2Name = "restoreks2" - restoreKS3Name = "restoreks3" - shardName = "0" - shard0Name = "-80" - shard1Name = "80-" - dbName = "vt_ks" - mysqlUserName = "vt_dba" - mysqlPassword = "password" - vSchema = `{ + cell = "zone1" + hostname = "localhost" + binlogHost = "127.0.0.1" + keyspaceName = "ks" + restoreKS1Name = "restoreks1" + restoreKS2Name = "restoreks2" + restoreKS3Name = "restoreks3" + shardName = "0" + shard0Name = "-80" + shard1Name = "80-" + dbName = "vt_ks" + mysqlUserName = "vt_dba" + mysqlPassword = "VtDbaPass" + dbCredentialFile = "" + initDBFileWithPassword = "" + vSchema = `{ "sharded": true, "vindexes": { "hash_index": { @@ -408,6 +413,10 @@ func initializeCluster(t *testing.T) { shard0.Vttablets = []*cluster.Vttablet{shard0Primary, shard0Replica1, shard0Replica2} shard1.Vttablets = []*cluster.Vttablet{shard1Primary, shard1Replica1, shard1Replica2} + dbCredentialFile = cluster.WriteDbCredentialToTmp(clusterInstance.TmpDirectory) + extraArgs := []string{"--db-credentials-file", dbCredentialFile} + commonTabletArg = append(commonTabletArg, "--db-credentials-file", dbCredentialFile) + clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs, commonTabletArg...) clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs, "--restore_from_backup") @@ -416,10 +425,27 @@ func initializeCluster(t *testing.T) { vtctldClientProcess := cluster.VtctldClientProcessInstance("localhost", clusterInstance.VtctldProcess.GrpcPort, clusterInstance.TmpDirectory) out, err := vtctldClientProcess.ExecuteCommandWithOutput("SetKeyspaceDurabilityPolicy", keyspaceName, "--durability-policy=semi_sync") require.NoError(t, err, out) + + initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) + sql := string(initDb) + // The original init_db.sql does not have any passwords. Here we update the init file with passwords + sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(clusterInstance), "") + if err != nil { + require.NoError(t, err, "expected to load init_db file") + } + initDBFileWithPassword = path.Join(clusterInstance.TmpDirectory, "init_db_with_passwords.sql") + err = os.WriteFile(initDBFileWithPassword, []byte(sql), 0666) + if err != nil { + require.NoError(t, err, "expected to load init_db file") + } + // Start MySql var mysqlCtlProcessList []*exec.Cmd for _, shard := range clusterInstance.Keyspaces[0].Shards { for _, tablet := range shard.Vttablets { + tablet.MysqlctlProcess.InitDBFile = initDBFileWithPassword + tablet.VttabletProcess.DbPassword = mysqlPassword + tablet.MysqlctlProcess.ExtraArgs = extraArgs proc, err := tablet.MysqlctlProcess.StartProcess() require.NoError(t, err) mysqlCtlProcessList = append(mysqlCtlProcessList, proc) @@ -432,21 +458,8 @@ func initializeCluster(t *testing.T) { require.NoError(t, err) } - queryCmds := []string{ - fmt.Sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s';", mysqlUserName, mysqlPassword), - fmt.Sprintf("GRANT ALL ON *.* TO '%s'@'%%';", mysqlUserName), - fmt.Sprintf("GRANT GRANT OPTION ON *.* TO '%s'@'%%';", mysqlUserName), - fmt.Sprintf("create database %s;", "vt_ks"), - "FLUSH PRIVILEGES;", - } - for _, shard := range clusterInstance.Keyspaces[0].Shards { for _, tablet := range shard.Vttablets { - for _, query := range queryCmds { - _, err = tablet.VttabletProcess.QueryTablet(query, keyspace.Name, false) - require.NoError(t, err) - } - err = tablet.VttabletProcess.Setup() require.NoError(t, err) } @@ -550,9 +563,15 @@ func launchRecoveryTablet(t *testing.T, tablet *cluster.Vttablet, binlogServer * "--lock_tables_timeout", "5s", "--watch_replication_stream", "--serving_state_grace_period", "1s", + "--db-credentials-file", dbCredentialFile, } tablet.VttabletProcess.ServingStatus = "" + extraArgs := []string{"--db-credentials-file", dbCredentialFile} + tablet.MysqlctlProcess.InitDBFile = initDBFileWithPassword + tablet.VttabletProcess.DbPassword = mysqlPassword + tablet.MysqlctlProcess.ExtraArgs = extraArgs + err = tablet.VttabletProcess.Setup() require.NoError(t, err) diff --git a/go/test/endtoend/recovery/unshardedrecovery/recovery.go b/go/test/endtoend/recovery/unshardedrecovery/recovery.go index 77d24d1aa13..df945b21cac 100644 --- a/go/test/endtoend/recovery/unshardedrecovery/recovery.go +++ b/go/test/endtoend/recovery/unshardedrecovery/recovery.go @@ -94,7 +94,8 @@ func TestMainImpl(m *testing.M) { // Create a new init_db.sql file that sets up passwords for all users. // Then we use a db-credentials-file with the passwords. - // We need these users/passwords during backup-restore process, for example vt_repl is needed during ResetReplication while taking backup. + // We could have operated with empty password (which is default) here as well. + // TODO: Create a separate test to test --db-credentials-file functionality (@rsajwani) dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) diff --git a/go/test/endtoend/vault/dbcreds_secret.json b/go/test/endtoend/vault/dbcreds_secret.json index 96fff38bdcd..ee0a4af534b 100644 --- a/go/test/endtoend/vault/dbcreds_secret.json +++ b/go/test/endtoend/vault/dbcreds_secret.json @@ -1,17 +1,23 @@ { + "root": [ + "RootPass" + ], "vt_app": [ - "password" + "VtAppPass" ], "vt_dba": [ - "password" + "VtDbaPass" ], "vt_repl": [ - "password" + "VtReplPass" ], "vt_appdebug": [ - "password" + "VtDebugPass" ], "vt_filtered": [ - "password" + "VtFilteredPass" + ], + "vt_allprivs": [ + "VtAllprivsPass" ] } diff --git a/go/test/endtoend/vault/vault_test.go b/go/test/endtoend/vault/vault_test.go index ff8aa709149..4945bb2c95d 100644 --- a/go/test/endtoend/vault/vault_test.go +++ b/go/test/endtoend/vault/vault_test.go @@ -33,6 +33,7 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/test/endtoend/cluster" + "vitess.io/vitess/go/test/endtoend/utils" "vitess.io/vitess/go/vt/log" ) @@ -53,7 +54,7 @@ var ( shardName = "0" dbName = "vt_ks" mysqlUsers = []string{"vt_dba", "vt_app", "vt_appdebug", "vt_repl", "vt_filtered"} - mysqlPassword = "password" + mysqlPassword = "VtDbaPass" vtgateUser = "vtgate_user" vtgatePassword = "password123" commonTabletArg = []string{ @@ -251,10 +252,25 @@ func initializeClusterLate(t *testing.T) { out, err := vtctldClientProcess.ExecuteCommandWithOutput("SetKeyspaceDurabilityPolicy", keyspaceName, "--durability-policy=semi_sync") require.NoError(t, err, out) + initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) + sql := string(initDb) + // The original init_db.sql does not have any passwords. Here we update the init file with passwords + sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(clusterInstance), "") + if err != nil { + require.NoError(t, err, "expected to load init_db file") + } + newInitDBFile := path.Join(clusterInstance.TmpDirectory, "init_db_with_passwords.sql") + err = os.WriteFile(newInitDBFile, []byte(sql), 0666) + if err != nil { + require.NoError(t, err, "expected to load init_db file") + } + // Start MySQL var mysqlCtlProcessList []*exec.Cmd for _, shard := range clusterInstance.Keyspaces[0].Shards { for _, tablet := range shard.Vttablets { + tablet.MysqlctlProcess.InitDBFile = newInitDBFile + tablet.VttabletProcess.DbPassword = mysqlPassword proc, err := tablet.MysqlctlProcess.StartProcess() require.NoError(t, err) mysqlCtlProcessList = append(mysqlCtlProcessList, proc) @@ -269,18 +285,6 @@ func initializeClusterLate(t *testing.T) { // TODO: may be put them in init_db at runtime, then we don't need superReadOnly handling for _, tablet := range []*cluster.Vttablet{primary, replica} { - for _, user := range mysqlUsers { - query := fmt.Sprintf("ALTER USER '%s'@'%s' IDENTIFIED BY '%s';", user, hostname, mysqlPassword) - _, err = tablet.VttabletProcess.QueryTabletWithSuperReadOnlyHandling(query, keyspace.Name, false) - // Reset after the first ALTER, or we lock ourselves out. - tablet.VttabletProcess.DbPassword = mysqlPassword - if err != nil { - query = fmt.Sprintf("ALTER USER '%s'@'%%' IDENTIFIED BY '%s';", user, mysqlPassword) - _, err = tablet.VttabletProcess.QueryTabletWithSuperReadOnlyHandling(query, keyspace.Name, false) - require.NoError(t, err) - } - } - err = tablet.VttabletProcess.Setup() require.NoError(t, err) From 2be31470e4a9ae56661915f343b36b4566813bee Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Fri, 3 Mar 2023 08:33:07 -0800 Subject: [PATCH 60/65] moving flag at right place Signed-off-by: Rameez Sajwani --- go/test/endtoend/recovery/pitr/shardedpitr_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go index c7962705dfb..c5cb7962c41 100644 --- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go +++ b/go/test/endtoend/recovery/pitr/shardedpitr_test.go @@ -523,6 +523,10 @@ func testTabletRecovery(t *testing.T, binlogServer *binLogServer, lookupTimeout, func launchRecoveryTablet(t *testing.T, tablet *cluster.Vttablet, binlogServer *binLogServer, lookupTimeout, restoreKeyspaceName, shardName string) { tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + extraArgs := []string{"--db-credentials-file", dbCredentialFile} + tablet.MysqlctlProcess.InitDBFile = initDBFileWithPassword + tablet.VttabletProcess.DbPassword = mysqlPassword + tablet.MysqlctlProcess.ExtraArgs = extraArgs err := tablet.MysqlctlProcess.Start() require.NoError(t, err) @@ -567,11 +571,6 @@ func launchRecoveryTablet(t *testing.T, tablet *cluster.Vttablet, binlogServer * } tablet.VttabletProcess.ServingStatus = "" - extraArgs := []string{"--db-credentials-file", dbCredentialFile} - tablet.MysqlctlProcess.InitDBFile = initDBFileWithPassword - tablet.VttabletProcess.DbPassword = mysqlPassword - tablet.MysqlctlProcess.ExtraArgs = extraArgs - err = tablet.VttabletProcess.Setup() require.NoError(t, err) From cf9b781cc04ae3013574190a106a379130b9ef06 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Tue, 7 Mar 2023 11:26:09 -0800 Subject: [PATCH 61/65] code review feedback Signed-off-by: Rameez Sajwani --- config/mycnf/test-suite.cnf | 3 +- go/test/endtoend/backup/vtbackup/main_test.go | 9 ++++-- .../backup/vtctlbackup/backup_utils.go | 14 +++++++-- go/test/endtoend/cellalias/cell_alias_test.go | 6 +++- go/test/endtoend/cluster/cluster_process.go | 18 +++++++++-- go/test/endtoend/cluster/mysqlctl_process.go | 27 ++++++++++------- go/test/endtoend/cluster/mysqlctld_process.go | 11 ++++--- .../encrypted_replication_test.go | 6 +++- .../encrypted_transport_test.go | 6 +++- go/test/endtoend/mysqlctl/mysqlctl_test.go | 6 +++- go/test/endtoend/mysqlctld/mysqlctld_test.go | 8 +++-- .../recovery/pitr/shardedpitr_test.go | 8 +++-- .../recovery/unshardedrecovery/recovery.go | 8 +++-- go/test/endtoend/reparent/utils/utils.go | 6 +++- .../endtoend/sharded/sharded_keyspace_test.go | 6 +++- go/test/endtoend/tabletmanager/tablet_test.go | 16 +++++++--- go/test/endtoend/topoconncache/main_test.go | 6 +++- .../topoconncache/topo_conn_cache_test.go | 6 +++- go/test/endtoend/vreplication/cluster_test.go | 6 +++- go/vt/vtexplain/vtexplain_vttablet.go | 30 +++++++++---------- 20 files changed, 146 insertions(+), 60 deletions(-) diff --git a/config/mycnf/test-suite.cnf b/config/mycnf/test-suite.cnf index 5a1ada5a75b..318bc4c824f 100644 --- a/config/mycnf/test-suite.cnf +++ b/config/mycnf/test-suite.cnf @@ -23,6 +23,7 @@ sql_mode = STRICT_TRANS_TABLES # set a short heartbeat interval in order to detect failures quickly slave_net_timeout = 4 -# test-suite is mainly used for vttestserver, which does not need super-read-only. Therefore, +# Disabling `super-read-only`. `test-suite` is mainly used for `vttestserver`. Since `vttestserver` uses a single MySQL for primary and replicas, +# so it is not possible to run it with `super-read-only`. # we are disabling it. super-read-only = false diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index 53f42585eae..2f24799ebec 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -88,8 +88,7 @@ func TestMain(m *testing.M) { // Create a new init_db.sql file that sets up passwords for all users. // Then we use a db-credentials-file with the passwords. // We could have operated with empty password (which is default) here as well. - // TODO: Create a separate test to test --db-credentials-file functionality (@rsajwani) - // TODO: Create a separate test to test --db-credentials-file functionality (@rsajwani) + // TODO: Create a separate test for --db-credentials-file functionality (@rsajwani) dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) @@ -120,7 +119,11 @@ func TestMain(m *testing.M) { tablet.VttabletProcess.ExtraArgs = commonTabletArg tablet.VttabletProcess.SupportsBackup = true - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, localCluster.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, localCluster.TmpDirectory) + if err != nil { + return 1, err + } + tablet.MysqlctlProcess = *mysqlctlProcess tablet.MysqlctlProcess.InitDBFile = newInitDBFile tablet.MysqlctlProcess.ExtraArgs = extraArgs proc, err := tablet.MysqlctlProcess.StartProcess() diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 008b7d4d613..ce527e0d72b 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -118,7 +118,7 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp // Create a new init_db.sql file that sets up passwords for all users. // Then we use a db-credentials-file with the passwords. // We could have operated with empty password (which is default) here as well. - // TODO: Create a separate test to test --db-credentials-file functionality (@rsajwani) + // TODO: Create a separate test for --db-credentials-file functionality (@rsajwani) dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) @@ -171,7 +171,11 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp tablet.VttabletProcess.SupportsBackup = true if setupType == Mysqlctld { - tablet.MysqlctldProcess = *cluster.MysqlCtldProcessInstance(tablet.TabletUID, tablet.MySQLPort, localCluster.TmpDirectory) + mysqlctldProcess, err := cluster.MysqlCtldProcessInstance(tablet.TabletUID, tablet.MySQLPort, localCluster.TmpDirectory) + if err != nil { + return 1, err + } + tablet.MysqlctldProcess = *mysqlctldProcess tablet.MysqlctldProcess.InitDBFile = newInitDBFile tablet.MysqlctldProcess.ExtraArgs = extraArgs tablet.MysqlctldProcess.Password = tablet.VttabletProcess.DbPassword @@ -182,7 +186,11 @@ func LaunchCluster(setupType int, streamMode string, stripes int, cDetails *Comp continue } - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, localCluster.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, localCluster.TmpDirectory) + if err != nil { + return 1, err + } + tablet.MysqlctlProcess = *mysqlctlProcess tablet.MysqlctlProcess.InitDBFile = newInitDBFile tablet.MysqlctlProcess.ExtraArgs = extraArgs proc, err := tablet.MysqlctlProcess.StartProcess() diff --git a/go/test/endtoend/cellalias/cell_alias_test.go b/go/test/endtoend/cellalias/cell_alias_test.go index 47f3108e6c7..3b6aa8c6bda 100644 --- a/go/test/endtoend/cellalias/cell_alias_test.go +++ b/go/test/endtoend/cellalias/cell_alias_test.go @@ -132,7 +132,11 @@ func TestMain(m *testing.M) { var mysqlProcs []*exec.Cmd for _, tablet := range []*cluster.Vttablet{shard1Primary, shard1Replica, shard1Rdonly, shard2Primary, shard2Replica, shard2Rdonly} { - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, localCluster.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, localCluster.TmpDirectory) + if err != nil { + return 1, err + } + tablet.MysqlctlProcess = *mysqlctlProcess tablet.VttabletProcess = cluster.VttabletProcessInstance(tablet.HTTPPort, tablet.GrpcPort, tablet.TabletUID, diff --git a/go/test/endtoend/cluster/cluster_process.go b/go/test/endtoend/cluster/cluster_process.go index 7786f86736b..e7df056fa56 100644 --- a/go/test/endtoend/cluster/cluster_process.go +++ b/go/test/endtoend/cluster/cluster_process.go @@ -352,7 +352,11 @@ func (cluster *LocalProcessCluster) startKeyspace(keyspace Keyspace, shardNames } // Start Mysqlctl process log.Infof("Starting mysqlctl for table uid %d, mysql port %d", tablet.TabletUID, tablet.MySQLPort) - tablet.MysqlctlProcess = *MysqlCtlProcessInstanceOptionalInit(tablet.TabletUID, tablet.MySQLPort, cluster.TmpDirectory, !cluster.ReusingVTDATAROOT) + mysqlctlProcess, err := MysqlCtlProcessInstanceOptionalInit(tablet.TabletUID, tablet.MySQLPort, cluster.TmpDirectory, !cluster.ReusingVTDATAROOT) + if err != nil { + return err + } + tablet.MysqlctlProcess = *mysqlctlProcess proc, err := tablet.MysqlctlProcess.StartProcess() if err != nil { log.Errorf("error starting mysqlctl process: %v, %v", tablet.MysqlctldProcess, err) @@ -499,7 +503,11 @@ func (cluster *LocalProcessCluster) StartKeyspaceLegacy(keyspace Keyspace, shard } // Start Mysqlctl process log.Infof("Starting mysqlctl for table uid %d, mysql port %d", tablet.TabletUID, tablet.MySQLPort) - tablet.MysqlctlProcess = *MysqlCtlProcessInstanceOptionalInit(tablet.TabletUID, tablet.MySQLPort, cluster.TmpDirectory, !cluster.ReusingVTDATAROOT) + mysqlctlProcess, err := MysqlCtlProcessInstanceOptionalInit(tablet.TabletUID, tablet.MySQLPort, cluster.TmpDirectory, !cluster.ReusingVTDATAROOT) + if err != nil { + return err + } + tablet.MysqlctlProcess = *mysqlctlProcess proc, err := tablet.MysqlctlProcess.StartProcess() if err != nil { log.Errorf("error starting mysqlctl process: %v, %v", tablet.MysqlctldProcess, err) @@ -619,7 +627,11 @@ func (cluster *LocalProcessCluster) SetupCluster(keyspace *Keyspace, shards []Sh for _, shard := range shards { for _, tablet := range shard.Vttablets { // Setup MysqlctlProcess - tablet.MysqlctlProcess = *MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, cluster.TmpDirectory) + mysqlctlProcess, err := MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, cluster.TmpDirectory) + if err != nil { + return err + } + tablet.MysqlctlProcess = *mysqlctlProcess // Setup VttabletProcess tablet.VttabletProcess = VttabletProcessInstance( tablet.HTTPPort, diff --git a/go/test/endtoend/cluster/mysqlctl_process.go b/go/test/endtoend/cluster/mysqlctl_process.go index 429c536a4d2..800cc6118eb 100644 --- a/go/test/endtoend/cluster/mysqlctl_process.go +++ b/go/test/endtoend/cluster/mysqlctl_process.go @@ -236,11 +236,10 @@ func (mysqlctl *MysqlctlProcess) Connect(ctx context.Context, username string) ( // MysqlCtlProcessInstanceOptionalInit returns a Mysqlctl handle for mysqlctl process // configured with the given Config. -func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirectory string, initMySQL bool) *MysqlctlProcess { - var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value - updatedInitFile, err := getInitDBFile() - if err == nil { - initFile = updatedInitFile +func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirectory string, initMySQL bool) (*MysqlctlProcess, error) { + initFile, err := getInitDBFile() + if err != nil { + return nil, err } mysqlctl := &MysqlctlProcess{ Name: "mysqlctl", @@ -252,7 +251,7 @@ func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirect mysqlctl.TabletUID = tabletUID mysqlctl.InitMysql = initMySQL mysqlctl.SecureTransport = false - return mysqlctl + return mysqlctl, nil } func getInitDBFile() (string, error) { @@ -272,20 +271,28 @@ func getInitDBFile() (string, error) { // MysqlCtlProcessInstance returns a Mysqlctl handle for mysqlctl process // configured with the given Config. -func MysqlCtlProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) *MysqlctlProcess { +func MysqlCtlProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) (*MysqlctlProcess, error) { return MysqlCtlProcessInstanceOptionalInit(tabletUID, mySQLPort, tmpDirectory, true) } // StartMySQL starts mysqlctl process func StartMySQL(ctx context.Context, tablet *Vttablet, username string, tmpDirectory string) error { - tablet.MysqlctlProcess = *MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, tmpDirectory) + mysqlctlProcess, err := MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, tmpDirectory) + if err != nil { + return err + } + tablet.MysqlctlProcess = *mysqlctlProcess return tablet.MysqlctlProcess.Start() } // StartMySQLAndGetConnection create a connection to tablet mysql func StartMySQLAndGetConnection(ctx context.Context, tablet *Vttablet, username string, tmpDirectory string) (*mysql.Conn, error) { - tablet.MysqlctlProcess = *MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, tmpDirectory) - err := tablet.MysqlctlProcess.Start() + mysqlctlProcess, err := MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, tmpDirectory) + if err != nil { + return nil, err + } + tablet.MysqlctlProcess = *mysqlctlProcess + err = tablet.MysqlctlProcess.Start() if err != nil { return nil, err } diff --git a/go/test/endtoend/cluster/mysqlctld_process.go b/go/test/endtoend/cluster/mysqlctld_process.go index eef1afc83a5..685cff54c8e 100644 --- a/go/test/endtoend/cluster/mysqlctld_process.go +++ b/go/test/endtoend/cluster/mysqlctld_process.go @@ -144,11 +144,10 @@ func (mysqlctld *MysqlctldProcess) CleanupFiles(tabletUID int) { // MysqlCtldProcessInstance returns a Mysqlctld handle for mysqlctld process // configured with the given Config. -func MysqlCtldProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) *MysqlctldProcess { - var initFile = path.Join(os.Getenv("VTROOT"), "/config/init_db.sql") //default value - updatedInitFile, err := getInitDBFile() - if err == nil { - initFile = updatedInitFile +func MysqlCtldProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) (*MysqlctldProcess, error) { + initFile, err := getInitDBFile() + if err != nil { + return nil, err } mysqlctld := &MysqlctldProcess{ Name: "mysqlctld", @@ -159,7 +158,7 @@ func MysqlCtldProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) mysqlctld.MySQLPort = mySQLPort mysqlctld.TabletUID = tabletUID mysqlctld.InitMysql = true - return mysqlctld + return mysqlctld, nil } // IsHealthy gives the health status of mysql. diff --git a/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go b/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go index 8900db58ce1..d7de8052599 100644 --- a/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go +++ b/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go @@ -142,7 +142,11 @@ func initializeCluster(t *testing.T) (int, error) { tablet := clusterInstance.NewVttabletInstance("replica", tabletUID, cell) // Start Mysqlctl process - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + return 1, err + } + tablet.MysqlctlProcess = *mysqlctlProcess proc, err := tablet.MysqlctlProcess.StartProcess() if err != nil { return 1, err diff --git a/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go b/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go index b0d0a507a43..e81b019d273 100644 --- a/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go +++ b/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go @@ -360,7 +360,11 @@ func clusterSetUp(t *testing.T) (int, error) { tablet := clusterInstance.NewVttabletInstance("replica", 0, cell) // Start Mysqlctl process - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + return 1, err + } + tablet.MysqlctlProcess = *mysqlctlProcess proc, err := tablet.MysqlctlProcess.StartProcess() if err != nil { return 1, err diff --git a/go/test/endtoend/mysqlctl/mysqlctl_test.go b/go/test/endtoend/mysqlctl/mysqlctl_test.go index ec54ffb91d5..5b348cd4eb5 100644 --- a/go/test/endtoend/mysqlctl/mysqlctl_test.go +++ b/go/test/endtoend/mysqlctl/mysqlctl_test.go @@ -96,7 +96,11 @@ func initCluster(shardNames []string, totalTabletsRequired int) { tablet.Type = "primary" } // Start Mysqlctl process - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + return + } + tablet.MysqlctlProcess = *mysqlctlProcess proc, err := tablet.MysqlctlProcess.StartProcess() if err != nil { return diff --git a/go/test/endtoend/mysqlctld/mysqlctld_test.go b/go/test/endtoend/mysqlctld/mysqlctld_test.go index 28d2bb71ced..89e35aea31d 100644 --- a/go/test/endtoend/mysqlctld/mysqlctld_test.go +++ b/go/test/endtoend/mysqlctld/mysqlctld_test.go @@ -96,8 +96,12 @@ func initCluster(shardNames []string, totalTabletsRequired int) error { tablet.Type = "primary" } // Start Mysqlctld process - tablet.MysqlctldProcess = *cluster.MysqlCtldProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) - err := tablet.MysqlctldProcess.Start() + mysqlctldProcess, err := cluster.MysqlCtldProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + return err + } + tablet.MysqlctldProcess = *mysqlctldProcess + err = tablet.MysqlctldProcess.Start() if err != nil { return err } diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go index c5cb7962c41..0f1e860c4b3 100644 --- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go +++ b/go/test/endtoend/recovery/pitr/shardedpitr_test.go @@ -522,12 +522,16 @@ func testTabletRecovery(t *testing.T, binlogServer *binLogServer, lookupTimeout, } func launchRecoveryTablet(t *testing.T, tablet *cluster.Vttablet, binlogServer *binLogServer, lookupTimeout, restoreKeyspaceName, shardName string) { - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + require.NoError(t, err) + } + tablet.MysqlctlProcess = *mysqlctlProcess extraArgs := []string{"--db-credentials-file", dbCredentialFile} tablet.MysqlctlProcess.InitDBFile = initDBFileWithPassword tablet.VttabletProcess.DbPassword = mysqlPassword tablet.MysqlctlProcess.ExtraArgs = extraArgs - err := tablet.MysqlctlProcess.Start() + err = tablet.MysqlctlProcess.Start() require.NoError(t, err) tablet.VttabletProcess = cluster.VttabletProcessInstance( diff --git a/go/test/endtoend/recovery/unshardedrecovery/recovery.go b/go/test/endtoend/recovery/unshardedrecovery/recovery.go index df945b21cac..653c5b9fb26 100644 --- a/go/test/endtoend/recovery/unshardedrecovery/recovery.go +++ b/go/test/endtoend/recovery/unshardedrecovery/recovery.go @@ -95,7 +95,7 @@ func TestMainImpl(m *testing.M) { // Create a new init_db.sql file that sets up passwords for all users. // Then we use a db-credentials-file with the passwords. // We could have operated with empty password (which is default) here as well. - // TODO: Create a separate test to test --db-credentials-file functionality (@rsajwani) + // TODO: Create a separate test for --db-credentials-file functionality (@rsajwani) dbCredentialFile = cluster.WriteDbCredentialToTmp(localCluster.TmpDirectory) initDb, _ := os.ReadFile(path.Join(os.Getenv("VTROOT"), "/config/init_db.sql")) sql := string(initDb) @@ -130,7 +130,11 @@ func TestMainImpl(m *testing.M) { } tablet.VttabletProcess.SupportsBackup = true - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, localCluster.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, localCluster.TmpDirectory) + if err != nil { + return 1, err + } + tablet.MysqlctlProcess = *mysqlctlProcess tablet.MysqlctlProcess.InitDBFile = newInitDBFile tablet.MysqlctlProcess.ExtraArgs = extraArgs proc, err := tablet.MysqlctlProcess.StartProcess() diff --git a/go/test/endtoend/reparent/utils/utils.go b/go/test/endtoend/reparent/utils/utils.go index c2ab9d48306..93440e23f76 100644 --- a/go/test/endtoend/reparent/utils/utils.go +++ b/go/test/endtoend/reparent/utils/utils.go @@ -193,7 +193,11 @@ func StartNewVTTablet(t *testing.T, clusterInstance *cluster.LocalProcessCluster shard := keyspace.Shards[0] // Setup MysqlctlProcess - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + require.NoError(t, err) + } + tablet.MysqlctlProcess = *mysqlctlProcess // Setup VttabletProcess tablet.VttabletProcess = cluster.VttabletProcessInstance( tablet.HTTPPort, diff --git a/go/test/endtoend/sharded/sharded_keyspace_test.go b/go/test/endtoend/sharded/sharded_keyspace_test.go index d5f5e5b2255..0298da0bdb2 100644 --- a/go/test/endtoend/sharded/sharded_keyspace_test.go +++ b/go/test/endtoend/sharded/sharded_keyspace_test.go @@ -215,7 +215,11 @@ func initCluster(shardNames []string, totalTabletsRequired int) { tablet.Type = "primary" } // Start Mysqlctl process - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + return + } + tablet.MysqlctlProcess = *mysqlctlProcess proc, err := tablet.MysqlctlProcess.StartProcess() if err != nil { return diff --git a/go/test/endtoend/tabletmanager/tablet_test.go b/go/test/endtoend/tabletmanager/tablet_test.go index 3c597e97981..bd07650d9b5 100644 --- a/go/test/endtoend/tabletmanager/tablet_test.go +++ b/go/test/endtoend/tabletmanager/tablet_test.go @@ -34,8 +34,12 @@ func TestEnsureDB(t *testing.T) { // Create new tablet tablet := clusterInstance.NewVttabletInstance("replica", 0, "") - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) - err := tablet.MysqlctlProcess.Start() + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + return + } + tablet.MysqlctlProcess = *mysqlctlProcess + err = tablet.MysqlctlProcess.Start() require.NoError(t, err) log.Info(fmt.Sprintf("Started vttablet %v", tablet)) @@ -67,8 +71,12 @@ func TestResetReplicationParameters(t *testing.T) { // Create new tablet tablet := clusterInstance.NewVttabletInstance("replica", 0, "") - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) - err := tablet.MysqlctlProcess.Start() + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + require.NoError(t, err) + } + tablet.MysqlctlProcess = *mysqlctlProcess + err = tablet.MysqlctlProcess.Start() require.NoError(t, err) log.Info(fmt.Sprintf("Started vttablet %v", tablet)) diff --git a/go/test/endtoend/topoconncache/main_test.go b/go/test/endtoend/topoconncache/main_test.go index 2a074e8428a..7cfea8839b0 100644 --- a/go/test/endtoend/topoconncache/main_test.go +++ b/go/test/endtoend/topoconncache/main_test.go @@ -140,7 +140,11 @@ func TestMain(m *testing.M) { var mysqlProcs []*exec.Cmd for _, tablet := range []*cluster.Vttablet{shard1Primary, shard1Replica, shard1Rdonly, shard2Primary, shard2Replica, shard2Rdonly} { - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + return 1, err + } + tablet.MysqlctlProcess = *mysqlctlProcess tablet.VttabletProcess = cluster.VttabletProcessInstance(tablet.HTTPPort, tablet.GrpcPort, tablet.TabletUID, diff --git a/go/test/endtoend/topoconncache/topo_conn_cache_test.go b/go/test/endtoend/topoconncache/topo_conn_cache_test.go index 02f14a7304d..2ebdf3f32b2 100644 --- a/go/test/endtoend/topoconncache/topo_conn_cache_test.go +++ b/go/test/endtoend/topoconncache/topo_conn_cache_test.go @@ -136,7 +136,11 @@ func addCellback(t *testing.T) { // create sql process for vttablets var mysqlProcs []*exec.Cmd for _, tablet := range []*cluster.Vttablet{shard1Replica, shard1Rdonly, shard2Replica, shard2Rdonly} { - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) + if err != nil { + require.NoError(t, err) + } + tablet.MysqlctlProcess = *mysqlctlProcess tablet.VttabletProcess = cluster.VttabletProcessInstance(tablet.HTTPPort, tablet.GrpcPort, tablet.TabletUID, diff --git a/go/test/endtoend/vreplication/cluster_test.go b/go/test/endtoend/vreplication/cluster_test.go index 43991454b6e..5c5dd4922c9 100644 --- a/go/test/endtoend/vreplication/cluster_test.go +++ b/go/test/endtoend/vreplication/cluster_test.go @@ -450,7 +450,11 @@ func (vc *VitessCluster) AddTablet(t testing.TB, cell *Cell, keyspace *Keyspace, require.NotNil(t, vttablet) vttablet.SupportsBackup = false - tablet.DbServer = cluster.MysqlCtlProcessInstance(tabletID, vc.ClusterConfig.tabletMysqlPortBase+tabletID, vc.ClusterConfig.tmpDir) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tabletID, vc.ClusterConfig.tabletMysqlPortBase+tabletID, vc.ClusterConfig.tmpDir) + if err != nil { + require.NoError(t, err) + } + tablet.DbServer = mysqlctlProcess require.NotNil(t, tablet.DbServer) tablet.DbServer.InitMysql = true proc, err := tablet.DbServer.StartProcess() diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 2d38bd8a102..94c03671659 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -496,21 +496,6 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* t.mu.Lock() defer t.mu.Unlock() - if !strings.Contains(query, "1 != 1") { - t.mysqlQueries = append(t.mysqlQueries, &MysqlQuery{ - Time: t.currentTime, - SQL: query, - }) - } - - // return the pre-computed results for any schema introspection queries - tEnv := t.vte.getGlobalTabletEnv() - result := tEnv.getResult(query) - - if result != nil { - return callback(result) - } - // If query is part of rejected list then return error right away. if err := t.db.GetRejectedQueryResult(query); err != nil { return err @@ -535,6 +520,21 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* return callback(expResult.Result) } + if !strings.Contains(query, "1 != 1") { + t.mysqlQueries = append(t.mysqlQueries, &MysqlQuery{ + Time: t.currentTime, + SQL: query, + }) + } + + // return the pre-computed results for any schema introspection queries + tEnv := t.vte.getGlobalTabletEnv() + result := tEnv.getResult(query) + + if result != nil { + return callback(result) + } + switch sqlparser.Preview(query) { case sqlparser.StmtSelect: var err error From 30f36d6f728122b3f3397905e810525fc6e42a2f Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Tue, 7 Mar 2023 20:03:54 -0800 Subject: [PATCH 62/65] fixing require.noerror check Signed-off-by: Rameez Sajwani --- go/test/endtoend/reparent/utils/utils.go | 4 +--- go/test/endtoend/tabletmanager/tablet_test.go | 4 +--- go/test/endtoend/topoconncache/topo_conn_cache_test.go | 4 +--- go/test/endtoend/vreplication/cluster_test.go | 4 +--- .../vtgate/tablet_healthcheck_cache/correctness_test.go | 4 +++- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/go/test/endtoend/reparent/utils/utils.go b/go/test/endtoend/reparent/utils/utils.go index 93440e23f76..1ec834f1cc7 100644 --- a/go/test/endtoend/reparent/utils/utils.go +++ b/go/test/endtoend/reparent/utils/utils.go @@ -194,9 +194,7 @@ func StartNewVTTablet(t *testing.T, clusterInstance *cluster.LocalProcessCluster // Setup MysqlctlProcess mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) - if err != nil { - require.NoError(t, err) - } + require.NoError(t, err) tablet.MysqlctlProcess = *mysqlctlProcess // Setup VttabletProcess tablet.VttabletProcess = cluster.VttabletProcessInstance( diff --git a/go/test/endtoend/tabletmanager/tablet_test.go b/go/test/endtoend/tabletmanager/tablet_test.go index bd07650d9b5..8333946bfc0 100644 --- a/go/test/endtoend/tabletmanager/tablet_test.go +++ b/go/test/endtoend/tabletmanager/tablet_test.go @@ -72,9 +72,7 @@ func TestResetReplicationParameters(t *testing.T) { // Create new tablet tablet := clusterInstance.NewVttabletInstance("replica", 0, "") mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) - if err != nil { - require.NoError(t, err) - } + require.NoError(t, err) tablet.MysqlctlProcess = *mysqlctlProcess err = tablet.MysqlctlProcess.Start() require.NoError(t, err) diff --git a/go/test/endtoend/topoconncache/topo_conn_cache_test.go b/go/test/endtoend/topoconncache/topo_conn_cache_test.go index 2ebdf3f32b2..504ca218047 100644 --- a/go/test/endtoend/topoconncache/topo_conn_cache_test.go +++ b/go/test/endtoend/topoconncache/topo_conn_cache_test.go @@ -137,9 +137,7 @@ func addCellback(t *testing.T) { var mysqlProcs []*exec.Cmd for _, tablet := range []*cluster.Vttablet{shard1Replica, shard1Rdonly, shard2Replica, shard2Rdonly} { mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) - if err != nil { - require.NoError(t, err) - } + require.NoError(t, err) tablet.MysqlctlProcess = *mysqlctlProcess tablet.VttabletProcess = cluster.VttabletProcessInstance(tablet.HTTPPort, tablet.GrpcPort, diff --git a/go/test/endtoend/vreplication/cluster_test.go b/go/test/endtoend/vreplication/cluster_test.go index 5c5dd4922c9..cd2c60a6336 100644 --- a/go/test/endtoend/vreplication/cluster_test.go +++ b/go/test/endtoend/vreplication/cluster_test.go @@ -451,9 +451,7 @@ func (vc *VitessCluster) AddTablet(t testing.TB, cell *Cell, keyspace *Keyspace, vttablet.SupportsBackup = false mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tabletID, vc.ClusterConfig.tabletMysqlPortBase+tabletID, vc.ClusterConfig.tmpDir) - if err != nil { - require.NoError(t, err) - } + require.NoError(t, err) tablet.DbServer = mysqlctlProcess require.NotNil(t, tablet.DbServer) tablet.DbServer.InitMysql = true diff --git a/go/test/endtoend/vtgate/tablet_healthcheck_cache/correctness_test.go b/go/test/endtoend/vtgate/tablet_healthcheck_cache/correctness_test.go index 386ef325996..928cb2d1c6a 100644 --- a/go/test/endtoend/vtgate/tablet_healthcheck_cache/correctness_test.go +++ b/go/test/endtoend/vtgate/tablet_healthcheck_cache/correctness_test.go @@ -183,7 +183,9 @@ func addTablet(t *testing.T, tabletUID int, tabletType string) *cluster.Vttablet Alias: fmt.Sprintf("%s-%010d", cell, tabletUID), } // Start Mysqlctl process - tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstanceOptionalInit(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory, !clusterInstance.ReusingVTDATAROOT) + mysqlctlProcess, err := cluster.MysqlCtlProcessInstanceOptionalInit(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory, !clusterInstance.ReusingVTDATAROOT) + require.Nil(t, err) + tablet.MysqlctlProcess = *mysqlctlProcess proc, err := tablet.MysqlctlProcess.StartProcess() require.Nil(t, err) From b1683bd3156a27d6bbb5338cba4d33698eb0827d Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Wed, 8 Mar 2023 09:14:14 -0800 Subject: [PATCH 63/65] code review - part 2 Signed-off-by: Rameez Sajwani --- config/mycnf/test-suite.cnf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/mycnf/test-suite.cnf b/config/mycnf/test-suite.cnf index 318bc4c824f..e6d0992f6e6 100644 --- a/config/mycnf/test-suite.cnf +++ b/config/mycnf/test-suite.cnf @@ -24,6 +24,5 @@ sql_mode = STRICT_TRANS_TABLES # set a short heartbeat interval in order to detect failures quickly slave_net_timeout = 4 # Disabling `super-read-only`. `test-suite` is mainly used for `vttestserver`. Since `vttestserver` uses a single MySQL for primary and replicas, -# so it is not possible to run it with `super-read-only`. -# we are disabling it. +# so it is not possible to run it with `super-read-only`. Therefore, we are disabling it. super-read-only = false From 19803668a00fe222432b9ee0a96669f0570418f4 Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Fri, 10 Mar 2023 17:27:59 -0800 Subject: [PATCH 64/65] code review phase 3 Signed-off-by: Rameez Sajwani --- config/init_db.sql | 7 ++-- config/mycnf/mariadb10.cnf | 2 + doc/releasenotes/17_0_0_summary.md | 4 +- go/cmd/vtbackup/vtbackup.go | 6 +-- go/mysql/collations/local.go | 5 +-- go/mysql/fakesqldb/server.go | 3 +- .../backup/vtbackup/backup_only_test.go | 5 ++- go/test/endtoend/cluster/mysqlctl_process.go | 6 ++- go/test/endtoend/cluster/mysqlctld_process.go | 2 +- .../recovery/pitr/shardedpitr_test.go | 14 ++----- go/test/endtoend/tabletmanager/tablet_test.go | 5 +-- go/test/endtoend/utils/mysql_test.go | 40 ++++++++++++------- go/test/endtoend/utils/utils.go | 6 +-- go/test/endtoend/vault/vault_test.go | 10 ++--- .../testdata/config/init_testserver_db.sql | 4 +- .../vreplication/vreplication_test.go | 1 + .../vtorc/readtopologyinstance/main_test.go | 2 +- go/test/endtoend/vtorc/utils/utils.go | 3 +- go/vt/dbconfigs/dbconfigs.go | 4 +- go/vt/mysqlctl/builtinbackupengine.go | 18 ++++++--- go/vt/mysqlctl/fakemysqldaemon.go | 6 +-- go/vt/mysqlctl/mysqld.go | 4 +- go/vt/mysqlctl/replication.go | 33 ++++++++------- .../vttablet/tabletmanager/rpc_replication.go | 6 +-- 24 files changed, 105 insertions(+), 91 deletions(-) diff --git a/config/init_db.sql b/config/init_db.sql index 031b889c89b..d04960633de 100644 --- a/config/init_db.sql +++ b/config/init_db.sql @@ -1,5 +1,4 @@ -# This file is executed immediately after mysql_install_db, -# to initialize a fresh data directory. +# This file is executed immediately after initializing a fresh data directory. ############################################################################### # WARNING: This sql is *NOT* safe for production use, @@ -85,7 +84,7 @@ RESET SLAVE ALL; RESET MASTER; # custom sql is used to add custom scripts like creating users/passwords. We use it in our tests -# add custom sql here +# {{custom_sql}} # We need to set super_read_only back to what it was before -SET GLOBAL super_read_only=IFNULL(@original_super_read_only, 'OFF'); +SET GLOBAL super_read_only=IFNULL(@original_super_read_only, 'ON'); diff --git a/config/mycnf/mariadb10.cnf b/config/mycnf/mariadb10.cnf index 1912cd8e154..120bd7b7d00 100644 --- a/config/mycnf/mariadb10.cnf +++ b/config/mycnf/mariadb10.cnf @@ -39,3 +39,5 @@ slave_net_timeout = 60 character_set_server = utf8 collation_server = utf8_general_ci +# All MariaDB instances should start in read-only mode +read-only diff --git a/doc/releasenotes/17_0_0_summary.md b/doc/releasenotes/17_0_0_summary.md index 0240d725a9f..7b84459a42d 100644 --- a/doc/releasenotes/17_0_0_summary.md +++ b/doc/releasenotes/17_0_0_summary.md @@ -205,8 +205,8 @@ These stats are deprecated in v17. #### Initializing all replicas with super_read_only In order to prevent SUPER privileged users like `root` or `vt_dba` from producing errant GTIDs on replicas, all the replica MySQL servers are initialized with the MySQL global variable `super_read_only` value set to `ON`. During failovers, we set `super_read_only` to `OFF` for the promoted primary tablet. This will allow the -primary to accept writes. All replicas except the primary will still have their global variable `super_read_only` set to `ON`. This will make sure that apart from -MySQL replication no other component or offline system can write directly to a replica. +primary to accept writes. All of the shard's tablets, except the current primary, will still have their global variable `super_read_only` set to `ON`. This will make sure that apart from +MySQL replication no other component, offline system or operator can write directly to a replica. Reference PR for this change is [PR #12206](https://github.com/vitessio/vitess/pull/12206) diff --git a/go/cmd/vtbackup/vtbackup.go b/go/cmd/vtbackup/vtbackup.go index c65db228685..8f5a39e8d0c 100644 --- a/go/cmd/vtbackup/vtbackup.go +++ b/go/cmd/vtbackup/vtbackup.go @@ -312,16 +312,16 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back if err := mysqld.ResetReplication(ctx); err != nil { return fmt.Errorf("can't reset replication: %v", err) } - // We need to switch off super_read_only before we create database. + // We need to switch off super_read_only before we create the database. resetFunc, err := mysqld.SetSuperReadOnly(false) if err != nil { - return fmt.Errorf("can't turn-off super_read_only during backup: %v", err) + return fmt.Errorf("failed to disable super_read_only during backup: %v", err) } if resetFunc != nil { defer func() { err := resetFunc() if err != nil { - log.Info("not able to set super_read_only to its original value during backup") + log.Error("Failed to set super_read_only back to its original value during backup") } }() } diff --git a/go/mysql/collations/local.go b/go/mysql/collations/local.go index c0d3c10da09..19aab141465 100644 --- a/go/mysql/collations/local.go +++ b/go/mysql/collations/local.go @@ -21,7 +21,6 @@ package collations import ( "sync" - "vitess.io/vitess/go/internal/flag" "vitess.io/vitess/go/vt/servenv" ) @@ -32,9 +31,9 @@ var defaultEnvInit sync.Once // on the value of the `mysql_server_version` flag passed to this Vitess process. func Local() *Environment { defaultEnvInit.Do(func() { - if !flag.Parsed() { + /*if !flag.Parsed() { panic("collations.Local() called too early") - } + }*/ defaultEnv = NewEnvironment(servenv.MySQLServerVersion()) }) return defaultEnv diff --git a/go/mysql/fakesqldb/server.go b/go/mysql/fakesqldb/server.go index 5cc643479f0..e40d092e244 100644 --- a/go/mysql/fakesqldb/server.go +++ b/go/mysql/fakesqldb/server.go @@ -795,7 +795,6 @@ func (db *DB) GetRejectedQueryResult(key string) error { // GetQueryResult checks for explicit queries add through AddQuery(). func (db *DB) GetQueryResult(key string) *ExpectedResult { - result, ok := db.data[key] if ok { return result @@ -803,7 +802,7 @@ func (db *DB) GetQueryResult(key string) *ExpectedResult { return nil } -// GetQueryPatternResult checks if query matches ay pattern from AddQueryPattern(). +// GetQueryPatternResult checks if a query matches any pattern previously added using AddQueryPattern(). func (db *DB) GetQueryPatternResult(key string) (func(string), ExpectedResult, bool, error) { for _, pat := range db.patternData { if pat.expr.MatchString(key) { diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go index 7cafdf966bd..408cc64a21b 100644 --- a/go/test/endtoend/backup/vtbackup/backup_only_test.go +++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go @@ -57,6 +57,8 @@ func TestTabletInitialBackup(t *testing.T) { // - list the backups, remove them defer cluster.PanicHandler(t) + waitForReplicationToCatchup([]cluster.Vttablet{*replica1, *replica2}) + vtBackup(t, true, false, false) verifyBackupCount(t, shardKsName, 1) @@ -304,7 +306,8 @@ func tearDown(t *testing.T, initMysql bool) { _, err := primary.VttabletProcess.QueryTablet(fmt.Sprintf("drop database if exists %s", db), keyspaceName, true) require.Nil(t, err) } - waitForReplicationToCatchup([]cluster.Vttablet{*replica1, *replica2}) + caughtUp := waitForReplicationToCatchup([]cluster.Vttablet{*replica1, *replica2}) + require.True(t, caughtUp, "Timed out waiting for all replicas to catch up") promoteCommands := "STOP SLAVE; RESET SLAVE ALL; RESET MASTER;" disableSemiSyncCommands := "SET GLOBAL rpl_semi_sync_master_enabled = false; SET GLOBAL rpl_semi_sync_slave_enabled = false" for _, tablet := range []cluster.Vttablet{*primary, *replica1, *replica2} { diff --git a/go/test/endtoend/cluster/mysqlctl_process.go b/go/test/endtoend/cluster/mysqlctl_process.go index 800cc6118eb..7c8f2607841 100644 --- a/go/test/endtoend/cluster/mysqlctl_process.go +++ b/go/test/endtoend/cluster/mysqlctl_process.go @@ -237,7 +237,7 @@ func (mysqlctl *MysqlctlProcess) Connect(ctx context.Context, username string) ( // MysqlCtlProcessInstanceOptionalInit returns a Mysqlctl handle for mysqlctl process // configured with the given Config. func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirectory string, initMySQL bool) (*MysqlctlProcess, error) { - initFile, err := getInitDBFile() + initFile, err := getInitDBFileUsed() if err != nil { return nil, err } @@ -254,7 +254,7 @@ func MysqlCtlProcessInstanceOptionalInit(tabletUID int, mySQLPort int, tmpDirect return mysqlctl, nil } -func getInitDBFile() (string, error) { +func getInitDBFileUsed() (string, error) { versionStr, err := mysqlctl.GetVersionString() if err != nil { return "", err @@ -266,6 +266,8 @@ func getInitDBFile() (string, error) { if flavor == mysqlctl.FlavorMySQL || flavor == mysqlctl.FlavorPercona { return path.Join(os.Getenv("VTROOT"), "/config/init_db.sql"), nil } + // Non-MySQL instances for example MariaDB, will use init_testserver_db.sql which does not contain super_read_only global variable. + // Even though MariaDB support is deprecated (https://github.com/vitessio/vitess/issues/9518) but we still support migration scenario. return path.Join(os.Getenv("VTROOT"), "go/test/endtoend/vreplication/testdata/config/init_testserver_db.sql"), nil } diff --git a/go/test/endtoend/cluster/mysqlctld_process.go b/go/test/endtoend/cluster/mysqlctld_process.go index 685cff54c8e..673870e62bb 100644 --- a/go/test/endtoend/cluster/mysqlctld_process.go +++ b/go/test/endtoend/cluster/mysqlctld_process.go @@ -145,7 +145,7 @@ func (mysqlctld *MysqlctldProcess) CleanupFiles(tabletUID int) { // MysqlCtldProcessInstance returns a Mysqlctld handle for mysqlctld process // configured with the given Config. func MysqlCtldProcessInstance(tabletUID int, mySQLPort int, tmpDirectory string) (*MysqlctldProcess, error) { - initFile, err := getInitDBFile() + initFile, err := getInitDBFileUsed() if err != nil { return nil, err } diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go index 0f1e860c4b3..ab54693993a 100644 --- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go +++ b/go/test/endtoend/recovery/pitr/shardedpitr_test.go @@ -430,14 +430,10 @@ func initializeCluster(t *testing.T) { sql := string(initDb) // The original init_db.sql does not have any passwords. Here we update the init file with passwords sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(clusterInstance), "") - if err != nil { - require.NoError(t, err, "expected to load init_db file") - } + require.NoError(t, err, "expected to load init_db file") initDBFileWithPassword = path.Join(clusterInstance.TmpDirectory, "init_db_with_passwords.sql") - err = os.WriteFile(initDBFileWithPassword, []byte(sql), 0666) - if err != nil { - require.NoError(t, err, "expected to load init_db file") - } + err = os.WriteFile(initDBFileWithPassword, []byte(sql), 0660) + require.NoError(t, err, "expected to load init_db file") // Start MySql var mysqlCtlProcessList []*exec.Cmd @@ -523,9 +519,7 @@ func testTabletRecovery(t *testing.T, binlogServer *binLogServer, lookupTimeout, func launchRecoveryTablet(t *testing.T, tablet *cluster.Vttablet, binlogServer *binLogServer, lookupTimeout, restoreKeyspaceName, shardName string) { mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) - if err != nil { - require.NoError(t, err) - } + require.NoError(t, err) tablet.MysqlctlProcess = *mysqlctlProcess extraArgs := []string{"--db-credentials-file", dbCredentialFile} tablet.MysqlctlProcess.InitDBFile = initDBFileWithPassword diff --git a/go/test/endtoend/tabletmanager/tablet_test.go b/go/test/endtoend/tabletmanager/tablet_test.go index 8333946bfc0..643785dcd89 100644 --- a/go/test/endtoend/tabletmanager/tablet_test.go +++ b/go/test/endtoend/tabletmanager/tablet_test.go @@ -35,9 +35,8 @@ func TestEnsureDB(t *testing.T) { // Create new tablet tablet := clusterInstance.NewVttabletInstance("replica", 0, "") mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) - if err != nil { - return - } + require.NoError(t, err) + tablet.MysqlctlProcess = *mysqlctlProcess err = tablet.MysqlctlProcess.Start() require.NoError(t, err) diff --git a/go/test/endtoend/utils/mysql_test.go b/go/test/endtoend/utils/mysql_test.go index ad0317274b5..de9db23dab1 100644 --- a/go/test/endtoend/utils/mysql_test.go +++ b/go/test/endtoend/utils/mysql_test.go @@ -75,35 +75,47 @@ func TestCreateMySQL(t *testing.T) { } func TestSetSuperReadOnlyMySQL(t *testing.T) { + require.NotNil(t, mysqld) + isSuperReadOnly, _ := mysqld.IsSuperReadOnly() + assert.False(t, isSuperReadOnly, "super_read_only should be set to False") retFunc1, err := mysqld.SetSuperReadOnly(true) - assert.NotNil(t, retFunc1, "SetSuperReadOnly is suppose to return a defer function") - assert.Nil(t, err, "SetSuperReadOnly should not have failed") + assert.NotNil(t, retFunc1, "SetSuperReadOnly is supposed to return a defer function") + assert.NoError(t, err, "SetSuperReadOnly should not have failed") - // if value is already true then retFunc will be nil + isSuperReadOnly, _ = mysqld.IsSuperReadOnly() + assert.True(t, isSuperReadOnly, "super_read_only should be set to True") + // if value is already true then retFunc2 will be nil retFunc2, err := mysqld.SetSuperReadOnly(true) - assert.Nil(t, retFunc2, "SetSuperReadOnly is suppose to return a nil function") - assert.Nil(t, err, "SetSuperReadOnly should not have failed") + assert.Nil(t, retFunc2, "SetSuperReadOnly is supposed to return a nil function") + assert.NoError(t, err, "SetSuperReadOnly should not have failed") retFunc1() - isSuperReadOnly, _ := mysqld.IsSuperReadOnly() + isSuperReadOnly, _ = mysqld.IsSuperReadOnly() assert.False(t, isSuperReadOnly, "super_read_only should be set to False") isReadOnly, _ := mysqld.IsReadOnly() assert.True(t, isReadOnly, "read_only should be set to True") + isSuperReadOnly, _ = mysqld.IsSuperReadOnly() + assert.False(t, isSuperReadOnly, "super_read_only should be set to False") retFunc1, err = mysqld.SetSuperReadOnly(false) - assert.Nil(t, retFunc1, "SetSuperReadOnly is suppose to return a nil function") - assert.Nil(t, err, "SetSuperReadOnly should not have failed") + assert.Nil(t, retFunc1, "SetSuperReadOnly is supposed to return a nil function") + assert.NoError(t, err, "SetSuperReadOnly should not have failed") - _, _ = mysqld.SetSuperReadOnly(true) + _, err = mysqld.SetSuperReadOnly(true) + assert.NoError(t, err) + isSuperReadOnly, _ = mysqld.IsSuperReadOnly() + assert.True(t, isSuperReadOnly, "super_read_only should be set to True") retFunc1, err = mysqld.SetSuperReadOnly(false) - assert.NotNil(t, retFunc1, "SetSuperReadOnly is suppose to return a defer function") - assert.Nil(t, err, "SetSuperReadOnly should not have failed") + assert.NotNil(t, retFunc1, "SetSuperReadOnly is supposed to return a defer function") + assert.NoError(t, err, "SetSuperReadOnly should not have failed") - // if value is already false then retFunc will be nil + isSuperReadOnly, _ = mysqld.IsSuperReadOnly() + assert.False(t, isSuperReadOnly, "super_read_only should be set to False") + // if value is already false then retFunc2 will be nil retFunc2, err = mysqld.SetSuperReadOnly(false) - assert.Nil(t, retFunc2, "SetSuperReadOnly is suppose to return a nil function") - assert.Nil(t, err, "SetSuperReadOnly should not have failed") + assert.Nil(t, retFunc2, "SetSuperReadOnly is supposed to return a nil function") + assert.NoError(t, err, "SetSuperReadOnly should not have failed") retFunc1() isSuperReadOnly, _ = mysqld.IsSuperReadOnly() diff --git a/go/test/endtoend/utils/utils.go b/go/test/endtoend/utils/utils.go index aaf1bcd6644..82d696fa856 100644 --- a/go/test/endtoend/utils/utils.go +++ b/go/test/endtoend/utils/utils.go @@ -291,9 +291,9 @@ func convertToMap(input interface{}) map[string]interface{} { func GetInitDBSQL(initDBSQL string, updatedPasswords string, oldAlterTableMode string) (string, error) { // Since password update is DML we need to insert it before we disable // super_read_only therefore doing the split below. - splitString := strings.Split(initDBSQL, "# add custom sql here") - if len(splitString) < 2 { - return "", fmt.Errorf("missing `# add custom sql here` in init_db.sql file") + splitString := strings.Split(initDBSQL, "# {{custom_sql}}") + if len(splitString) != 2 { + return "", fmt.Errorf("missing `# {{custom_sql}}` in init_db.sql file") } var builder strings.Builder builder.WriteString(splitString[0]) diff --git a/go/test/endtoend/vault/vault_test.go b/go/test/endtoend/vault/vault_test.go index 0d6ec090b10..2c4bf3059d6 100644 --- a/go/test/endtoend/vault/vault_test.go +++ b/go/test/endtoend/vault/vault_test.go @@ -256,14 +256,10 @@ func initializeClusterLate(t *testing.T) { sql := string(initDb) // The original init_db.sql does not have any passwords. Here we update the init file with passwords sql, err = utils.GetInitDBSQL(sql, cluster.GetPasswordUpdateSQL(clusterInstance), "") - if err != nil { - require.NoError(t, err, "expected to load init_db file") - } + require.NoError(t, err, "expected to load init_db file") newInitDBFile := path.Join(clusterInstance.TmpDirectory, "init_db_with_passwords.sql") - err = os.WriteFile(newInitDBFile, []byte(sql), 0666) - if err != nil { - require.NoError(t, err, "expected to load init_db file") - } + err = os.WriteFile(newInitDBFile, []byte(sql), 0660) + require.NoError(t, err, "expected to load init_db file") // Start MySQL var mysqlCtlProcessList []*exec.Cmd diff --git a/go/test/endtoend/vreplication/testdata/config/init_testserver_db.sql b/go/test/endtoend/vreplication/testdata/config/init_testserver_db.sql index e79083e400e..03df754ea21 100644 --- a/go/test/endtoend/vreplication/testdata/config/init_testserver_db.sql +++ b/go/test/endtoend/vreplication/testdata/config/init_testserver_db.sql @@ -1,5 +1,5 @@ # This file is for testing purpose only. -# This file is executed immediately after mysql_install_db, to initialize a fresh data directory. +# This file is executed immediately after initializing a fresh data directory. # It is equivalent of init_db.sql. Given init_db.sql is for mysql which has super_read_only # related stuff therefore for testing purpose we avoid setting `super_read_only` during initialization. @@ -88,4 +88,4 @@ RESET SLAVE ALL; RESET MASTER; # custom sql is used to add custom scripts like creating users/passwords. We use it in our tests -# add custom sql here +# {{custom_sql}} diff --git a/go/test/endtoend/vreplication/vreplication_test.go b/go/test/endtoend/vreplication/vreplication_test.go index 3f8f7f91997..6e65a72544e 100644 --- a/go/test/endtoend/vreplication/vreplication_test.go +++ b/go/test/endtoend/vreplication/vreplication_test.go @@ -386,6 +386,7 @@ func TestMultiCellVreplicationWorkflow(t *testing.T) { insertInitialData(t) shardCustomer(t, true, []*Cell{cell1, cell2}, cell2.Name, true) + checkIfDenyListExists(t, vc, "product:0", "customer") // we tag along this test so as not to create the overhead of creating another cluster testVStreamCellFlag(t) } diff --git a/go/test/endtoend/vtorc/readtopologyinstance/main_test.go b/go/test/endtoend/vtorc/readtopologyinstance/main_test.go index f2b0c560962..fe8b53f5103 100644 --- a/go/test/endtoend/vtorc/readtopologyinstance/main_test.go +++ b/go/test/endtoend/vtorc/readtopologyinstance/main_test.go @@ -105,7 +105,7 @@ func TestReadTopologyInstanceBufferable(t *testing.T) { assert.Equal(t, primaryInstance.ReplicationIOThreadState, inst.ReplicationThreadStateNoThread) assert.Equal(t, primaryInstance.ReplicationSQLThreadState, inst.ReplicationThreadStateNoThread) - // Insert an errant GTID in the replica + // Insert an errant GTID in the replica. // The way to do this is to disable global recoveries, stop replication and inject an errant GTID. // After this we restart the replication and enable the recoveries again. err = logic.DisableRecovery() diff --git a/go/test/endtoend/vtorc/utils/utils.go b/go/test/endtoend/vtorc/utils/utils.go index 7fd7b26ec6f..fc118ef3ac5 100644 --- a/go/test/endtoend/vtorc/utils/utils.go +++ b/go/test/endtoend/vtorc/utils/utils.go @@ -589,7 +589,8 @@ func RunSQL(t *testing.T, sql string, tablet *cluster.Vttablet, db string) (*sql func RunSQLs(t *testing.T, sqls []string, tablet *cluster.Vttablet, db string) error { // Get Connection tabletParams := getMysqlConnParam(tablet, db) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + var timeoutDuration = time.Duration(5 * len(sqls)) + ctx, cancel := context.WithTimeout(context.Background(), timeoutDuration*time.Second) defer cancel() conn, err := mysql.Connect(ctx, &tabletParams) require.Nil(t, err) diff --git a/go/vt/dbconfigs/dbconfigs.go b/go/vt/dbconfigs/dbconfigs.go index 7d2d8c0ba0b..940652094c9 100644 --- a/go/vt/dbconfigs/dbconfigs.go +++ b/go/vt/dbconfigs/dbconfigs.go @@ -216,12 +216,12 @@ func (dbcfgs *DBConfigs) AppDebugWithDB() Connector { return dbcfgs.makeParams(&dbcfgs.appdebugParams, true) } -// AllPrivsConnector returns connection parameters for allPrivs with no dbname set. +// AllPrivsConnector returns connection parameters for allprivs with no dbname set. func (dbcfgs *DBConfigs) AllPrivsConnector() Connector { return dbcfgs.makeParams(&dbcfgs.allprivsParams, false) } -// AllPrivsWithDB returns connection parameters for allPrivs with dbname set. +// AllPrivsWithDB returns connection parameters for allprivs with dbname set. func (dbcfgs *DBConfigs) AllPrivsWithDB() Connector { return dbcfgs.makeParams(&dbcfgs.allprivsParams, true) } diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index c880a5252c6..7c16aec37b7 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -339,22 +339,30 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac // get the read-only flag readOnly, err = params.Mysqld.IsReadOnly() if err != nil { - return false, vterrors.Wrap(err, "can't get read_only status") + return false, vterrors.Wrap(err, "failed to get read_only status") } superReadOnly, err = params.Mysqld.IsSuperReadOnly() if err != nil { return false, vterrors.Wrap(err, "can't get super_read_only status") } - log.Infof("Flag values during full backup, read_only: %v, super_read_only:%v", readOnly, superReadOnly) + log.Infof("Flag values during full backup, read_only: %v, super_read_only:%t", readOnly, superReadOnly) // get the replication position if sourceIsPrimary { // No need to set read_only because super_read_only will implicitly set read_only to true as well. if !superReadOnly { - params.Logger.Infof("turning primary super_read_only before backup") + params.Logger.Infof("Enabling super_read_only on primary prior to backup") if _, err = params.Mysqld.SetSuperReadOnly(true); err != nil { - return false, vterrors.Wrap(err, "can't set super_read_only status") + return false, vterrors.Wrap(err, "failed to enable super_read_only") } + defer func() { + // Resetting super_read_only back to its original value + params.Logger.Infof("resetting mysqld super_read_only to %v", superReadOnly) + if _, err := params.Mysqld.SetSuperReadOnly(false); err != nil { + log.Error("Failed to set super_read_only back to its original value") + } + }() + } replicationPosition, err = params.Mysqld.PrimaryPosition() if err != nil { @@ -406,7 +414,7 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac } // Resetting super_read_only back to its original value - params.Logger.Infof("resetting mysqld super_read-only to %v", superReadOnly) + params.Logger.Infof("resetting mysqld super_read_only to %v", superReadOnly) if _, err := params.Mysqld.SetSuperReadOnly(superReadOnly); err != nil { return usable, err } diff --git a/go/vt/mysqlctl/fakemysqldaemon.go b/go/vt/mysqlctl/fakemysqldaemon.go index 360062118fe..475d4251fbc 100644 --- a/go/vt/mysqlctl/fakemysqldaemon.go +++ b/go/vt/mysqlctl/fakemysqldaemon.go @@ -101,7 +101,7 @@ type FakeMysqlDaemon struct { ReadOnly bool // SuperReadOnly is the current value of the flag - SuperReadOnly bool + SuperReadOnly atomic.Bool // SetReplicationPositionPos is matched against the input of SetReplicationPosition. // If it doesn't match, SetReplicationPosition will return an error. @@ -366,7 +366,7 @@ func (fmd *FakeMysqlDaemon) IsReadOnly() (bool, error) { // IsSuperReadOnly is part of the MysqlDaemon interface func (fmd *FakeMysqlDaemon) IsSuperReadOnly() (bool, error) { - return fmd.SuperReadOnly, nil + return fmd.SuperReadOnly.Load(), nil } // SetReadOnly is part of the MysqlDaemon interface @@ -377,7 +377,7 @@ func (fmd *FakeMysqlDaemon) SetReadOnly(on bool) error { // SetSuperReadOnly is part of the MysqlDaemon interface func (fmd *FakeMysqlDaemon) SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) { - fmd.SuperReadOnly = on + fmd.SuperReadOnly.Store(on) fmd.ReadOnly = on return nil, nil } diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index f7c345291b4..19ab541a322 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -667,7 +667,7 @@ func (mysqld *Mysqld) InitConfig(cnf *Mycnf) error { // generate / configure a my.cnf file install a skeleton database, // and apply the provided initial SQL file. func (mysqld *Mysqld) Init(ctx context.Context, cnf *Mycnf, initDBSQLFile string) error { - log.Infof("mysqlctl.Init with %s", initDBSQLFile) + log.Infof("mysqlctl.Init running with contents previously embedded from %s", initDBSQLFile) err := mysqld.InitConfig(cnf) if err != nil { log.Errorf("%s", err.Error()) @@ -1258,7 +1258,7 @@ func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTID log.Infof("applyBinlogFile: disabling super_read_only") resetFunc, err := mysqld.SetSuperReadOnly(false) if err != nil { - if strings.Contains(err.Error(), mysql.ERUnknownSystemVariable.ToString()) { + if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERUnknownSystemVariable { log.Warningf("applyBinlogFile: server does not know about super_read_only, continuing anyway...") } else { log.Errorf("applyBinlogFile: unexpected error while trying to set super_read_only: %v", err) diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index 556a99da2fa..10258b16d2c 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -270,40 +270,39 @@ func (mysqld *Mysqld) SetReadOnly(on bool) error { return mysqld.ExecuteSuperQuery(context.TODO(), query) } -// SetSuperReadOnly set/unset the super_read_only flag +// SetSuperReadOnly set/unset the super_read_only flag. // Returns a function which is called to set super_read_only back to its original value. func (mysqld *Mysqld) SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) { // return function for switching `OFF` super_read_only - var returnFunc ResetSuperReadOnlyFunc - var resetFunc = func() error { + var resetFunc ResetSuperReadOnlyFunc + var disableFunc = func() error { query := "SET GLOBAL super_read_only = 'OFF'" - err := mysqld.ExecuteSuperQuery(context.TODO(), query) + err := mysqld.ExecuteSuperQuery(context.Background(), query) return err } - // return function for switching `ON` super_read_only - var setFunc = func() error { + // return function for switching `ON` super_read_only. + var enableFunc = func() error { query := "SET GLOBAL super_read_only = 'ON'" - err := mysqld.ExecuteSuperQuery(context.TODO(), query) + err := mysqld.ExecuteSuperQuery(context.Background(), query) return err } - //var err error = nil superReadOnlyEnabled, err := mysqld.IsSuperReadOnly() if err != nil { return nil, err } - // If non-idempotent then set the right call-back - // We are asked to turn on super_read_only but original value is false - // then return resetFunc, that can be used as defer by caller + // If non-idempotent then set the right call-back. + // We are asked to turn on super_read_only but original value is false, + // therefore return disableFunc, that can be used as defer by caller. if on && !superReadOnlyEnabled { - returnFunc = resetFunc + resetFunc = disableFunc } - // We are asked to turn off super_read_only but original value is true - // then return setFunc, that can be used as defer by caller + // We are asked to turn off super_read_only but original value is true, + // therefore return enableFunc, that can be used as defer by caller. if !on && superReadOnlyEnabled { - returnFunc = setFunc + resetFunc = enableFunc } query := "SET GLOBAL super_read_only = " @@ -312,11 +311,11 @@ func (mysqld *Mysqld) SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) } else { query += "'OFF'" } - if err := mysqld.ExecuteSuperQuery(context.TODO(), query); err != nil { + if err := mysqld.ExecuteSuperQuery(context.Background(), query); err != nil { return nil, err } - return returnFunc, nil + return resetFunc, nil } // WaitSourcePos lets replicas wait to given replication position diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index 125727a14e2..445e8d94c8b 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -41,7 +41,7 @@ var disableReplicationManager bool func registerReplicationFlags(fs *pflag.FlagSet) { fs.Bool("use_super_read_only", true, "Set super_read_only flag when performing planned failover.") - fs.MarkDeprecated("use_super_read_only", "From v17 onwards MySQL server will always start with super_read_only=ON") + fs.MarkDeprecated("use_super_read_only", "From v17 onwards MySQL server will always try to start with super_read_only=ON") fs.BoolVar(&disableReplicationManager, "disable-replication-manager", disableReplicationManager, "Disable replication manager to prevent replication repairs.") fs.MarkDeprecated("disable-replication-manager", "Replication manager is deleted") } @@ -306,7 +306,7 @@ func (tm *TabletManager) InitPrimary(ctx context.Context, semiSync bool) (string // Setting super_read_only `OFF` so that we can run the DDL commands if _, err := tm.MysqlDaemon.SetSuperReadOnly(false); err != nil { - if strings.Contains(err.Error(), mysql.ERUnknownSystemVariable.ToString()) { + if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERUnknownSystemVariable { log.Warningf("server does not know about super_read_only, continuing anyway...") } else { return "", err @@ -472,7 +472,7 @@ func (tm *TabletManager) demotePrimary(ctx context.Context, revertPartialFailure // previous demotion, or because we are not primary anyway, this should be // idempotent. if _, err := tm.MysqlDaemon.SetSuperReadOnly(true); err != nil { - if strings.Contains(err.Error(), mysql.ERUnknownSystemVariable.ToString()) { + if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERUnknownSystemVariable { log.Warningf("server does not know about super_read_only, continuing anyway...") } else { return nil, err From 53ea516e09284436bd7eca64b1c71bda1fc7478e Mon Sep 17 00:00:00 2001 From: Rameez Sajwani Date: Mon, 13 Mar 2023 16:56:38 -0700 Subject: [PATCH 65/65] revert uncommented code Signed-off-by: Rameez Sajwani --- go/mysql/collations/local.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/go/mysql/collations/local.go b/go/mysql/collations/local.go index 19aab141465..c0d3c10da09 100644 --- a/go/mysql/collations/local.go +++ b/go/mysql/collations/local.go @@ -21,6 +21,7 @@ package collations import ( "sync" + "vitess.io/vitess/go/internal/flag" "vitess.io/vitess/go/vt/servenv" ) @@ -31,9 +32,9 @@ var defaultEnvInit sync.Once // on the value of the `mysql_server_version` flag passed to this Vitess process. func Local() *Environment { defaultEnvInit.Do(func() { - /*if !flag.Parsed() { + if !flag.Parsed() { panic("collations.Local() called too early") - }*/ + } defaultEnv = NewEnvironment(servenv.MySQLServerVersion()) }) return defaultEnv