From 293bad9bea7e9c10e57d3ffc85b9c09a3e0f9265 Mon Sep 17 00:00:00 2001 From: Alan Tang Date: Tue, 19 Mar 2019 16:56:38 +0800 Subject: [PATCH 1/4] Keep mysql readonly after exit group unintentionally Since mysql version >= 8.0.12, <= 8.0.15 changed default behavior to `ABORT_SERVER`. Which will shutdown the server after exit group unintentionally. It should better change server to `READ_ONLY` instead of exit. Future version MySQL also change this behavior back to `READ_ONLY` https://dev.mysql.com/doc/refman/8.0/en/group-replication-options.html#sysvar_group_replication_exit_state_action Signed-off-by: Alan Tang --- pkg/resources/statefulsets/statefulset.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/resources/statefulsets/statefulset.go b/pkg/resources/statefulsets/statefulset.go index ebfea7a10..470603f21 100644 --- a/pkg/resources/statefulsets/statefulset.go +++ b/pkg/resources/statefulsets/statefulset.go @@ -172,6 +172,7 @@ func mysqlServerContainer(cluster *v1alpha1.Cluster, mysqlServerImage string, ro "--master-info-repository=TABLE", "--relay-log-info-repository=TABLE", "--transaction-write-set-extraction=XXHASH64", + "--group-replication-exit-state-action=READ_ONLY", fmt.Sprintf("--relay-log=%s-${index}-relay-bin", cluster.Name), fmt.Sprintf("--report-host=\"%[1]s-${index}.%[1]s\"", cluster.Name), "--log-error-verbosity=3", From aa5924e8e25a20592d8fd8b62d93b9d52124d8d1 Mon Sep 17 00:00:00 2001 From: Alan Tang Date: Wed, 20 Mar 2019 10:45:25 +0800 Subject: [PATCH 2/4] Handle MySQL version < 8.0.12 Signed-off-by: Alan Tang --- pkg/resources/statefulsets/statefulset.go | 27 ++++++++++++++- .../statefulsets/statefulset_test.go | 34 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/pkg/resources/statefulsets/statefulset.go b/pkg/resources/statefulsets/statefulset.go index 470603f21..b467e59ff 100644 --- a/pkg/resources/statefulsets/statefulset.go +++ b/pkg/resources/statefulsets/statefulset.go @@ -33,6 +33,8 @@ import ( operatoropts "github.com/oracle/mysql-operator/pkg/options/operator" "github.com/oracle/mysql-operator/pkg/resources/secrets" "github.com/oracle/mysql-operator/pkg/version" + + goverion "github.com/hashicorp/go-version" ) const ( @@ -48,6 +50,8 @@ const ( mySQLSSLVolumeName = "mysqlsslvolume" replicationGroupPort = 13306 + + minMysqlVersionWithGroupExitStateArgs = "8.0.12" ) func volumeMounts(cluster *v1alpha1.Cluster) []v1.VolumeMount { @@ -155,6 +159,24 @@ func getReplicationGroupSeeds(name string, members int) string { return strings.Join(seeds, ",") } +func checkSupportGroupExitStateArgs(deployingVersion string) bool { + ver, err := goverion.NewVersion(deployingVersion) + if err != nil { + return false + } + + minVer, err := goverion.NewVersion(minMysqlVersionWithGroupExitStateArgs) + if err != nil { + return false + } + + if ver.GreaterThan(minVer) || ver.Equal(minVer) { + return true + } + + return false +} + // Builds the MySQL operator container for a cluster. // The 'mysqlImage' parameter is the image name of the mysql server to use with // no version information.. e.g. 'mysql/mysql-server' @@ -172,7 +194,6 @@ func mysqlServerContainer(cluster *v1alpha1.Cluster, mysqlServerImage string, ro "--master-info-repository=TABLE", "--relay-log-info-repository=TABLE", "--transaction-write-set-extraction=XXHASH64", - "--group-replication-exit-state-action=READ_ONLY", fmt.Sprintf("--relay-log=%s-${index}-relay-bin", cluster.Name), fmt.Sprintf("--report-host=\"%[1]s-${index}.%[1]s\"", cluster.Name), "--log-error-verbosity=3", @@ -185,6 +206,10 @@ func mysqlServerContainer(cluster *v1alpha1.Cluster, mysqlServerImage string, ro "--ssl-key=/etc/ssl/mysql/tls.key") } + if checkSupportGroupExitStateArgs(cluster.Spec.Version) { + args = append(args, "--group-replication-exit-state-action=READ_ONLY") + } + entryPointArgs := strings.Join(args, " ") cmd := fmt.Sprintf(` diff --git a/pkg/resources/statefulsets/statefulset_test.go b/pkg/resources/statefulsets/statefulset_test.go index 7d8544c05..615d36d0a 100644 --- a/pkg/resources/statefulsets/statefulset_test.go +++ b/pkg/resources/statefulsets/statefulset_test.go @@ -323,3 +323,37 @@ func TestClusterDefaultOverride(t *testing.T) { assert.Equal(t, "OverrideDefaultImage:"+v1alpha1.DefaultVersion, si) } + +func TestClusterSetGroupExitStateArgs(t *testing.T) { + cluster := &v1alpha1.Cluster{} + cluster.EnsureDefaults() + cluster.Spec.Version = "8.0.12" + + statefulSet := NewForCluster(cluster, mockOperatorConfig().Images, "mycluster") + + cmd := statefulSet.Spec.Template.Spec.Containers[0].Command[2] + + assert.Contains(t, cmd, "--group-replication-exit-state-action=READ_ONLY") + + cluster2 := &v1alpha1.Cluster{} + cluster2.EnsureDefaults() + cluster2.Spec.Version = "8.0.13" + + statefulSet2 := NewForCluster(cluster2, mockOperatorConfig().Images, "mycluster") + + cmd2 := statefulSet2.Spec.Template.Spec.Containers[0].Command[2] + + assert.Contains(t, cmd2, "--group-replication-exit-state-action=READ_ONLY") +} + +func TestClusterNotSetGroupExitStateArgs(t *testing.T) { + cluster := &v1alpha1.Cluster{} + cluster.EnsureDefaults() + cluster.Spec.Version = "8.0.11" + + statefulSet := NewForCluster(cluster, mockOperatorConfig().Images, "mycluster") + + cmd := statefulSet.Spec.Template.Spec.Containers[0].Command[2] + + assert.NotContains(t, cmd, "--group-replication-exit-state-action=READ_ONLY") +} From 9d027722ebe9c09821f582e3757f427c9d94d175 Mon Sep 17 00:00:00 2001 From: Alan Tang Date: Wed, 20 Mar 2019 11:26:39 +0800 Subject: [PATCH 3/4] Change to use semver to compare version Not realized there already have semver can use before. Signed-off-by: Alan Tang --- pkg/resources/statefulsets/statefulset.go | 28 ++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/pkg/resources/statefulsets/statefulset.go b/pkg/resources/statefulsets/statefulset.go index b467e59ff..26761ef04 100644 --- a/pkg/resources/statefulsets/statefulset.go +++ b/pkg/resources/statefulsets/statefulset.go @@ -34,7 +34,7 @@ import ( "github.com/oracle/mysql-operator/pkg/resources/secrets" "github.com/oracle/mysql-operator/pkg/version" - goverion "github.com/hashicorp/go-version" + "github.com/coreos/go-semver/semver" ) const ( @@ -159,22 +159,24 @@ func getReplicationGroupSeeds(name string, members int) string { return strings.Join(seeds, ",") } -func checkSupportGroupExitStateArgs(deployingVersion string) bool { - ver, err := goverion.NewVersion(deployingVersion) - if err != nil { - return false - } +func checkSupportGroupExitStateArgs(deployingVersion string) (supportedVer bool) { + defer func() { + if r := recover(); r != nil { - minVer, err := goverion.NewVersion(minMysqlVersionWithGroupExitStateArgs) - if err != nil { - return false - } + } + }() + + supportedVer = false + + ver := semver.New(deployingVersion) + minVer := semver.New(minMysqlVersionWithGroupExitStateArgs) - if ver.GreaterThan(minVer) || ver.Equal(minVer) { - return true + if ver.LessThan(*minVer) { + return } - return false + supportedVer = true + return } // Builds the MySQL operator container for a cluster. From 641c30af0008c6411581d4282869b86462e42874 Mon Sep 17 00:00:00 2001 From: Alan Tang Date: Wed, 20 Mar 2019 13:56:51 +0800 Subject: [PATCH 4/4] Add loose to bypass MySQL start validate Because MySQL check variable before load group replication plugin Signed-off-by: Alan Tang --- pkg/resources/statefulsets/statefulset.go | 2 +- pkg/resources/statefulsets/statefulset_test.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/resources/statefulsets/statefulset.go b/pkg/resources/statefulsets/statefulset.go index 26761ef04..b3ae46f3c 100644 --- a/pkg/resources/statefulsets/statefulset.go +++ b/pkg/resources/statefulsets/statefulset.go @@ -209,7 +209,7 @@ func mysqlServerContainer(cluster *v1alpha1.Cluster, mysqlServerImage string, ro } if checkSupportGroupExitStateArgs(cluster.Spec.Version) { - args = append(args, "--group-replication-exit-state-action=READ_ONLY") + args = append(args, "--loose-group-replication-exit-state-action=READ_ONLY") } entryPointArgs := strings.Join(args, " ") diff --git a/pkg/resources/statefulsets/statefulset_test.go b/pkg/resources/statefulsets/statefulset_test.go index 615d36d0a..fc3050e79 100644 --- a/pkg/resources/statefulsets/statefulset_test.go +++ b/pkg/resources/statefulsets/statefulset_test.go @@ -333,7 +333,7 @@ func TestClusterSetGroupExitStateArgs(t *testing.T) { cmd := statefulSet.Spec.Template.Spec.Containers[0].Command[2] - assert.Contains(t, cmd, "--group-replication-exit-state-action=READ_ONLY") + assert.Contains(t, cmd, "--loose-group-replication-exit-state-action=READ_ONLY") cluster2 := &v1alpha1.Cluster{} cluster2.EnsureDefaults() @@ -343,7 +343,7 @@ func TestClusterSetGroupExitStateArgs(t *testing.T) { cmd2 := statefulSet2.Spec.Template.Spec.Containers[0].Command[2] - assert.Contains(t, cmd2, "--group-replication-exit-state-action=READ_ONLY") + assert.Contains(t, cmd2, "--loose-group-replication-exit-state-action=READ_ONLY") } func TestClusterNotSetGroupExitStateArgs(t *testing.T) { @@ -355,5 +355,5 @@ func TestClusterNotSetGroupExitStateArgs(t *testing.T) { cmd := statefulSet.Spec.Template.Spec.Containers[0].Command[2] - assert.NotContains(t, cmd, "--group-replication-exit-state-action=READ_ONLY") + assert.NotContains(t, cmd, "--loose-group-replication-exit-state-action=READ_ONLY") }