From 8a887295364a0b3b1cd8a7f2638b2fa0bd2a1d6f Mon Sep 17 00:00:00 2001 From: shunki-fujita Date: Fri, 7 Jun 2024 05:52:43 +0000 Subject: [PATCH 1/9] issue-686: fix documents --- docs/backup.md | 4 ++-- docs/clustering.md | 8 ++++---- docs/known_issues.md | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/backup.md b/docs/backup.md index fee7d9ed5..64c375bbe 100644 --- a/docs/backup.md +++ b/docs/backup.md @@ -127,7 +127,7 @@ MOCO then creates a tarball of the dump and puts it to an object storage bucket. To retrieve transactions since the last backup until now, `mysqlbinlog` is used with these flags: -- [`--read-from-remote-master=BINLOG-DUMP-GTIDS`](https://dev.mysql.com/doc/refman/8.0/en/mysqlbinlog.html#option_mysqlbinlog_read-from-remote-master) +- [`--read-from-remote-source=BINLOG-DUMP-GTIDS`](https://dev.mysql.com/doc/refman/8.0/en/mysqlbinlog.html#option_mysqlbinlog_read-from-remote-source) - [`--exclude-gtids=`](https://dev.mysql.com/doc/refman/8.0/en/mysqlbinlog.html#option_mysqlbinlog_exclude-gtids) - [`--to-last-log`](https://dev.mysql.com/doc/refman/8.0/en/mysqlbinlog.html#option_mysqlbinlog_to-last-log) @@ -139,7 +139,7 @@ Finally, the Job updates MySQLCluster status field with the following informatio - The time spent on the backup - The ordinal of the backup source instance - `server_uuid` of the instance (to check whether the instance was re-initialized or not) -- The binlog filename in `SHOW MASTER STATUS` output. +- The binlog filename in `SHOW MASTER STATUS | SHOW BINARY LOG STATUS` output. - The size of the tarball of the dumped files - The size of the tarball of the binlog files - The maximum usage of the working directory diff --git a/docs/clustering.md b/docs/clustering.md index 06a73b51f..1b186f803 100644 --- a/docs/clustering.md +++ b/docs/clustering.md @@ -47,9 +47,9 @@ Likewise, MOCO configures [`rpl_semi_sync_master_wait_for_slave_count`](https:// MOCO also disables [`relay_log_recovery`](https://dev.mysql.com/doc/refman/8.0/en/replication-options-replica.html#sysvar_relay_log_recovery) because enabling it would drop the relay logs on replicas. -`mysqld` always starts with `super_read_only=1` to prevent erroneous writes, and with `skip_slave_start` to prevent misconfigured replication. +`mysqld` always starts with `super_read_only=1` to prevent erroneous writes, and with `skip_replica_start` to prevent misconfigured replication. -[`moco-agent`][agent], a sidecar container for MOCO, initializes MySQL users and plugins. At the end of the initialization, it issues `RESET MASTER` to clear [executed GTID set](https://dev.mysql.com/doc/refman/8.0/en/replication-options-gtids.html#sysvar_gtid_executed). +[`moco-agent`][agent], a sidecar container for MOCO, initializes MySQL users and plugins. At the end of the initialization, it issues `RESET MASTER | RESET BINARY LOGS AND GTIDS` to clear [executed GTID set](https://dev.mysql.com/doc/refman/8.0/en/replication-options-gtids.html#sysvar_gtid_executed). `moco-agent` also provides a readiness probe for `mysqld` container. If a replica instance does not start replication threads or is too delayed to execute transactions, the container and the Pod will be determined as unready. @@ -156,8 +156,8 @@ MOCO gathers the information from `kube-apiserver` and `mysqld` as follows: - Pod resources - If some of the Pods are missing, MOCO does nothing. - `mysqld` - - `SHOW SLAVE HOSTS` (on the primary) - - `SHOW SLAVE STATUS` (on the replicas) + - `SHOW REPLICAS` (on the primary) + - `SHOW REPLICA STATUS` (on the replicas) - Global variables such as `gtid_executed` or `super_read_only` - Result of CLONE from `performance_schema.clone_status` table diff --git a/docs/known_issues.md b/docs/known_issues.md index 8d3d78738..f22276e8c 100644 --- a/docs/known_issues.md +++ b/docs/known_issues.md @@ -8,7 +8,7 @@ This document lists the known issues of MOCO. _Status: not fixed as of MOCO v0.9.5_ -If you use MOCO with MySQL version 8.0.25 or earlier, you should not configure the replicas with `slave_parallel_workers` > 1. +If you use MOCO with MySQL version 8.0.25 or earlier, you should not configure the replicas with `replica_parallel_workers` > 1. Multi-threaded replication will cause the replica to fail to resume after the crash. This issue is registered as [#322](https://github.com/cybozu-go/moco/issues/322) and will be addressed at no distant date. From 5ddb249e9bb3c562a25502e6d022f0c2605e226b Mon Sep 17 00:00:00 2001 From: shunki-fujita Date: Fri, 7 Jun 2024 07:36:17 +0000 Subject: [PATCH 2/9] issue-686 Replace 'master/slave' with 'source/replica' --- backup/restore.go | 2 +- clustering/manager_test.go | 10 ++-- clustering/mock_test.go | 24 +++++----- clustering/operations.go | 8 ++-- clustering/status.go | 4 +- clustering/status_test.go | 2 +- pkg/bkop/status.go | 21 +++++++-- pkg/bkop/types.go | 2 +- pkg/dbop/operator.go | 2 +- pkg/dbop/replication.go | 24 +++++++--- pkg/dbop/status.go | 10 ++-- pkg/dbop/test_util.go | 8 +++- pkg/dbop/types.go | 80 ++++++++++++++++---------------- pkg/mycnf/generator.go | 8 ++-- pkg/mycnf/testdata/bufsize.cnf | 4 +- pkg/mycnf/testdata/loose.cnf | 4 +- pkg/mycnf/testdata/nil.cnf | 4 +- pkg/mycnf/testdata/normalize.cnf | 4 +- pkg/mycnf/testdata/opaque.cnf | 4 +- 19 files changed, 126 insertions(+), 99 deletions(-) diff --git a/backup/restore.go b/backup/restore.go index f988b3b06..441ff299e 100644 --- a/backup/restore.go +++ b/backup/restore.go @@ -123,7 +123,7 @@ func (rm *RestoreManager) Restore(ctx context.Context) error { st := &bkop.ServerStatus{} if err := op.GetServerStatus(ctx, st); err != nil { rm.log.Error(err, "failed to get server status") - // SHOW MASTER STATUS fails due to the insufficient privileges, + // SHOW MASTER STATUS | SHOW BINARY LOG STATUS fails due to the insufficient privileges, // if this restore process connects a target database before moco-agent grants privileges to moco-admin. // In this case, the restore process panics and retries from the beginning. panic(ErrBadConnection) diff --git a/clustering/manager_test.go b/clustering/manager_test.go index af3c532a1..76dff44e6 100644 --- a/clustering/manager_test.go +++ b/clustering/manager_test.go @@ -442,7 +442,7 @@ var _ = Describe("manager", func() { Expect(st.GlobalVariables.SuperReadOnly).To(BeTrue()) Expect(st.GlobalVariables.SemiSyncSlaveEnabled).To(BeFalse()) Expect(st.ReplicaStatus).NotTo(BeNil()) - Expect(st.ReplicaStatus.SlaveIORunning).To(Equal("Yes")) + Expect(st.ReplicaStatus.ReplicaIORunning).To(Equal("Yes")) } Expect(of.getKillConnectionsCount(cluster.PodHostname(0))).To(Equal(0)) // connection should not be killed @@ -537,9 +537,9 @@ var _ = Describe("manager", func() { Expect(st.GlobalVariables.SemiSyncSlaveEnabled).To(BeFalse()) Expect(st.ReplicaStatus).NotTo(BeNil()) if i == newPrimary { - Expect(st.ReplicaStatus.MasterHost).To(Equal("external")) + Expect(st.ReplicaStatus.SourceHost).To(Equal("external")) } else { - Expect(st.ReplicaStatus.MasterHost).To(Equal(cluster.PodHostname(newPrimary))) + Expect(st.ReplicaStatus.SourceHost).To(Equal(cluster.PodHostname(newPrimary))) } } @@ -597,7 +597,7 @@ var _ = Describe("manager", func() { Expect(st.GlobalVariables.SuperReadOnly).To(BeTrue()) Expect(st.GlobalVariables.SemiSyncSlaveEnabled).To(BeTrue()) Expect(st.ReplicaStatus).NotTo(BeNil()) - Expect(st.ReplicaStatus.MasterHost).To(Equal(cluster.PodHostname(newPrimary))) + Expect(st.ReplicaStatus.SourceHost).To(Equal(cluster.PodHostname(newPrimary))) } } }) @@ -856,7 +856,7 @@ var _ = Describe("manager", func() { st1 := of.getInstanceStatus(cluster.PodHostname(1)) Expect(st1).NotTo(BeNil()) if st1.ReplicaHosts != nil { - Expect(st1.ReplicaStatus.SlaveIORunning).NotTo(Equal("Yes")) + Expect(st1.ReplicaStatus.ReplicaIORunning).NotTo(Equal("Yes")) } for i := 0; i < 5; i++ { diff --git a/clustering/mock_test.go b/clustering/mock_test.go index a02d83de5..604443d4c 100644 --- a/clustering/mock_test.go +++ b/clustering/mock_test.go @@ -265,10 +265,10 @@ func (o *mockOperator) ConfigureReplica(ctx context.Context, source dbop.AccessI if o.mysql.status.ReplicaStatus != nil { var oldi *mockMySQL - if o.mysql.status.ReplicaStatus.MasterHost == source.Host { + if o.mysql.status.ReplicaStatus.SourceHost == source.Host { oldi = si } else { - oldi = o.factory.getInstance(o.mysql.status.ReplicaStatus.MasterHost) + oldi = o.factory.getInstance(o.mysql.status.ReplicaStatus.SourceHost) if oldi == nil { panic(oldi) } @@ -292,10 +292,10 @@ func (o *mockOperator) ConfigureReplica(ctx context.Context, source dbop.AccessI gtid, _ := testGetGTID(source.Host) o.mysql.status.ReplicaStatus = &dbop.ReplicaStatus{ - MasterHost: source.Host, - RetrievedGtidSet: gtid, - SlaveIORunning: "Yes", - SlaveSQLRunning: "Yes", + SourceHost: source.Host, + RetrievedGtidSet: gtid, + ReplicaIORunning: "Yes", + ReplicaSQLRunning: "Yes", } o.mysql.status.GlobalVariables.SemiSyncSlaveEnabled = semisync return setPodReadiness(ctx, o.cluster.PodName(o.index), true) @@ -315,7 +315,7 @@ func (o *mockOperator) ConfigurePrimary(ctx context.Context, waitForCount int) e return nil } -// StopReplicaIOThread executes `STOP SLAVE IO_THREAD`. +// StopReplicaIOThread executes `STOP REPLICA IO_THREAD`. func (o *mockOperator) StopReplicaIOThread(ctx context.Context) error { if o.failing { return errors.New("mysqld is down") @@ -326,7 +326,7 @@ func (o *mockOperator) StopReplicaIOThread(ctx context.Context) error { if o.mysql.status.ReplicaStatus == nil { return nil } - o.mysql.status.ReplicaStatus.SlaveIORunning = "No" + o.mysql.status.ReplicaStatus.ReplicaIORunning = "No" return setPodReadiness(ctx, o.cluster.PodName(o.index), false) } @@ -352,12 +352,12 @@ func (o *mockOperator) WaitForGTID(_ context.Context, gtidSet string, _ int) err o.mysql.status.GlobalVariables.ExecutedGTID = gtidSet return nil } - if o.mysql.status.ReplicaStatus.SlaveIORunning == "Yes" { - primary := o.factory.getInstance(o.mysql.status.ReplicaStatus.MasterHost) + if o.mysql.status.ReplicaStatus.ReplicaIORunning == "Yes" { + primary := o.factory.getInstance(o.mysql.status.ReplicaStatus.SourceHost) if primary == nil { return errors.New("waitForGTID: primary not found") } - primaryGTID, _ := testGetGTID(o.mysql.status.ReplicaStatus.MasterHost) + primaryGTID, _ := testGetGTID(o.mysql.status.ReplicaStatus.SourceHost) if primaryGTID == gtidSet { testSetGTID(o.Name(), gtidSet) o.mysql.status.GlobalVariables.ExecutedGTID = gtidSet @@ -383,7 +383,7 @@ func (o *mockOperator) SetReadOnly(ctx context.Context, readonly bool) error { } if o.mysql.status.ReplicaStatus != nil { - primary := o.factory.getInstance(o.mysql.status.ReplicaStatus.MasterHost) + primary := o.factory.getInstance(o.mysql.status.ReplicaStatus.SourceHost) if primary == nil { return errors.New("setReadOnly: primary not found") } diff --git a/clustering/operations.go b/clustering/operations.go index dcfaa1f93..4c149ced0 100644 --- a/clustering/operations.go +++ b/clustering/operations.go @@ -427,7 +427,7 @@ func (p *managerProcess) configureIntermediatePrimary(ctx context.Context, ss *S User: string(secret.Data[constants.CloneSourceUserKey]), Password: string(secret.Data[constants.CloneSourcePasswordKey]), } - if pst.ReplicaStatus == nil || pst.ReplicaStatus.SlaveIORunning != "Yes" || pst.ReplicaStatus.MasterHost != ai.Host { + if pst.ReplicaStatus == nil || pst.ReplicaStatus.ReplicaIORunning != "Yes" || pst.ReplicaStatus.SourceHost != ai.Host { redo = true log.Info("start replication", "instance", ss.Primary, "semisync", false) if err := op.ConfigureReplica(ctx, ai, false); err != nil { @@ -443,7 +443,7 @@ func (p *managerProcess) configurePrimary(ctx context.Context, ss *StatusSet) (r op := ss.DBOps[ss.Primary] // wait for all retrieved transactions to be executed if this used to be an intermediate replica - if pst.ReplicaStatus != nil && pst.ReplicaStatus.SlaveIORunning == "Yes" { + if pst.ReplicaStatus != nil && pst.ReplicaStatus.ReplicaIORunning == "Yes" { redo = true log.Info("stop replica IO thread", "instance", ss.Primary) if err := op.StopReplicaIOThread(ctx); err != nil { @@ -484,7 +484,7 @@ func (p *managerProcess) configureReplica(ctx context.Context, ss *StatusSet, in if st.ReplicaStatus == nil { return } - if st.ReplicaStatus.SlaveIORunning != "Yes" { + if st.ReplicaStatus.ReplicaIORunning != "Yes" { return } log.Info("stop replica IO thread", "instance", index) @@ -567,7 +567,7 @@ func (p *managerProcess) configureReplica(ctx context.Context, ss *StatusSet, in Password: ss.Password.Replicator(), } semisync := ss.Cluster.Spec.ReplicationSourceSecretName == nil - if st.ReplicaStatus == nil || st.ReplicaStatus.SlaveIORunning != "Yes" || st.ReplicaStatus.MasterHost != ai.Host || st.GlobalVariables.SemiSyncSlaveEnabled != semisync { + if st.ReplicaStatus == nil || st.ReplicaStatus.ReplicaIORunning != "Yes" || st.ReplicaStatus.SourceHost != ai.Host || st.GlobalVariables.SemiSyncSlaveEnabled != semisync { redo = true log.Info("start replication", "instance", index, "semisync", semisync) if err := op.ConfigureReplica(ctx, ai, semisync); err != nil { diff --git a/clustering/status.go b/clustering/status.go index 5146a8144..037606241 100644 --- a/clustering/status.go +++ b/clustering/status.go @@ -377,7 +377,7 @@ func isHealthy(ss *StatusSet) bool { if ist.ReplicaStatus == nil { return false } - if ist.ReplicaStatus.MasterHost != primaryHostname { + if ist.ReplicaStatus.SourceHost != primaryHostname { return false } ss.Candidates = append(ss.Candidates, i) @@ -481,7 +481,7 @@ func isDegraded(ss *StatusSet) bool { if ist.ReplicaStatus == nil { continue } - if ist.ReplicaStatus.MasterHost != primaryHostname { + if ist.ReplicaStatus.SourceHost != primaryHostname { continue } if ist.IsErrant { diff --git a/clustering/status_test.go b/clustering/status_test.go index 13a8a6ed1..0601a7790 100644 --- a/clustering/status_test.go +++ b/clustering/status_test.go @@ -161,7 +161,7 @@ func (b *mysqlBuilder) build() *dbop.MySQLInstanceStatus { } if len(b.sourceHost) > 0 { st.ReplicaStatus = &dbop.ReplicaStatus{ - MasterHost: b.sourceHost, + SourceHost: b.sourceHost, } } st.ReplicaHosts = b.replicaHosts diff --git a/pkg/bkop/status.go b/pkg/bkop/status.go index a51aea13c..c30371347 100644 --- a/pkg/bkop/status.go +++ b/pkg/bkop/status.go @@ -6,15 +6,26 @@ import ( ) func (o operator) GetServerStatus(ctx context.Context, st *ServerStatus) error { - ms := &showMasterStatus{} - if err := o.db.GetContext(ctx, ms, `SHOW MASTER STATUS`); err != nil { - return fmt.Errorf("failed to show master status: %w", err) + bls := &showBinaryLogStatus{} + var version string + if err := o.db.GetContext(ctx, &version, `SELECT SUBSTRING_INDEX(VERSION(), '.', 2)`); err != nil { + return fmt.Errorf("failed to get version: %w", err) + } + if version == "8.4" { + if err := o.db.GetContext(ctx, bls, `SHOW BINARY LOG STATUS`); err != nil { + return fmt.Errorf("failed to show binary log status: %w", err) + } + } else if version == "8.0" { + if err := o.db.GetContext(ctx, bls, `SHOW MASTER STATUS`); err != nil { + return fmt.Errorf("failed to show master status: %w", err) + } + } else { + return fmt.Errorf("unsupported version: %s", version) } - if err := o.db.GetContext(ctx, st, `SELECT @@super_read_only, @@server_uuid`); err != nil { return fmt.Errorf("failed to get global variables: %w", err) } - st.CurrentBinlog = ms.File + st.CurrentBinlog = bls.File return nil } diff --git a/pkg/bkop/types.go b/pkg/bkop/types.go index 4aabb458d..64bf3a60a 100644 --- a/pkg/bkop/types.go +++ b/pkg/bkop/types.go @@ -9,7 +9,7 @@ type ServerStatus struct { CurrentBinlog string } -type showMasterStatus struct { +type showBinaryLogStatus struct { File string `db:"File"` Position int64 `db:"Position"` BinlogDoDB string `db:"Binlog_Do_DB"` diff --git a/pkg/dbop/operator.go b/pkg/dbop/operator.go index 3f2262b2f..855703373 100644 --- a/pkg/dbop/operator.go +++ b/pkg/dbop/operator.go @@ -46,7 +46,7 @@ type Operator interface { // For asynchronous replication, this method should not be called. ConfigurePrimary(ctx context.Context, waitForCount int) error - // StopReplicaIOThread executes `STOP SLAVE IO_THREAD`. + // StopReplicaIOThread executes `STOP REPLICA IO_THREAD`. StopReplicaIOThread(context.Context) error // WaitForGTID waits for `mysqld` to execute all GTIDs in `gtidSet`. diff --git a/pkg/dbop/replication.go b/pkg/dbop/replication.go index 92982f17a..999d67b53 100644 --- a/pkg/dbop/replication.go +++ b/pkg/dbop/replication.go @@ -8,10 +8,22 @@ import ( const semiSyncMasterTimeout = 24 * 60 * 60 * 1000 func (o *operator) ConfigureReplica(ctx context.Context, primary AccessInfo, semisync bool) error { - if _, err := o.db.ExecContext(ctx, `STOP SLAVE`); err != nil { + if _, err := o.db.ExecContext(ctx, `STOP REPLICA`); err != nil { return fmt.Errorf("failed to stop replica: %w", err) } - if _, err := o.db.NamedExecContext(ctx, `CHANGE MASTER TO MASTER_HOST = :Host, MASTER_PORT = :Port, MASTER_USER = :User, MASTER_PASSWORD = :Password, MASTER_AUTO_POSITION = 1, GET_MASTER_PUBLIC_KEY = 1`, primary); err != nil { + var version string + if err := o.db.GetContext(ctx, &version, `SELECT SUBSTRING_INDEX(VERSION(), '.', 2)`); err != nil { + return fmt.Errorf("failed to get version: %w", err) + } + var cmd string + if version == "8.4" { + cmd = `CHANGE REPLICATION SOURCE TO SOURCE_HOST = :Host, SOURCE_PORT = :Port, SOURCE_USER = :User, SOURCE_PASSWORD = :Password, SOURCE_AUTO_POSITION = 1, GET_SOURCE_PUBLIC_KEY = 1` + } else if version == "8.0" { + cmd = `CHANGE MASTER TO MASTER_HOST = :Host, MASTER_PORT = :Port, MASTER_USER = :User, MASTER_PASSWORD = :Password, MASTER_AUTO_POSITION = 1, GET_MASTER_PUBLIC_KEY = 1` + } else { + return fmt.Errorf("unsupported version: %s", version) + } + if _, err := o.db.NamedExecContext(ctx, cmd, primary); err != nil { return fmt.Errorf("failed to change primary: %w", err) } if _, err := o.db.ExecContext(ctx, "SET GLOBAL rpl_semi_sync_slave_enabled=?", semisync); err != nil { @@ -20,7 +32,7 @@ func (o *operator) ConfigureReplica(ctx context.Context, primary AccessInfo, sem if _, err := o.db.ExecContext(ctx, "SET GLOBAL rpl_semi_sync_master_enabled=OFF"); err != nil { return fmt.Errorf("failed to disable rpl_semi_sync_master_enabled: %w", err) } - if _, err := o.db.ExecContext(ctx, `START SLAVE`); err != nil { + if _, err := o.db.ExecContext(ctx, `START REPLICA`); err != nil { return fmt.Errorf("failed to start replica: %w", err) } return nil @@ -40,7 +52,7 @@ func (o *operator) ConfigurePrimary(ctx context.Context, waitForCount int) error } func (o *operator) StopReplicaIOThread(ctx context.Context) error { - if _, err := o.db.ExecContext(ctx, `STOP SLAVE IO_THREAD`); err != nil { + if _, err := o.db.ExecContext(ctx, `STOP REPLICA IO_THREAD`); err != nil { return fmt.Errorf("failed to stop replica IO thread: %w", err) } return nil @@ -67,10 +79,10 @@ func (o *operator) SetReadOnly(ctx context.Context, readOnly bool) error { return nil } - if _, err := o.db.ExecContext(ctx, "STOP SLAVE"); err != nil { + if _, err := o.db.ExecContext(ctx, "STOP REPLICA"); err != nil { return fmt.Errorf("failed to stop replica: %w", err) } - if _, err := o.db.ExecContext(ctx, "RESET SLAVE"); err != nil { + if _, err := o.db.ExecContext(ctx, "RESET REPLICA"); err != nil { return fmt.Errorf("failed to stop replica: %w", err) } if _, err := o.db.ExecContext(ctx, "SET GLOBAL read_only=0"); err != nil { diff --git a/pkg/dbop/status.go b/pkg/dbop/status.go index dd32dd15a..496c9eb1b 100644 --- a/pkg/dbop/status.go +++ b/pkg/dbop/status.go @@ -20,8 +20,8 @@ func (o *operator) GetStatus(ctx context.Context) (*MySQLInstanceStatus, error) } status.GlobalVariables = *globalVariablesStatus - if err := o.db.Select(&status.ReplicaHosts, `SHOW SLAVE HOSTS`); err != nil { - return nil, fmt.Errorf("failed to get slave hosts: pod=%s, namespace=%s: %w", o.name, o.namespace, err) + if err := o.db.Select(&status.ReplicaHosts, `SHOW REPLICAS`); err != nil { + return nil, fmt.Errorf("failed to get replica hosts: pod=%s, namespace=%s: %w", o.name, o.namespace, err) } replicaStatus, err := o.getReplicaStatus(ctx) @@ -50,13 +50,13 @@ func (o *operator) getGlobalVariablesStatus(ctx context.Context) (*GlobalVariabl func (o *operator) getReplicaStatus(ctx context.Context) (*ReplicaStatus, error) { status := &ReplicaStatus{} - err := o.db.GetContext(ctx, status, `SHOW SLAVE STATUS`) + err := o.db.GetContext(ctx, status, `SHOW REPLICA STATUS`) if err != nil { if errors.Is(err, sql.ErrNoRows) { - // slave status can be empty for non-replica servers + // replica status can be empty for non-replica servers return nil, nil } - return nil, fmt.Errorf("failed to get slave status: %w", err) + return nil, fmt.Errorf("failed to get replica status: %w", err) } return status, nil } diff --git a/pkg/dbop/test_util.go b/pkg/dbop/test_util.go index bf1d47b88..7f714328d 100644 --- a/pkg/dbop/test_util.go +++ b/pkg/dbop/test_util.go @@ -31,7 +31,7 @@ var startupMycnf = map[string]string{ "collation_server": "utf8mb4_unicode_ci", "default_time_zone": "+0:00", "disabled_storage_engines": "MyISAM", - "skip_slave_start": "ON", + "skip_replica_start": "ON", "enforce_gtid_consistency": "ON", "gtid_mode": "ON", } @@ -98,7 +98,11 @@ func ConfigureMySQLOnDocker(pwd *password.MySQLPassword, port int) error { } // clear executed_gtid_set - db.MustExec(`RESET MASTER`) + if strings.HasPrefix(testMySQLImage, "mysql:8.4") { + db.MustExec(`RESET BINARY LOGS AND GTIDS`) + } else { + db.MustExec(`RESET MASTER`) + } db.Close() return nil } diff --git a/pkg/dbop/types.go b/pkg/dbop/types.go index 87c33f9c8..d1b5faa94 100644 --- a/pkg/dbop/types.go +++ b/pkg/dbop/types.go @@ -41,13 +41,13 @@ type GlobalVariables struct { SemiSyncSlaveEnabled bool `db:"@@rpl_semi_sync_slave_enabled"` } -// ReplicaHost defines the columns from `SHOW SLAVE HOSTS` +// ReplicaHost defines the columns from `SHOW REPLICAS` type ReplicaHost struct { - ServerID int32 `db:"Server_id"` + ServerID int32 `db:"Server_Id"` Host string `db:"Host"` Port int `db:"Port"` - SourceID int32 `db:"Master_id"` - ReplicaUUID string `db:"Slave_UUID"` + SourceID int32 `db:"Source_Id"` + ReplicaUUID string `db:"Replica_UUID"` // the following fields don't appear normally User string `db:"User"` @@ -56,26 +56,26 @@ type ReplicaHost struct { // ReplicaStatus defines the observed state of a replica type ReplicaStatus struct { - LastIoErrno int `db:"Last_IO_Errno"` - LastIoError string `db:"Last_IO_Error"` - LastSQLErrno int `db:"Last_SQL_Errno"` - LastSQLError string `db:"Last_SQL_Error"` - MasterHost string `db:"Master_Host"` - RetrievedGtidSet string `db:"Retrieved_Gtid_Set"` - ExecutedGtidSet string `db:"Executed_Gtid_Set"` - SlaveIORunning string `db:"Slave_IO_Running"` - SlaveSQLRunning string `db:"Slave_SQL_Running"` + LastIoErrno int `db:"Last_IO_Errno"` + LastIoError string `db:"Last_IO_Error"` + LastSQLErrno int `db:"Last_SQL_Errno"` + LastSQLError string `db:"Last_SQL_Error"` + SourceHost string `db:"Source_Host"` + RetrievedGtidSet string `db:"Retrieved_Gtid_Set"` + ExecutedGtidSet string `db:"Executed_Gtid_Set"` + ReplicaIORunning string `db:"Replica_IO_Running"` + ReplicaSQLRunning string `db:"Replica_SQL_Running"` // All of variables from here are NOT used in MOCO's reconcile - SlaveIOState string `db:"Slave_IO_State"` - MasterUser string `db:"Master_User"` - MasterPort int `db:"Master_Port"` + ReplicaIOState string `db:"Replica_IO_State"` + SourceUser string `db:"Source_User"` + SourcePort int `db:"Source_Port"` ConnectRetry int `db:"Connect_Retry"` - MasterLogFile string `db:"Master_Log_File"` - ReadMasterLogPos int `db:"Read_Master_Log_Pos"` + SourceLogFile string `db:"Source_Log_File"` + ReadSourceLogPos int `db:"Read_Source_Log_Pos"` RelayLogFile string `db:"Relay_Log_File"` RelayLogPos int `db:"Relay_Log_Pos"` - RelayMasterLogFile string `db:"Relay_Master_Log_File"` + RelaySourceLogFile string `db:"Relay_Source_Log_File"` ReplicateDoDB string `db:"Replicate_Do_DB"` ReplicateIgnoreDB string `db:"Replicate_Ignore_DB"` ReplicateDoTable string `db:"Replicate_Do_Table"` @@ -85,38 +85,38 @@ type ReplicaStatus struct { LastErrno int `db:"Last_Errno"` LastError string `db:"Last_Error"` SkipCounter int `db:"Skip_Counter"` - ExecMasterLogPos int `db:"Exec_Master_Log_Pos"` + ExecSourceLogPos int `db:"Exec_Source_Log_Pos"` RelayLogSpace int `db:"Relay_Log_Space"` UntilCondition string `db:"Until_Condition"` UntilLogFile string `db:"Until_Log_File"` UntilLogPos int `db:"Until_Log_Pos"` - MasterSSLAllowed string `db:"Master_SSL_Allowed"` - MasterSSLCAFile string `db:"Master_SSL_CA_File"` - MasterSSLCAPath string `db:"Master_SSL_CA_Path"` - MasterSSLCert string `db:"Master_SSL_Cert"` - MasterSSLCipher string `db:"Master_SSL_Cipher"` - MasterSSLKey string `db:"Master_SSL_Key"` - SecondsBehindMaster sql.NullInt64 `db:"Seconds_Behind_Master"` - MasterSSLVerifyServerCert string `db:"Master_SSL_Verify_Server_Cert"` + SourceSSLAllowed string `db:"Source_SSL_Allowed"` + SourceSSLCAFile string `db:"Source_SSL_CA_File"` + SourceSSLCAPath string `db:"Source_SSL_CA_Path"` + SourceSSLCert string `db:"Source_SSL_Cert"` + SourceSSLCipher string `db:"Source_SSL_Cipher"` + SourceSSLKey string `db:"Source_SSL_Key"` + SecondsBehindSource sql.NullInt64 `db:"Seconds_Behind_Source"` + SourceSSLVerifyServerCert string `db:"Source_SSL_Verify_Server_Cert"` ReplicateIgnoreServerIds string `db:"Replicate_Ignore_Server_Ids"` - MasterServerID int `db:"Master_Server_Id"` - MasterUUID string `db:"Master_UUID"` - MasterInfoFile string `db:"Master_Info_File"` + SourceServerID int `db:"Source_Server_Id"` + SourceUUID string `db:"Source_UUID"` + SourceInfoFile string `db:"Source_Info_File"` SQLDelay int `db:"SQL_Delay"` SQLRemainingDelay sql.NullInt64 `db:"SQL_Remaining_Delay"` - SlaveSQLRunningState string `db:"Slave_SQL_Running_State"` - MasterRetryCount int `db:"Master_Retry_Count"` - MasterBind string `db:"Master_Bind"` + ReplicaSQLRunningState string `db:"Replica_SQL_Running_State"` + SourceRetryCount int `db:"Source_Retry_Count"` + SourceBind string `db:"Source_Bind"` LastIOErrorTimestamp string `db:"Last_IO_Error_Timestamp"` LastSQLErrorTimestamp string `db:"Last_SQL_Error_Timestamp"` - MasterSSLCrl string `db:"Master_SSL_Crl"` - MasterSSLCrlpath string `db:"Master_SSL_Crlpath"` + SourceSSLCrl string `db:"Source_SSL_Crl"` + SourceSSLCrlpath string `db:"Source_SSL_Crlpath"` AutoPosition string `db:"Auto_Position"` ReplicateRewriteDB string `db:"Replicate_Rewrite_DB"` ChannelName string `db:"Channel_Name"` - MasterTLSVersion string `db:"Master_TLS_Version"` - Masterpublickeypath string `db:"Master_public_key_path"` - Getmasterpublickey string `db:"Get_master_public_key"` + SourceTLSVersion string `db:"Source_TLS_Version"` + Sourcepublickeypath string `db:"Source_public_key_path"` + GetSourcepublickey string `db:"Get_Source_public_key"` NetworkNamespace string `db:"Network_Namespace"` } @@ -124,7 +124,7 @@ func (rs *ReplicaStatus) IsRunning() bool { if rs == nil { return false } - return rs.SlaveIORunning == "Yes" && rs.SlaveSQLRunning == "Yes" + return rs.ReplicaIORunning == "Yes" && rs.ReplicaSQLRunning == "Yes" } // CloneStatus defines the observed clone status of a MySQL instance diff --git a/pkg/mycnf/generator.go b/pkg/mycnf/generator.go index a9bee9de5..2dfe93de3 100644 --- a/pkg/mycnf/generator.go +++ b/pkg/mycnf/generator.go @@ -111,7 +111,7 @@ var ConstMycnf = map[string]map[string]string{ "enforce_gtid_consistency": "ON", // This must be set before gtid_mode. "gtid_mode": "ON", "binlog_format": "ROW", - "log_slave_updates": "ON", + "log_replica_updates": "ON", "relay_log_recovery": "OFF", // Turning this on would risk the loss of transaction in case of chained failures "mysqlx_port": strconv.Itoa(constants.MySQLXPort), @@ -119,9 +119,9 @@ var ConstMycnf = map[string]map[string]string{ "pid_file": filepath.Join(constants.RunPath, "mysqld.pid"), - "read_only": "ON", - "super_read_only": "ON", - "skip_slave_start": "ON", + "read_only": "ON", + "super_read_only": "ON", + "skip_replica_start": "ON", // Optimizing locks for semisync replication. Available from 8.0.23. "loose_replication_optimize_for_static_plugin_config": "ON", diff --git a/pkg/mycnf/testdata/bufsize.cnf b/pkg/mycnf/testdata/bufsize.cnf index 844dbf5dd..cbb2c508e 100644 --- a/pkg/mycnf/testdata/bufsize.cnf +++ b/pkg/mycnf/testdata/bufsize.cnf @@ -41,7 +41,7 @@ innodb_undo_log_truncate = OFF join_buffer_size = 2M lock_wait_timeout = 60 log_error_verbosity = 3 -log_slave_updates = ON +log_replica_updates = ON log_slow_extra = ON long_query_time = 2 loose_binlog_transaction_compression = ON @@ -61,7 +61,7 @@ read_only = ON relay_log_recovery = OFF secure_file_priv = NULL skip_name_resolve = ON -skip_slave_start = ON +skip_replica_start = ON slow_query_log = ON slow_query_log_file = /var/log/mysql/mysql.slow socket = /run/mysqld.sock diff --git a/pkg/mycnf/testdata/loose.cnf b/pkg/mycnf/testdata/loose.cnf index 0583a6e59..f656fe67e 100644 --- a/pkg/mycnf/testdata/loose.cnf +++ b/pkg/mycnf/testdata/loose.cnf @@ -42,7 +42,7 @@ innodb_undo_log_truncate = OFF join_buffer_size = 2M lock_wait_timeout = 60 log_error_verbosity = 3 -log_slave_updates = ON +log_replica_updates = ON log_slow_extra = ON long_query_time = 2 loose_binlog_transaction_compression = ON @@ -62,7 +62,7 @@ read_only = ON relay_log_recovery = OFF secure_file_priv = NULL skip_name_resolve = ON -skip_slave_start = ON +skip_replica_start = ON slow_query_log = ON slow_query_log_file = /var/log/mysql/mysql.slow socket = /run/mysqld.sock diff --git a/pkg/mycnf/testdata/nil.cnf b/pkg/mycnf/testdata/nil.cnf index 73f78f705..4f341b135 100644 --- a/pkg/mycnf/testdata/nil.cnf +++ b/pkg/mycnf/testdata/nil.cnf @@ -41,7 +41,7 @@ innodb_undo_log_truncate = OFF join_buffer_size = 2M lock_wait_timeout = 60 log_error_verbosity = 3 -log_slave_updates = ON +log_replica_updates = ON log_slow_extra = ON long_query_time = 2 loose_binlog_transaction_compression = ON @@ -61,7 +61,7 @@ read_only = ON relay_log_recovery = OFF secure_file_priv = NULL skip_name_resolve = ON -skip_slave_start = ON +skip_replica_start = ON slow_query_log = ON slow_query_log_file = /var/log/mysql/mysql.slow socket = /run/mysqld.sock diff --git a/pkg/mycnf/testdata/normalize.cnf b/pkg/mycnf/testdata/normalize.cnf index 52c9d1914..5b638b7f0 100644 --- a/pkg/mycnf/testdata/normalize.cnf +++ b/pkg/mycnf/testdata/normalize.cnf @@ -42,7 +42,7 @@ innodb_undo_log_truncate = OFF join_buffer_size = 2M lock_wait_timeout = 60 log_error_verbosity = 3 -log_slave_updates = ON +log_replica_updates = ON log_slow_extra = ON long_query_time = 2 loose_binlog_transaction_compression = ON @@ -62,7 +62,7 @@ read_only = ON relay_log_recovery = OFF secure_file_priv = NULL skip_name_resolve = ON -skip_slave_start = ON +skip_replica_start = ON slow_query_log = ON slow_query_log_file = /var/log/mysql/mysql.slow socket = /run/mysqld.sock diff --git a/pkg/mycnf/testdata/opaque.cnf b/pkg/mycnf/testdata/opaque.cnf index 8e31dbfdf..8e4354264 100644 --- a/pkg/mycnf/testdata/opaque.cnf +++ b/pkg/mycnf/testdata/opaque.cnf @@ -46,7 +46,7 @@ innodb_undo_log_truncate = OFF join_buffer_size = 2M lock_wait_timeout = 60 log_error_verbosity = 3 -log_slave_updates = ON +log_replica_updates = ON log_slow_extra = ON long_query_time = 2 loose_binlog_transaction_compression = ON @@ -66,7 +66,7 @@ read_only = ON relay_log_recovery = OFF secure_file_priv = NULL skip_name_resolve = ON -skip_slave_start = ON +skip_replica_start = ON slow_query_log = ON slow_query_log_file = /var/log/mysql/mysql.slow socket = /run/mysqld.sock From e1eb249f7edd565ba1137abe5b771fabaf1909cc Mon Sep 17 00:00:00 2001 From: shunki-fujita Date: Tue, 11 Jun 2024 07:22:22 +0000 Subject: [PATCH 3/9] issue-686: support MySQL 8.4.0 --- .github/workflows/ci-e2e.yaml | 6 +++--- .github/workflows/weekly.yaml | 6 +++--- DEVELOP.md | 14 +++++++------- Dockerfile | 6 +++--- Makefile | 2 +- README.md | 4 ++-- docs/change-pvc-template.md | 2 +- docs/custom-mysqld.md | 12 ++++++------ docs/designdoc/allow_customize_containers.md | 4 ++-- docs/designdoc/support_reduce_volume_size.md | 2 +- docs/usage.md | 6 +++--- e2e/Makefile | 2 +- e2e/upgrade_test.go | 4 ++-- examples/anti-affinity.yaml | 2 +- examples/collect-metrics.yaml | 2 +- examples/custom-mycnf.yaml | 2 +- examples/custom-probe.yaml | 2 +- examples/guaranteed.yaml | 2 +- examples/loadbalancer.yaml | 2 +- pkg/bkop/operator_test.go | 9 ++++++++- pkg/dbop/replication_test.go | 2 +- pkg/mycnf/generator.go | 3 +++ pkg/mycnf/testdata/bufsize.cnf | 1 + pkg/mycnf/testdata/loose.cnf | 1 + pkg/mycnf/testdata/nil.cnf | 1 + pkg/mycnf/testdata/normalize.cnf | 1 + pkg/mycnf/testdata/opaque.cnf | 1 + 27 files changed, 58 insertions(+), 43 deletions(-) diff --git a/.github/workflows/ci-e2e.yaml b/.github/workflows/ci-e2e.yaml index 546005c32..891979ad5 100644 --- a/.github/workflows/ci-e2e.yaml +++ b/.github/workflows/ci-e2e.yaml @@ -24,7 +24,7 @@ jobs: name: Integration tests with MySQL strategy: matrix: - mysql-version: ["8.0.35", "8.0.36", "8.0.37"] + mysql-version: ["8.0.28", "8.0.36", "8.0.37", "8.4.0"] runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -44,7 +44,7 @@ jobs: name: Supported Kubernetes versions End-to-End Tests strategy: matrix: - mysql-version: ["8.0.37"] + mysql-version: ["8.4.0"] k8s-version: ["1.27.13", "1.28.9", "1.29.4"] runs-on: group: moco @@ -67,7 +67,7 @@ jobs: name: Supported MySQL versions End-to-End Tests strategy: matrix: - mysql-version: ["8.0.35", "8.0.36", "8.0.37"] + mysql-version: ["8.0.28", "8.0.36", "8.0.37", "8.4.0"] k8s-version: ["1.29.4"] runs-on: group: moco diff --git a/.github/workflows/weekly.yaml b/.github/workflows/weekly.yaml index 7c7219d51..86797d969 100644 --- a/.github/workflows/weekly.yaml +++ b/.github/workflows/weekly.yaml @@ -17,7 +17,7 @@ jobs: name: Integration tests with MySQL strategy: matrix: - mysql-version: ["8.0.18", "8.0.25", "8.0.26", "8.0.27", "8.0.28", "8.0.30", "8.0.31", "8.0.32", "8.0.33", "8.0.34", "8.0.35", "8.0.36", "8.0.37"] + mysql-version: ["8.0.28", "8.0.36", "8.0.37", "8.4.0"] runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -29,7 +29,7 @@ jobs: name: Supported Kubernetes versions End-to-End Tests strategy: matrix: - mysql-version: ["8.0.37"] + mysql-version: ["8.4.0"] k8s-version: ["1.27.13", "1.28.9", "1.29.4"] runs-on: group: moco @@ -44,7 +44,7 @@ jobs: name: Supported MySQL versions End-to-End Tests strategy: matrix: - mysql-version: ["8.0.18", "8.0.25", "8.0.26", "8.0.27", "8.0.28", "8.0.30", "8.0.31", "8.0.32", "8.0.33", "8.0.34", "8.0.35", "8.0.36", "8.0.37"] + mysql-version: ["8.0.28", "8.0.36", "8.0.37", "8.4.0"] k8s-version: ["1.29.4"] runs-on: group: moco diff --git a/DEVELOP.md b/DEVELOP.md index a06959e61..d8fe9b6fe 100644 --- a/DEVELOP.md +++ b/DEVELOP.md @@ -58,10 +58,10 @@ Edit the following lines in `Dockerfile`: ``` # The tag should be the latest one -FROM ghcr.io/cybozu-go/moco/mysql:8.0.35.1 as mysql +FROM ghcr.io/cybozu-go/moco/mysql:8.4.0.1 as mysql # See the below description for how to get the version string. -ARG MYSQLSH_VERSION=8.0.35-1 +ARG MYSQLSH_VERSION=8.4.0-1 ``` The MySQL shell debian package can be found in https://dev.mysql.com/downloads/shell/ . @@ -88,23 +88,23 @@ MySQL versions appear twice: name: Integration tests with MySQL strategy: matrix: - mysql-version: ["8.0.18", "8.0.25", "8.0.26", "8.0.27", "8.0.28", "8.0.30", "8.0.31", "8.0.32", "8.0.33", "8.0.34", "8.0.35"] + mysql-version: ["8.0.28", "8.0.36", "8.0.37", "8.4.0"] ... # Matrix tests for the latest MySQL version on different Kubernetes versions. e2e: name: Supported Kubernetes versions End-to-End Tests strategy: matrix: - mysql-version: ["8.0.35"] - k8s-version: ["1.19.11", "1.20.7", "1.21.1"] + mysql-version: ["8.4.0"] + k8s-version: ["1.27.13", "1.28.9", "1.29.4"] ... # Matrix tests for different MySQL versions on the latest supported Kubernetes version. e2e-mysql: name: Supported MySQL versions End-to-End Tests strategy: matrix: - mysql-version: ["8.0.18", "8.0.25", "8.0.26", "8.0.27", "8.0.28", "8.0.30", "8.0.31", "8.0.32", "8.0.33", "8.0.34", "8.0.35"] - k8s-version: ["1.21.1"] + mysql-version: ["8.0.28", "8.0.36", "8.0.37", "8.4.0"] + k8s-version: ["1.29.4"] ``` ## Updating moco-agent diff --git a/Dockerfile b/Dockerfile index da07f3ea9..040c028c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,13 +20,13 @@ USER 10000:10000 ENTRYPOINT ["/moco-controller"] # For MySQL binaries -FROM --platform=$TARGETPLATFORM ghcr.io/cybozu-go/moco/mysql:8.0.37.1 as mysql +FROM --platform=$TARGETPLATFORM ghcr.io/cybozu-go/moco/mysql:8.4.0.1 as mysql # the backup image FROM --platform=$TARGETPLATFORM ghcr.io/cybozu/ubuntu:22.04 LABEL org.opencontainers.image.source https://github.com/cybozu-go/moco -ARG MYSQLSH_VERSION=8.0.37 +ARG MYSQLSH_VERSION=8.4.0 ARG MYSQLSH_GLIBC_VERSION=2.28 ARG TARGETARCH @@ -41,7 +41,7 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* \ && if [ "${TARGETARCH}" = 'amd64' ]; then MYSQLSH_ARCH='x86-64'; fi \ && if [ "${TARGETARCH}" = 'arm64' ]; then MYSQLSH_ARCH='arm-64'; fi \ - && curl -o /tmp/mysqlsh.tar.gz -fsL "https://cdn.mysql.com//Downloads/MySQL-Shell/mysql-shell-${MYSQLSH_VERSION}-linux-glibc${MYSQLSH_GLIBC_VERSION}-${MYSQLSH_ARCH:-unknown}bit.tar.gz" \ + && curl -o /tmp/mysqlsh.tar.gz -fsL "https://cdn.mysql.com/Downloads/MySQL-Shell/mysql-shell-${MYSQLSH_VERSION}-linux-glibc${MYSQLSH_GLIBC_VERSION}-${MYSQLSH_ARCH:-unknown}bit.tar.gz" \ && mkdir /usr/local/mysql-shell \ && tar -xf /tmp/mysqlsh.tar.gz -C /usr/local/mysql-shell --strip-components=1 \ && rm -f /tmp/mysqlsh.tar.gz diff --git a/Makefile b/Makefile index 7e28e4a63..08079ad50 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CTRL_RUNTIME_VERSION := $(shell awk '/sigs.k8s.io\/controller-runtime/ {print su KUSTOMIZE_VERSION = 5.4.1 HELM_VERSION = 3.15.0 CRD_TO_MARKDOWN_VERSION = 0.0.3 -MYSQLSH_VERSION = 8.0.37-1 +MYSQLSH_VERSION = 8.4.0-1 MDBOOK_VERSION = 0.4.37 GORELEASER_VERSION = 1.26.1 YQ_VERSION = 4.44.1 diff --git a/README.md b/README.md index ada50674f..5652bbbab 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Blog article: [Introducing MOCO, a modern MySQL operator on Kubernetes](https:// ## Supported software -- MySQL: 8.0.18, 8.0.25, 8.0.26, 8.0.27, 8.0.28, 8.0.30, 8.0.31, 8.0.32, 8.0.33, 8.0.34, 8.0.35, 8.0.36, 8.0.37 +- MySQL: 8.0.28, 8.0.36, 8.0.37, 8.4.0 - Kubernetes: 1.27, 1.28, 1.29 MOCO supports (tests) the LTS releases of MySQL 8. @@ -74,7 +74,7 @@ spec: spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.37 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 volumeClaimTemplates: - metadata: name: mysql-data diff --git a/docs/change-pvc-template.md b/docs/change-pvc-template.md index 36839dc77..66bc4be2b 100644 --- a/docs/change-pvc-template.md +++ b/docs/change-pvc-template.md @@ -93,7 +93,7 @@ For example, the user modifies the `.spec.volumeClaimTemplates` of the MySQLClus spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.30 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 volumeClaimTemplates: - metadata: name: mysql-data diff --git a/docs/custom-mysqld.md b/docs/custom-mysqld.md index 1309e4c9c..4e44db6b0 100644 --- a/docs/custom-mysqld.md +++ b/docs/custom-mysqld.md @@ -11,7 +11,7 @@ spec: spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.35 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 ``` If you want to build and use your own `mysqld`, read the rest of this document. @@ -29,19 +29,19 @@ You should keep the following points: ## How to build `mysqld` -On Ubuntu 20.04, you can build the source code as follows: +On Ubuntu 22.04, you can build the source code as follows: ```console $ sudo apt-get update $ sudo apt-get -y --no-install-recommends install build-essential libssl-dev \ cmake libncurses5-dev libjemalloc-dev libnuma-dev libaio-dev pkg-config -$ curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-8.0.20.tar.gz -$ tar -x -z -f mysql-boost-8.0.20.tar.gz -$ cd mysql-8.0.20 +$ curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-8.4.0.tar.gz +$ tar -x -z -f mysql-8.4.0.tar.gz +$ cd mysql-8.4.0 $ mkdir bld $ cd bld $ cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release \ - -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 + -DWITH_NUMA=1 -DWITH_JEMALLOC=1 $ make -j $(nproc) $ make install ``` diff --git a/docs/designdoc/allow_customize_containers.md b/docs/designdoc/allow_customize_containers.md index 0d6c870a4..6a1b2f43a 100644 --- a/docs/designdoc/allow_customize_containers.md +++ b/docs/designdoc/allow_customize_containers.md @@ -32,7 +32,7 @@ spec: spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.30 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 overwriteContainers: - name: agent resources: @@ -95,7 +95,7 @@ spec: spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.30 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 overwriteContainers: agent: resources: diff --git a/docs/designdoc/support_reduce_volume_size.md b/docs/designdoc/support_reduce_volume_size.md index e790838a1..69bac5154 100644 --- a/docs/designdoc/support_reduce_volume_size.md +++ b/docs/designdoc/support_reduce_volume_size.md @@ -45,7 +45,7 @@ For example, the user modifies the `.spec.volumeClaimTemplates` of the MySQLClus spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.30 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 volumeClaimTemplates: - metadata: name: mysql-data diff --git a/docs/usage.md b/docs/usage.md index 74166cb78..48a5c21d1 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -100,7 +100,7 @@ spec: containers: # At least a container named "mysqld" must be defined. - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.35 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 # By limiting CPU and memory, Pods will have Guaranteed QoS class. # requests can be omitted; it will be set to the same value as limits. resources: @@ -208,7 +208,7 @@ spec: spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.35 # must be the same version as the donor + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 # must be the same version as the donor volumeClaimTemplates: - metadata: name: mysql-data @@ -727,7 +727,7 @@ spec: containers: - name: mysqld # Edit the next line - image: ghcr.io/cybozu-go/moco/mysql:8.0.35 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 ``` You are advised to make backups and/or create a replica cluster before starting the upgrade process. diff --git a/e2e/Makefile b/e2e/Makefile index 99ac57472..3f40b0be7 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -1,7 +1,7 @@ KIND_VERSION = 0.23.0 KUBERNETES_VERSION = 1.29.4 CERT_MANAGER_VERSION = 1.14.5 -MYSQL_VERSION = 8.0.37 +MYSQL_VERSION = 8.4.0 KIND := $(dir $(shell pwd))/bin/kind KUBECTL := $(dir $(shell pwd))/bin/kubectl diff --git a/e2e/upgrade_test.go b/e2e/upgrade_test.go index 1b7e2e7d5..55b02d093 100644 --- a/e2e/upgrade_test.go +++ b/e2e/upgrade_test.go @@ -19,8 +19,8 @@ import ( var upgradeYAML string const ( - mysqlVersionOld = "8.0.18" - mysqlVersionNew = "8.0.25" + mysqlVersionOld = "8.0.28" + mysqlVersionNew = "8.4.0" ) var _ = Context("upgrade", func() { diff --git a/examples/anti-affinity.yaml b/examples/anti-affinity.yaml index 4b611e6e9..5410d5aba 100644 --- a/examples/anti-affinity.yaml +++ b/examples/anti-affinity.yaml @@ -26,7 +26,7 @@ spec: topologyKey: "kubernetes.io/hostname" containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.35 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 resources: requests: cpu: "10" diff --git a/examples/collect-metrics.yaml b/examples/collect-metrics.yaml index 0a6cd7028..1fa90aff0 100644 --- a/examples/collect-metrics.yaml +++ b/examples/collect-metrics.yaml @@ -14,7 +14,7 @@ spec: spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.35 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 volumeClaimTemplates: - metadata: name: mysql-data diff --git a/examples/custom-mycnf.yaml b/examples/custom-mycnf.yaml index bd4df8540..3c808d50c 100644 --- a/examples/custom-mycnf.yaml +++ b/examples/custom-mycnf.yaml @@ -24,7 +24,7 @@ spec: spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.35 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 volumeClaimTemplates: - metadata: name: mysql-data diff --git a/examples/custom-probe.yaml b/examples/custom-probe.yaml index 1a5cc4e22..70343e3ef 100644 --- a/examples/custom-probe.yaml +++ b/examples/custom-probe.yaml @@ -10,7 +10,7 @@ spec: spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.35 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 # If you want to override the default probes, you cannot override the httpGet. livenessProbe: failureThreshold: 3 diff --git a/examples/guaranteed.yaml b/examples/guaranteed.yaml index 93ea7668b..389012490 100644 --- a/examples/guaranteed.yaml +++ b/examples/guaranteed.yaml @@ -10,7 +10,7 @@ spec: spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.35 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 # By limiting CPU and memory, Pods will have Guaranteed QoS class. # requests can be omitted; it will be set to the same value as limits. resources: diff --git a/examples/loadbalancer.yaml b/examples/loadbalancer.yaml index 130446cb2..e0353dabb 100644 --- a/examples/loadbalancer.yaml +++ b/examples/loadbalancer.yaml @@ -18,7 +18,7 @@ spec: spec: containers: - name: mysqld - image: ghcr.io/cybozu-go/moco/mysql:8.0.35 + image: ghcr.io/cybozu-go/moco/mysql:8.4.0 volumeClaimTemplates: - metadata: name: mysql-data diff --git a/pkg/bkop/operator_test.go b/pkg/bkop/operator_test.go index 2ed6fa36b..d173355dc 100644 --- a/pkg/bkop/operator_test.go +++ b/pkg/bkop/operator_test.go @@ -5,6 +5,7 @@ import ( "os" "os/exec" "path/filepath" + "strings" "time" "github.com/cybozu-go/moco/pkg/constants" @@ -76,7 +77,13 @@ var _ = Describe("Operator", func() { opRe.(operator).db.MustExec(`DROP USER 'root'@'localhost'`) opRe.(operator).db.MustExec(`DROP USER 'root'@'%'`) opRe.(operator).db.MustExec(`FLUSH LOCAL PRIVILEGES`) - opRe.(operator).db.MustExec(`RESET MASTER`) + + mysqlVersion := os.Getenv("MYSQL_VERSION") + if strings.HasPrefix(mysqlVersion, "8.4") { + opRe.(operator).db.MustExec(`RESET BINARY LOGS AND GTIDS`) + } else { + opRe.(operator).db.MustExec(`RESET MASTER`) + } opRe.(operator).db.MustExec(`SET GLOBAL super_read_only=1`) baseDir, err = os.MkdirTemp("", "") diff --git a/pkg/dbop/replication_test.go b/pkg/dbop/replication_test.go index bd2f1022a..15da1c37c 100644 --- a/pkg/dbop/replication_test.go +++ b/pkg/dbop/replication_test.go @@ -92,7 +92,7 @@ var _ = Describe("replication", func() { Expect(err).NotTo(HaveOccurred()) err = ops[1].WaitForGTID(ctx, st0.GlobalVariables.ExecutedGTID, 1) Expect(err).To(MatchError(ErrTimeout)) - _, err = ops[1].db.Exec(`START SLAVE`) + _, err = ops[1].db.Exec(`START REPLICA`) Expect(err).NotTo(HaveOccurred()) err = ops[1].WaitForGTID(ctx, st0.GlobalVariables.ExecutedGTID, 0) Expect(err).NotTo(HaveOccurred()) diff --git a/pkg/mycnf/generator.go b/pkg/mycnf/generator.go index 2dfe93de3..b0819f83b 100644 --- a/pkg/mycnf/generator.go +++ b/pkg/mycnf/generator.go @@ -94,6 +94,9 @@ var DefaultMycnf = map[string]string{ // Disabled because of https://bugs.mysql.com/bug.php?id=104573 // The undo log truncate always fails on replica instances of `super_read_only = 1`. "innodb_undo_log_truncate": "OFF", + + // Disabled by default in MySQL 8.4 + "loose_mysql_native_password": "ON", } // ConstMycnf is the mysqld configurations that MOCO applies forcibly. diff --git a/pkg/mycnf/testdata/bufsize.cnf b/pkg/mycnf/testdata/bufsize.cnf index cbb2c508e..06fcfde8d 100644 --- a/pkg/mycnf/testdata/bufsize.cnf +++ b/pkg/mycnf/testdata/bufsize.cnf @@ -47,6 +47,7 @@ long_query_time = 2 loose_binlog_transaction_compression = ON loose_innodb_numa_interleave = ON loose_innodb_validate_tablespace_paths = OFF +loose_mysql_native_password = ON loose_replication_optimize_for_static_plugin_config = ON loose_replication_sender_observe_commit_only = OFF max_allowed_packet = 1G diff --git a/pkg/mycnf/testdata/loose.cnf b/pkg/mycnf/testdata/loose.cnf index f656fe67e..0e5acb7ae 100644 --- a/pkg/mycnf/testdata/loose.cnf +++ b/pkg/mycnf/testdata/loose.cnf @@ -47,6 +47,7 @@ log_slow_extra = ON long_query_time = 2 loose_binlog_transaction_compression = ON loose_innodb_validate_tablespace_paths = ON +loose_mysql_native_password = ON loose_replication_optimize_for_static_plugin_config = ON loose_replication_sender_observe_commit_only = OFF loose_temptable_use_mmap = ON diff --git a/pkg/mycnf/testdata/nil.cnf b/pkg/mycnf/testdata/nil.cnf index 4f341b135..9eb2bc6fa 100644 --- a/pkg/mycnf/testdata/nil.cnf +++ b/pkg/mycnf/testdata/nil.cnf @@ -47,6 +47,7 @@ long_query_time = 2 loose_binlog_transaction_compression = ON loose_innodb_numa_interleave = ON loose_innodb_validate_tablespace_paths = OFF +loose_mysql_native_password = ON loose_replication_optimize_for_static_plugin_config = ON loose_replication_sender_observe_commit_only = OFF max_allowed_packet = 1G diff --git a/pkg/mycnf/testdata/normalize.cnf b/pkg/mycnf/testdata/normalize.cnf index 5b638b7f0..46c0e2e76 100644 --- a/pkg/mycnf/testdata/normalize.cnf +++ b/pkg/mycnf/testdata/normalize.cnf @@ -48,6 +48,7 @@ long_query_time = 2 loose_binlog_transaction_compression = ON loose_innodb_numa_interleave = ON loose_innodb_validate_tablespace_paths = OFF +loose_mysql_native_password = ON loose_replication_optimize_for_static_plugin_config = ON loose_replication_sender_observe_commit_only = OFF max_allowed_packet = 1G diff --git a/pkg/mycnf/testdata/opaque.cnf b/pkg/mycnf/testdata/opaque.cnf index 8e4354264..237043741 100644 --- a/pkg/mycnf/testdata/opaque.cnf +++ b/pkg/mycnf/testdata/opaque.cnf @@ -52,6 +52,7 @@ long_query_time = 2 loose_binlog_transaction_compression = ON loose_innodb_numa_interleave = ON loose_innodb_validate_tablespace_paths = OFF +loose_mysql_native_password = ON loose_replication_optimize_for_static_plugin_config = ON loose_replication_sender_observe_commit_only = OFF max_allowed_packet = 1G From 1f0bf8f252f577cc1bb28caf55bd456e2bee8cde Mon Sep 17 00:00:00 2001 From: shunki-fujita Date: Thu, 13 Jun 2024 08:59:29 +0000 Subject: [PATCH 4/9] issue-686: fix Supported MySQL versions End-to-End Tests --- .github/actions/e2e/action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/e2e/action.yaml b/.github/actions/e2e/action.yaml index f385992a5..23bdd008d 100644 --- a/.github/actions/e2e/action.yaml +++ b/.github/actions/e2e/action.yaml @@ -26,7 +26,7 @@ runs: run: make start KUBERNETES_VERSION=${{ inputs.k8s-version }} MYSQL_VERSION=${{ inputs.mysql-version }} KIND_CONFIG=kind-config_actions.yaml working-directory: e2e shell: bash - - run: make test + - run: make test MYSQL_VERSION=${{ inputs.mysql-version }} working-directory: e2e shell: bash - run: make logs From cb539a96c4402f02d567ba2a7b3cc8f0d2eb8a78 Mon Sep 17 00:00:00 2001 From: shunki-fujita Date: Tue, 18 Jun 2024 07:30:56 +0000 Subject: [PATCH 5/9] issue-686: update mysqld_exporter version --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index 7ec52f42a..2bfa0929e 100644 --- a/version.go +++ b/version.go @@ -8,5 +8,5 @@ const ( FluentBitImage = "ghcr.io/cybozu-go/moco/fluent-bit:3.0.2.1" // ExporterImage is the image for mysqld_exporter sidecar container. - ExporterImage = "ghcr.io/cybozu-go/moco/mysqld_exporter:0.15.1.1" + ExporterImage = "ghcr.io/cybozu-go/moco/mysqld_exporter:0.15.1.2" ) From b61f360d0aa8e87f2e06f85b756ee7f442bbd285 Mon Sep 17 00:00:00 2001 From: shunki-fujita Date: Tue, 18 Jun 2024 07:44:15 +0000 Subject: [PATCH 6/9] issue-686: disable mysql_native_password --- pkg/mycnf/generator.go | 3 --- pkg/mycnf/testdata/bufsize.cnf | 1 - pkg/mycnf/testdata/loose.cnf | 1 - pkg/mycnf/testdata/nil.cnf | 1 - pkg/mycnf/testdata/normalize.cnf | 1 - pkg/mycnf/testdata/opaque.cnf | 1 - 6 files changed, 8 deletions(-) diff --git a/pkg/mycnf/generator.go b/pkg/mycnf/generator.go index b0819f83b..2dfe93de3 100644 --- a/pkg/mycnf/generator.go +++ b/pkg/mycnf/generator.go @@ -94,9 +94,6 @@ var DefaultMycnf = map[string]string{ // Disabled because of https://bugs.mysql.com/bug.php?id=104573 // The undo log truncate always fails on replica instances of `super_read_only = 1`. "innodb_undo_log_truncate": "OFF", - - // Disabled by default in MySQL 8.4 - "loose_mysql_native_password": "ON", } // ConstMycnf is the mysqld configurations that MOCO applies forcibly. diff --git a/pkg/mycnf/testdata/bufsize.cnf b/pkg/mycnf/testdata/bufsize.cnf index 06fcfde8d..cbb2c508e 100644 --- a/pkg/mycnf/testdata/bufsize.cnf +++ b/pkg/mycnf/testdata/bufsize.cnf @@ -47,7 +47,6 @@ long_query_time = 2 loose_binlog_transaction_compression = ON loose_innodb_numa_interleave = ON loose_innodb_validate_tablespace_paths = OFF -loose_mysql_native_password = ON loose_replication_optimize_for_static_plugin_config = ON loose_replication_sender_observe_commit_only = OFF max_allowed_packet = 1G diff --git a/pkg/mycnf/testdata/loose.cnf b/pkg/mycnf/testdata/loose.cnf index 0e5acb7ae..f656fe67e 100644 --- a/pkg/mycnf/testdata/loose.cnf +++ b/pkg/mycnf/testdata/loose.cnf @@ -47,7 +47,6 @@ log_slow_extra = ON long_query_time = 2 loose_binlog_transaction_compression = ON loose_innodb_validate_tablespace_paths = ON -loose_mysql_native_password = ON loose_replication_optimize_for_static_plugin_config = ON loose_replication_sender_observe_commit_only = OFF loose_temptable_use_mmap = ON diff --git a/pkg/mycnf/testdata/nil.cnf b/pkg/mycnf/testdata/nil.cnf index 9eb2bc6fa..4f341b135 100644 --- a/pkg/mycnf/testdata/nil.cnf +++ b/pkg/mycnf/testdata/nil.cnf @@ -47,7 +47,6 @@ long_query_time = 2 loose_binlog_transaction_compression = ON loose_innodb_numa_interleave = ON loose_innodb_validate_tablespace_paths = OFF -loose_mysql_native_password = ON loose_replication_optimize_for_static_plugin_config = ON loose_replication_sender_observe_commit_only = OFF max_allowed_packet = 1G diff --git a/pkg/mycnf/testdata/normalize.cnf b/pkg/mycnf/testdata/normalize.cnf index 46c0e2e76..5b638b7f0 100644 --- a/pkg/mycnf/testdata/normalize.cnf +++ b/pkg/mycnf/testdata/normalize.cnf @@ -48,7 +48,6 @@ long_query_time = 2 loose_binlog_transaction_compression = ON loose_innodb_numa_interleave = ON loose_innodb_validate_tablespace_paths = OFF -loose_mysql_native_password = ON loose_replication_optimize_for_static_plugin_config = ON loose_replication_sender_observe_commit_only = OFF max_allowed_packet = 1G diff --git a/pkg/mycnf/testdata/opaque.cnf b/pkg/mycnf/testdata/opaque.cnf index 237043741..8e4354264 100644 --- a/pkg/mycnf/testdata/opaque.cnf +++ b/pkg/mycnf/testdata/opaque.cnf @@ -52,7 +52,6 @@ long_query_time = 2 loose_binlog_transaction_compression = ON loose_innodb_numa_interleave = ON loose_innodb_validate_tablespace_paths = OFF -loose_mysql_native_password = ON loose_replication_optimize_for_static_plugin_config = ON loose_replication_sender_observe_commit_only = OFF max_allowed_packet = 1G From 8de622f9cdbdeafdce92076af75e44f4b28609ac Mon Sep 17 00:00:00 2001 From: shunki-fujita Date: Tue, 18 Jun 2024 07:59:06 +0000 Subject: [PATCH 7/9] issue-686: update moco-agent --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 452df1b22..1a56e4a4c 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/aws/aws-sdk-go-v2/credentials v1.17.15 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.20 github.com/aws/aws-sdk-go-v2/service/s3 v1.54.2 - github.com/cybozu-go/moco-agent v0.11.0 + github.com/cybozu-go/moco-agent v0.12.1 github.com/go-logr/logr v1.4.2 github.com/go-logr/stdr v1.2.2 github.com/go-sql-driver/mysql v1.8.1 diff --git a/go.sum b/go.sum index 1a2e89335..203daef2d 100644 --- a/go.sum +++ b/go.sum @@ -74,8 +74,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/cybozu-go/moco-agent v0.11.0 h1:gDNmhw5zl8eQP9aKYr7lX7K5hlL3Cv0jq9CJ9gGtpG4= -github.com/cybozu-go/moco-agent v0.11.0/go.mod h1:qea2oTno2dEpLLHHi/GiY8T0x+Aw6373aGbfk0fA5Bc= +github.com/cybozu-go/moco-agent v0.12.1 h1:Wp3S5whb9b3nD4cNvtJohJ/yBu6TtE7X3Md7WSIK/fw= +github.com/cybozu-go/moco-agent v0.12.1/go.mod h1:qea2oTno2dEpLLHHi/GiY8T0x+Aw6373aGbfk0fA5Bc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From df726477bb2c71ed639b681c9fe621e7b25c90df Mon Sep 17 00:00:00 2001 From: shunki-fujita Date: Tue, 18 Jun 2024 08:58:41 +0000 Subject: [PATCH 8/9] issue-686: increase time in Timeout --- e2e/upgrade_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/upgrade_test.go b/e2e/upgrade_test.go index 55b02d093..3125157ee 100644 --- a/e2e/upgrade_test.go +++ b/e2e/upgrade_test.go @@ -128,7 +128,7 @@ var _ = Context("upgrade", func() { } } return nil - }, 600).Should(Succeed()) + }, 1200).Should(Succeed()) cluster, err := getCluster("upgrade", "test") Expect(err).NotTo(HaveOccurred()) Expect(cluster.Status.CurrentPrimaryIndex).To(Equal(1)) From ff5abb2ddf845905537709ac38968d0a6158a7c8 Mon Sep 17 00:00:00 2001 From: shunki-fujita Date: Fri, 21 Jun 2024 08:41:31 +0000 Subject: [PATCH 9/9] Wait for the process to be killed --- pkg/dbop/kill_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/dbop/kill_test.go b/pkg/dbop/kill_test.go index 880972a96..5ce3772e7 100644 --- a/pkg/dbop/kill_test.go +++ b/pkg/dbop/kill_test.go @@ -54,7 +54,9 @@ var _ = Describe("kill", func() { var procs2 []Process err = op.(*operator).db.Select(&procs2, `SELECT ID, USER, HOST FROM information_schema.PROCESSLIST`) Expect(err).NotTo(HaveOccurred()) - Expect(len(procs) - len(procs2)).To(Equal(1)) + Eventually(func() int { + return len(procs) - len(procs2) + }).Should(BeNumerically("==", 1)) fooFound = false for _, p := range procs2 {