Skip to content
This repository was archived by the owner on May 28, 2021. It is now read-only.

Commit f455bf2

Browse files
prydieowainlewis
authored andcommitted
Upgrade to MySQL 8.0.11 (GA) (#87)
* Migrate to MySQL 8.0.11 * Implement recovery from complete outage * Remove 5.7.20-1.1.2 as a valid version * Remove clearing of binary logs on add instance * Use name-index.name to address cluster members (fixes #84) * Stop leaking mysqlsh processes * Disable GR SSL * Whitelist ips for GR members
1 parent f3b89a4 commit f455bf2

40 files changed

+608
-254
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ USE_GLOBAL_NAMESPACE ?= false
1717
ifdef WERCKER
1818
# Insert swear words about mysql group replication and hostname length. Arghh..
1919
NEW_NAMESPACE ?= e2e-$(shell echo ${WERCKER_GIT_COMMIT} | fold -w 8 | head -n1)
20-
VERSION ?= ${WERCKER_GIT_COMMIT}
20+
VERSION := ${WERCKER_GIT_COMMIT}
2121
E2E_FUNC := e2efunc-wercker
2222
E2E_NON_BUFFERED_LOGS ?= false
2323
else
2424
NEW_NAMESPACE ?= e2e-${USER}
25-
VERSION ?= ${USER}-$(shell date +%Y%m%d%H%M%S)
25+
VERSION := ${USER}-$(shell date +%Y%m%d%H%M%S)
2626
E2E_FUNC := e2efunc-docker
2727
E2E_NON_BUFFERED_LOGS ?= true
2828
endif

cmd/mysql-agent/app/mysql_agent.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ func Run(opts *options.MySQLAgentOpts) error {
6969
signals.SetupSignalHandler(cancelFunc)
7070

7171
// Set up healthchecks (liveness and readiness).
72+
checkInCluster, err := cluster.NewHealthCheck(ctx)
73+
if err != nil {
74+
glog.Fatal(err)
75+
}
7276
health := healthcheck.NewHandler()
73-
health.AddReadinessCheck("node-in-cluster",
74-
healthcheck.Async(
75-
healthcheck.Timeout(func() error { return cluster.CheckNodeInCluster(ctx) }, 5*time.Second),
76-
10*time.Second,
77-
))
77+
health.AddReadinessCheck("node-in-cluster", checkInCluster)
7878
go func() {
7979
glog.Fatal(http.ListenAndServe(
8080
net.JoinHostPort(opts.Address, strconv.Itoa(int(opts.HealthcheckPort))),

docker/mysql-agent/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM mysql/mysql-server:5.7.20-1.1.2
1+
FROM mysql/mysql-server:8.0.11
22

33
COPY bin/linux_amd64/mysql-agent /
44

examples/backup/backup-schedule.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ spec:
1010
databases:
1111
- test
1212
storage:
13-
provider: s3
13+
provider: s3
1414
secretRef:
1515
name: s3-credentials
1616
config:
1717
endpoint: ocitenancy.compat.objectstorage.ociregion.oraclecloud.com
1818
region: ociregion
1919
bucket: mybucket
2020
clusterRef:
21-
name: mysql-cluster
21+
name: mysql

examples/backup/backup.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ spec:
88
databases:
99
- test
1010
storage:
11-
provider: s3
11+
provider: s3
1212
secretRef:
1313
name: s3-credentials
14-
config:
14+
config:
1515
endpoint: ocitenancy.compat.objectstorage.ociregion.oraclecloud.com
1616
region: ociregion
1717
bucket: mybucket
1818
clusterRef:
19-
name: mysql-cluster
19+
name: mysql
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
apiVersion: "mysql.oracle.com/v1"
22
kind: MySQLCluster
33
metadata:
4-
name: mysql-cluster-with-3-replicas
4+
name: mysql
55
spec:
66
replicas: 3

examples/cluster/cluster-with-custom-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: "mysql.oracle.com/v1"
22
kind: MySQLCluster
33
metadata:
4-
name: mysql-cluster-with-custom-config
4+
name: mysql
55
spec:
66
replicas: 1
77
configRef:

examples/cluster/cluster-with-custom-secret.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: "mysql.oracle.com/v1"
22
kind: MySQLCluster
33
metadata:
4-
name: mysql-cluster-with-custom-secret
4+
name: mysql
55
spec:
66
replicas: 1
77
secretRef:

examples/cluster/cluster-with-data-volume-and-backup-volume.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ spec:
3434
apiVersion: "mysql.oracle.com/v1"
3535
kind: MySQLCluster
3636
metadata:
37-
name: mysql-cluster-with-data-volume-and-backup-volume
37+
name: mysql
3838
spec:
3939
replicas: 1
4040
secretRef:

examples/cluster/cluster-with-volume.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ spec:
1818
apiVersion: "mysql.oracle.com/v1"
1919
kind: MySQLCluster
2020
metadata:
21-
name: example-mysql-cluster-with-volume
21+
name: mysql
2222
spec:
2323
replicas: 1
2424
secretRef:

examples/cluster/cluster.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
apiVersion: "mysql.oracle.com/v1"
22
kind: MySQLCluster
33
metadata:
4-
name: mysql-cluster
4+
name: mysql
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: "mysql.oracle.com/v1"
22
kind: MySQLCluster
33
metadata:
4-
name: mysql-multimaster-cluster
4+
name: mysql
55
spec:
66
multiMaster: true
77
replicas: 3
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,27 @@
11
---
2+
kind: ConfigMap
3+
apiVersion: v1
4+
metadata:
5+
name: mysql-config
6+
data:
7+
my.cnf: |-
8+
[mysqld]
9+
default_authentication_plugin=mysql_native_password
10+
---
11+
apiVersion: v1
12+
kind: Secret
13+
metadata:
14+
name: wordpress-mysql-root-password
15+
data:
16+
password: bXktc3VwZXItc2VjcmV0LXBhc3M=
17+
---
218
apiVersion: "mysql.oracle.com/v1"
319
kind: MySQLCluster
420
metadata:
521
name: mysql-wordpress
622
spec:
723
replicas: 3
24+
configRef:
25+
name: mysql-config
826
secretRef:
927
name: wordpress-mysql-root-password

examples/demo/wordpress-router/wordpress-deployment.yaml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ spec:
2828
spec:
2929
containers:
3030
- name: mysqlrouter
31-
image: mysql/mysql-router:8.0
31+
image: mysql/mysql-router:8.0.11
3232
env:
3333
- name: MYSQL_PASSWORD
3434
valueFrom:
@@ -46,14 +46,9 @@ spec:
4646
command:
4747
- "/bin/bash"
4848
- "-cx"
49-
- |
50-
echo "Updating resolv.conf"
51-
search=$(grep ^search /etc/resolv.conf)
52-
echo "$search mysql-wordpress.default.svc.cluster.local" >> /etc/resolv.conf
53-
echo "Running the router"
54-
exec /run.sh mysqlrouter
49+
- "exec /run.sh mysqlrouter"
5550
- name: wordpress
56-
image: wordpress:4.8.0-apache
51+
image: wordpress:4.9.0-apache
5752
env:
5853
- name: WORDPRESS_DB_HOST
5954
value: 127.0.0.1:6446

examples/restore/restore.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ metadata:
44
name: mysql-restore
55
spec:
66
clusterRef:
7-
name: mysql-cluster
7+
name: mysql
88
backupRef:
99
name: mysql-backup

hack/mysql.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ fi
99

1010
NAMESPACE=${1%/*}
1111
POD=${1#*/}
12+
CLUSTER_NAME=${POD%-*} # statefulset and service name
13+
HOST="${POD}.${CLUSTER_NAME}"
1214

1315
kubectl exec \
1416
-n ${NAMESPACE} \
1517
-it \
1618
-c mysql-agent \
1719
${POD} -- /bin/sh \
18-
-c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD'
20+
-c "mysql -uroot -p\$MYSQL_ROOT_PASSWORD -h ${HOST}"

hack/mysqlsh-py.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ fi
99

1010
NAMESPACE=${1%/*}
1111
POD=${1#*/}
12+
CLUSTER_NAME=${POD%-*} # statefulset and service name
13+
URI="root:\$MYSQL_ROOT_PASSWORD@${POD}.${CLUSTER_NAME}:3306"
1214

1315
kubectl exec \
1416
-n ${NAMESPACE} \
1517
-it \
1618
-c mysql-agent \
1719
${POD} -- /bin/sh \
18-
-c 'mysqlsh --uri "root:$MYSQL_ROOT_PASSWORD@localhost:3306" --py'
20+
-c "PS1='\u@\h:\w\$ ' mysqlsh --no-wizard --uri ${URI} --py"

pkg/apis/mysql/v1/cluster.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222

2323
const (
2424
// The default MySQL version to use if not specified explicitly by user
25-
defaultVersion = "5.7.20-1.1.2"
25+
defaultVersion = "8.0.11"
2626
defaultReplicas = 1
2727
defaultBaseServerID = 1000
2828
// Max safe value for BaseServerID calculated as max MySQL server_id value - max Replication Group size
@@ -32,6 +32,17 @@ const (
3232
// ClusterCRDResourcePlural defines the custom resource name for mysqlclusters
3333
const ClusterCRDResourcePlural = "mysqlclusters"
3434

35+
const (
36+
// MaxInnoDBClusterMembers is the maximum number of members supported by InnoDB
37+
// group replication.
38+
MaxInnoDBClusterMembers = 9
39+
40+
// MySQLClusterNameMaxLen is the maximum supported length of a
41+
// MySQLCluster name.
42+
// See: https://bugs.mysql.com/bug.php?id=90601
43+
MySQLClusterNameMaxLen = 28
44+
)
45+
3546
// TODO (owain) we need to remove this because it's not reasonable for us to maintain a list
3647
// of all the potential MySQL versions that can be used and in reality, it shouldn't matter
3748
// too much. The burden of this is not worth the benfit to a user

pkg/apis/mysql/v1/validate_cluster.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,45 @@
1515
package v1
1616

1717
import (
18+
"fmt"
1819
"strconv"
1920

21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2022
"k8s.io/apimachinery/pkg/util/validation/field"
2123
)
2224

2325
func validateCluster(c *MySQLCluster) field.ErrorList {
2426
allErrs := field.ErrorList{}
27+
allErrs = append(allErrs, validateClusterMetadata(c.ObjectMeta, field.NewPath("metadata"))...)
2528
allErrs = append(allErrs, validateClusterSpec(c.Spec, field.NewPath("spec"))...)
2629
allErrs = append(allErrs, validateClusterStatus(c.Status, field.NewPath("status"))...)
2730
return allErrs
2831
}
2932

33+
func validateClusterMetadata(m metav1.ObjectMeta, fldPath *field.Path) field.ErrorList {
34+
allErrs := field.ErrorList{}
35+
36+
allErrs = append(allErrs, validateName(m.Name, fldPath.Child("name"))...)
37+
38+
return allErrs
39+
}
40+
41+
func validateName(name string, fldPath *field.Path) field.ErrorList {
42+
allErrs := field.ErrorList{}
43+
44+
if len(name) > MySQLClusterNameMaxLen {
45+
msg := fmt.Sprintf("longer than maximum supported length %d (see: https://bugs.mysql.com/bug.php?id=90601)", MaxInnoDBClusterMembers)
46+
allErrs = append(allErrs, field.Invalid(fldPath, name, msg))
47+
}
48+
49+
return allErrs
50+
}
51+
3052
func validateClusterSpec(s MySQLClusterSpec, fldPath *field.Path) field.ErrorList {
3153
allErrs := field.ErrorList{}
3254

3355
allErrs = append(allErrs, validateVersion(s.Version, fldPath.Child("version"))...)
56+
allErrs = append(allErrs, validateReplicas(s.Replicas, fldPath.Child("replicas"))...)
3457
allErrs = append(allErrs, validateBaseServerID(s.BaseServerID, fldPath.Child("baseServerId"))...)
3558

3659
return allErrs
@@ -69,3 +92,11 @@ func validatePhase(phase MySQLClusterPhase, fldPath *field.Path) field.ErrorList
6992
}
7093
return append(allErrs, field.Invalid(fldPath, phase, "invalid phase specified"))
7194
}
95+
96+
func validateReplicas(replicas int32, fldPath *field.Path) field.ErrorList {
97+
allErrs := field.ErrorList{}
98+
if replicas < 1 || replicas > MaxInnoDBClusterMembers {
99+
allErrs = append(allErrs, field.Invalid(fldPath, replicas, "InnoDB clustering supports between 1-9 members"))
100+
}
101+
return allErrs
102+
}

pkg/cluster/cluster_health.go

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,57 @@ package cluster
1616

1717
import (
1818
"context"
19-
"errors"
19+
"sync"
20+
"time"
2021

21-
"github.com/golang/glog"
22-
utilexec "k8s.io/utils/exec"
22+
"github.com/heptiolabs/healthcheck"
23+
"github.com/pkg/errors"
2324

2425
"github.com/oracle/mysql-operator/pkg/cluster/innodb"
25-
"github.com/oracle/mysql-operator/pkg/util/mysqlsh"
2626
)
2727

28-
// CheckNodeInCluster checks whether or not the local MySQL instance is a member
29-
// of an InnoDB cluster.
30-
func CheckNodeInCluster(ctx context.Context) error {
31-
instance, err := NewLocalInstance()
32-
if err != nil {
33-
return err
34-
}
35-
mysh := mysqlsh.New(utilexec.New(), instance.GetShellURI())
36-
clusterStatus, err := mysh.GetClusterStatus(ctx)
37-
if err != nil {
38-
return err
39-
}
40-
if clusterStatus.GetInstanceStatus(instance.Name()) != innodb.InstanceStatusOnline {
41-
return errors.New("database still requires management")
42-
}
43-
return nil
28+
var (
29+
status *innodb.ClusterStatus
30+
statusMutex sync.Mutex
31+
)
32+
33+
// SetStatus sets the status of the local mysql cluster. The cluster manager
34+
// controller is responsible for updating.
35+
func SetStatus(new *innodb.ClusterStatus) {
36+
statusMutex.Lock()
37+
defer statusMutex.Unlock()
38+
status = new.DeepCopy()
4439
}
4540

46-
// GetClusterStatus returns a JSON string representing the status of the InnoDb
47-
// MySQL cluster. TODO: Remove me.
48-
func GetClusterStatus(ctx context.Context) (*innodb.ClusterStatus, error) {
49-
pod, err := NewLocalInstance()
50-
if err != nil {
51-
glog.Errorf("Failed to get the pod details: %+v", err)
52-
return nil, err
41+
// GetStatus fetches a copy of the latest cluster status.
42+
func GetStatus() *innodb.ClusterStatus {
43+
statusMutex.Lock()
44+
defer statusMutex.Unlock()
45+
if status == nil {
46+
return nil
5347
}
48+
return status.DeepCopy()
49+
}
5450

55-
mysh := mysqlsh.New(utilexec.New(), pod.GetShellURI())
56-
clusterStatus, err := mysh.GetClusterStatus(ctx)
51+
// NewHealthCheck constructs a healthcheck for the local instance which checks
52+
// cluster status using mysqlsh.
53+
func NewHealthCheck(ctx context.Context) (healthcheck.Check, error) {
54+
instance, err := NewLocalInstance()
5755
if err != nil {
58-
glog.V(4).Info("Failed to get the cluster status")
59-
return nil, err
56+
return nil, errors.Wrap(err, "getting local mysql instance")
6057
}
61-
return clusterStatus, nil
58+
59+
return healthcheck.AsyncWithContext(ctx,
60+
healthcheck.Timeout(
61+
func() error {
62+
s := GetStatus()
63+
if s == nil || s.GetInstanceStatus(instance.Name()) != innodb.InstanceStatusOnline {
64+
return errors.New("database still requires management")
65+
}
66+
return nil
67+
},
68+
5*time.Second,
69+
),
70+
10*time.Second,
71+
), nil
6272
}

0 commit comments

Comments
 (0)