From ebd7ca64a50761fc1ace9b4ef5abe6bc8d74a275 Mon Sep 17 00:00:00 2001 From: cris Date: Wed, 10 Aug 2022 14:16:02 +0800 Subject: [PATCH 1/2] *: support MySQL subversion --- Dockerfile | 1 - Dockerfile.sidecar | 1 - Makefile | 17 +++++++++-------- api/v1alpha1/mysqlcluster_types.go | 4 ++++ api/v1alpha1/mysqlcluster_webhook.go | 3 ++- build/mysql/Dockerfile | 1 - build/xenon/Dockerfile | 2 +- .../crds/mysql.radondb.com_mysqlclusters.yaml | 4 ++++ .../bases/mysql.radondb.com_mysqlclusters.yaml | 4 ++++ .../samples/mysql_v1alpha1_mysqlcluster.yaml | 2 +- ...pha1_mysqlcluster_backup_schedule_demo.yaml | 2 +- .../mysql_v1alpha1_mysqlcluster_mysql8.yaml | 2 +- ..._v1alpha1_mysqlcluster_podAntiAffinity.yaml | 2 +- docs/en-us/backup_and_restoration_s3.md | 1 - docs/en-us/backup_cron.md | 1 - docs/zh-cn/backup_and_restoration_s3.md | 2 -- mysqlcluster/container/init_mysql.go | 2 +- mysqlcluster/container/init_mysql_test.go | 2 +- mysqlcluster/container/init_sidecar_test.go | 2 +- mysqlcluster/container/mysql.go | 2 +- mysqlcluster/container/mysql_test.go | 2 +- mysqlcluster/mysqlcluster.go | 18 +++--------------- mysqlcluster/mysqlcluster_test.go | 13 +++++++------ mysqlcluster/syncer/mysql_cm.go | 10 ++++++++-- test/e2e/framework/cluster_util.go | 3 +-- utils/common.go | 14 ++++++++++++++ utils/constants.go | 14 -------------- 27 files changed, 66 insertions(+), 65 deletions(-) diff --git a/Dockerfile b/Dockerfile index daa0463a2..8df52e281 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,6 @@ COPY go.mod go.mod COPY go.sum go.sum # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer -RUN if [ $(cat /etc/timezone) = "Asia/Shanghai" ] ; then go env -w GOPROXY=https://goproxy.cn,direct; fi RUN go mod download # Copy the go source diff --git a/Dockerfile.sidecar b/Dockerfile.sidecar index e51dbadbe..2c7e70e32 100644 --- a/Dockerfile.sidecar +++ b/Dockerfile.sidecar @@ -11,7 +11,6 @@ COPY go.sum go.sum # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer -RUN if [ $(cat /etc/timezone) = "Asia/Shanghai" ] ; then go env -w GOPROXY=https://goproxy.cn,direct; fi # go mod download RUN go mod download diff --git a/Makefile b/Makefile index e01a03886..dc41dd3c0 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,9 @@ # Image URL to use all building/pushing image targets -IMG ?= controller:latest -SIDECAR_IMG ?= sidecar:latest -XENON_IMG ?= xenon:latest +IMGPREFIX ?=radondb/ +IMG ?= $(IMGPREFIX)mysql-operator:latest +SIDECAR57_IMG ?= $(IMGPREFIX)mysql57-sidecar:latest +SIDECAR80_IMG ?= $(IMGPREFIX)mysql80-sidecar:latest +XENON_IMG ?= $(IMGPREFIX)xenon:latest # Produce CRDs that work back to Kubernetes 1.11 (no version conversion) CRD_OPTIONS ?= "crd:trivialVersions=true,preserveUnknownFields=false" @@ -58,7 +60,7 @@ ENVTEST_ASSETS_DIR=$(shell pwd)/testbin test: manifests generate fmt vet ## Run tests. mkdir -p ${ENVTEST_ASSETS_DIR} test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.8.3/hack/setup-envtest.sh - source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./... -coverprofile cover.out + source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test $(shell go list ./... | grep -v /test/) -coverprofile cover.out ##@ Build @@ -71,10 +73,9 @@ run: manifests generate fmt vet ## Run a controller from your host. docker-build: test ## Build docker image with the manager. docker build -t ${IMG} . - docker build -f Dockerfile.sidecar -t ${SIDECAR_IMG} . - docker build -f hack/xenon/Dockerfile -t ${XENON_IMG} hack/xenon -mysql8-sidecar: - docker build --build-arg XTRABACKUP_PKG=percona-xtrabackup-80 -f Dockerfile.sidecar -t ${SIDECAR_IMG} . + docker build -f Dockerfile.sidecar -t ${SIDECAR57_IMG} . + docker build -f build/xenon/Dockerfile -t ${XENON_IMG} . + docker build --build-arg XTRABACKUP_PKG=percona-xtrabackup-80 -f Dockerfile.sidecar -t ${SIDECAR80_IMG} . docker-push: ## Push docker image with the manager. docker push ${IMG} docker push ${SIDECAR_IMG} diff --git a/api/v1alpha1/mysqlcluster_types.go b/api/v1alpha1/mysqlcluster_types.go index 932a7e467..849a5ed86 100644 --- a/api/v1alpha1/mysqlcluster_types.go +++ b/api/v1alpha1/mysqlcluster_types.go @@ -104,6 +104,10 @@ type MysqlClusterSpec struct { // MysqlOpts defines the options of MySQL container. type MysqlOpts struct { + // Specifies mysql image to use. + // +optional + // +kubebuilder:default:="percona/percona-server:5.7.34" + Image string `json:"image,omitempty"` // Unchangeable: Use super users instead // Password for the root user, can be empty or 8~32 characters long. // Only be a combination of uppercase letters, lowercase letters, numbers or special characters. diff --git a/api/v1alpha1/mysqlcluster_webhook.go b/api/v1alpha1/mysqlcluster_webhook.go index 8d23e44ce..46d1f8dcc 100644 --- a/api/v1alpha1/mysqlcluster_webhook.go +++ b/api/v1alpha1/mysqlcluster_webhook.go @@ -18,6 +18,7 @@ package v1alpha1 import ( "fmt" + "strings" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" @@ -98,7 +99,7 @@ func (r *MysqlCluster) validateVolumeSize(oldCluster *MysqlCluster) error { func (r *MysqlCluster) validateLowTableCase(oldCluster *MysqlCluster) error { oldmyconf := oldCluster.Spec.MysqlOpts.MysqlConf newmyconf := r.Spec.MysqlOpts.MysqlConf - if r.Spec.MysqlVersion == "8.0" && + if strings.Contains(r.Spec.MysqlOpts.Image, "8.0") && oldmyconf["lower_case_table_names"] != newmyconf["lower_case_table_names"] { return apierrors.NewForbidden(schema.GroupResource{}, "", fmt.Errorf("lower_case_table_names cannot be changed in MySQL8.0+")) } diff --git a/build/mysql/Dockerfile b/build/mysql/Dockerfile index 766b4c45a..15c635c00 100644 --- a/build/mysql/Dockerfile +++ b/build/mysql/Dockerfile @@ -6,7 +6,6 @@ COPY go.mod go.mod COPY go.sum go.sum # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer -RUN if [ $(cat /etc/timezone) = "Asia/Shanghai" ] ; then go env -w GOPROXY=https://goproxy.cn,direct; fi # go mod download RUN go mod download diff --git a/build/xenon/Dockerfile b/build/xenon/Dockerfile index bd69000d0..1abb73bca 100644 --- a/build/xenon/Dockerfile +++ b/build/xenon/Dockerfile @@ -5,7 +5,7 @@ FROM golang:1.16 as builder ARG XENON_BRANCH=master -RUN if [ $(cat /etc/timezone) = "Asia/Shanghai" ] ; then go env -w GOPROXY=https://goproxy.cn,direct; fi && go env -w GO111MODULE=off; +RUN go env -w GO111MODULE=off; RUN set -ex; \ mkdir -p /go/src/github.com/radondb; \ cd /go/src/github.com/radondb; \ diff --git a/charts/mysql-operator/crds/mysql.radondb.com_mysqlclusters.yaml b/charts/mysql-operator/crds/mysql.radondb.com_mysqlclusters.yaml index 88d891c56..d1c3c8e08 100644 --- a/charts/mysql-operator/crds/mysql.radondb.com_mysqlclusters.yaml +++ b/charts/mysql-operator/crds/mysql.radondb.com_mysqlclusters.yaml @@ -152,6 +152,10 @@ spec: default: radondb description: Name for new database to create. type: string + image: + default: percona/percona-server:5.7.34 + description: Specifies mysql image to use. + type: string initTokuDB: default: false description: InitTokuDB represents if install tokudb engine. diff --git a/config/crd/bases/mysql.radondb.com_mysqlclusters.yaml b/config/crd/bases/mysql.radondb.com_mysqlclusters.yaml index 88d891c56..d1c3c8e08 100644 --- a/config/crd/bases/mysql.radondb.com_mysqlclusters.yaml +++ b/config/crd/bases/mysql.radondb.com_mysqlclusters.yaml @@ -152,6 +152,10 @@ spec: default: radondb description: Name for new database to create. type: string + image: + default: percona/percona-server:5.7.34 + description: Specifies mysql image to use. + type: string initTokuDB: default: false description: InitTokuDB represents if install tokudb engine. diff --git a/config/samples/mysql_v1alpha1_mysqlcluster.yaml b/config/samples/mysql_v1alpha1_mysqlcluster.yaml index 3c2e2c92e..1e86f9c50 100644 --- a/config/samples/mysql_v1alpha1_mysqlcluster.yaml +++ b/config/samples/mysql_v1alpha1_mysqlcluster.yaml @@ -5,7 +5,6 @@ metadata: spec: replicas: 3 mysqlVersion: "5.7" - # the backupSecretName specify the secret file name which store S3 information, # if you want S3 backup or restore, please create backup_secret.yaml, uncomment below and fill secret name: # backupSecretName: @@ -18,6 +17,7 @@ spec: # such as nfsServerAddress: "10.233.55.172" # nfsServerAddress: mysqlOpts: + image: percona/percona-server:5.7.34 user: radondb_usr password: RadonDB@123 database: radondb diff --git a/config/samples/mysql_v1alpha1_mysqlcluster_backup_schedule_demo.yaml b/config/samples/mysql_v1alpha1_mysqlcluster_backup_schedule_demo.yaml index 880e998ec..0d6e8c188 100644 --- a/config/samples/mysql_v1alpha1_mysqlcluster_backup_schedule_demo.yaml +++ b/config/samples/mysql_v1alpha1_mysqlcluster_backup_schedule_demo.yaml @@ -5,7 +5,6 @@ metadata: spec: replicas: 3 mysqlVersion: "5.7" - # the backupSecretName specify the secret file name which store S3 information, # if you want S3 backup or restore, please create backup_secret.yaml, uncomment below and fill secret name: backupSecretName: sample-backup-secret @@ -14,6 +13,7 @@ spec: # restoreFrom: BackupSchedule: "0 50 * * * *" mysqlOpts: + image: percona/percona-server:5.7.34 rootPassword: "RadonDB@123" rootHost: localhost user: radondb_usr diff --git a/config/samples/mysql_v1alpha1_mysqlcluster_mysql8.yaml b/config/samples/mysql_v1alpha1_mysqlcluster_mysql8.yaml index f7344b31d..9279d83e0 100644 --- a/config/samples/mysql_v1alpha1_mysqlcluster_mysql8.yaml +++ b/config/samples/mysql_v1alpha1_mysqlcluster_mysql8.yaml @@ -5,7 +5,6 @@ metadata: spec: replicas: 3 mysqlVersion: "8.0" - # the backupSecretName specify the secret file name which store S3 information, # if you want S3 backup or restore, please create backup_secret.yaml, uncomment below and fill secret name: # backupSecretName: @@ -14,6 +13,7 @@ spec: # restoreFrom: mysqlOpts: + image: percona/percona-server:8.0.25 user: radondb_usr password: RadonDB@123 database: radondb diff --git a/config/samples/mysql_v1alpha1_mysqlcluster_podAntiAffinity.yaml b/config/samples/mysql_v1alpha1_mysqlcluster_podAntiAffinity.yaml index 34680d191..9b76dec16 100644 --- a/config/samples/mysql_v1alpha1_mysqlcluster_podAntiAffinity.yaml +++ b/config/samples/mysql_v1alpha1_mysqlcluster_podAntiAffinity.yaml @@ -5,7 +5,6 @@ metadata: spec: replicas: 3 mysqlVersion: "5.7" - # the backupSecretName specify the secret file name which store S3 information, # if you want S3 backup or restore, please create backup_secret.yaml, uncomment below and fill secret name: # backupSecretName: @@ -14,6 +13,7 @@ spec: # restoreFrom: mysqlOpts: + image: percona/percona-server:5.7.34 user: radondb_usr password: RadonDB@123 database: radondb diff --git a/docs/en-us/backup_and_restoration_s3.md b/docs/en-us/backup_and_restoration_s3.md index 6641d3b0c..c26761046 100644 --- a/docs/en-us/backup_and_restoration_s3.md +++ b/docs/en-us/backup_and_restoration_s3.md @@ -51,7 +51,6 @@ Configure the `backupSecretName` property in `mysql_v1alpha1_mysqlcluster.yaml`, ```yaml spec: replicas: 3 - mysqlVersion: "5.7" backupSecretName: sample-backup-secret ... ``` diff --git a/docs/en-us/backup_cron.md b/docs/en-us/backup_cron.md index a5b3448b2..1f113ebe9 100644 --- a/docs/en-us/backup_cron.md +++ b/docs/en-us/backup_cron.md @@ -13,7 +13,6 @@ The scheduled backup is currently supported for both S3 and NFS backups. You can ... spec: replicas: 3 - mysqlVersion: "5.7" backupSchedule: "0 0 0 * * *" # daily ... ``` diff --git a/docs/zh-cn/backup_and_restoration_s3.md b/docs/zh-cn/backup_and_restoration_s3.md index 2f3e43756..9d9bc3769 100644 --- a/docs/zh-cn/backup_and_restoration_s3.md +++ b/docs/zh-cn/backup_and_restoration_s3.md @@ -51,7 +51,6 @@ kubectl create -f config/samples/backup_secret.yaml ```yaml spec: replicas: 3 - mysqlVersion: "5.7" backupSecretName: sample-backup-secret ... ``` @@ -94,7 +93,6 @@ backup-sample sample_2022526155115 2022-05-26T15:51:15 S3 ... spec: replicas: 3 - mysqlVersion: "5.7" backupSecretName: sample-backup-secret restoreFrom: "sample_2022526155115" ... diff --git a/mysqlcluster/container/init_mysql.go b/mysqlcluster/container/init_mysql.go index 670071947..55d3bedfe 100644 --- a/mysqlcluster/container/init_mysql.go +++ b/mysqlcluster/container/init_mysql.go @@ -38,7 +38,7 @@ func (c *initMysql) getName() string { // getImage get the container image. func (c *initMysql) getImage() string { - img := utils.MysqlImageVersions[c.GetMySQLVersion()] + img := c.Spec.MysqlOpts.Image return img } diff --git a/mysqlcluster/container/init_mysql_test.go b/mysqlcluster/container/init_mysql_test.go index fbd2f2c1d..4c976d53b 100644 --- a/mysqlcluster/container/init_mysql_test.go +++ b/mysqlcluster/container/init_mysql_test.go @@ -41,10 +41,10 @@ var ( Requests: nil, }, }, - MysqlVersion: "5.7", MysqlOpts: mysqlv1alpha1.MysqlOpts{ RootHost: "localhost", InitTokuDB: false, + Image: "percona/percona-server:5.7.34", }, }, } diff --git a/mysqlcluster/container/init_sidecar_test.go b/mysqlcluster/container/init_sidecar_test.go index 21d08537c..dcc3926c9 100644 --- a/mysqlcluster/container/init_sidecar_test.go +++ b/mysqlcluster/container/init_sidecar_test.go @@ -54,9 +54,9 @@ var ( MetricsOpts: mysqlv1alpha1.MetricsOpts{ Enabled: false, }, - MysqlVersion: "5.7", MysqlOpts: mysqlv1alpha1.MysqlOpts{ InitTokuDB: false, + Image: "percona/percona-server:5.7.34", }, Persistence: mysqlv1alpha1.Persistence{ Enabled: false, diff --git a/mysqlcluster/container/mysql.go b/mysqlcluster/container/mysql.go index c1bc0af17..a89265961 100644 --- a/mysqlcluster/container/mysql.go +++ b/mysqlcluster/container/mysql.go @@ -40,7 +40,7 @@ func (c *mysql) getName() string { // getImage get the container image. func (c *mysql) getImage() string { - img := utils.MysqlImageVersions[c.GetMySQLVersion()] + img := c.Spec.MysqlOpts.Image return img } diff --git a/mysqlcluster/container/mysql_test.go b/mysqlcluster/container/mysql_test.go index 0b388456c..ce90f3c47 100644 --- a/mysqlcluster/container/mysql_test.go +++ b/mysqlcluster/container/mysql_test.go @@ -37,9 +37,9 @@ var ( Requests: nil, }, }, - MysqlVersion: "5.7", MysqlOpts: mysqlv1alpha1.MysqlOpts{ InitTokuDB: false, + Image: "percona/percona-server:5.7.34", }, }, } diff --git a/mysqlcluster/mysqlcluster.go b/mysqlcluster/mysqlcluster.go index b1d8bcf67..eef061975 100644 --- a/mysqlcluster/mysqlcluster.go +++ b/mysqlcluster/mysqlcluster.go @@ -17,7 +17,6 @@ limitations under the License. package mysqlcluster import ( - "errors" "fmt" "math" "os" @@ -74,7 +73,7 @@ func (c *MysqlCluster) Validate() error { } // MySQL8 nerver support TokuDB // https://www.percona.com/blog/2021/05/21/tokudb-support-changes-and-future-removal-from-percona-server-for-mysql-8-0/ - if c.Spec.MysqlVersion == "8.0" && c.Spec.MysqlOpts.InitTokuDB { + if strings.Contains(c.Spec.MysqlOpts.Image, "8.0") && c.Spec.MysqlOpts.InitTokuDB { c.log.Info("TokuDB is not supported in MySQL 8.0 any more, the value in Cluster.spec.mysqlOpts.initTokuDB should be set false") return nil } @@ -131,22 +130,11 @@ func (c *MysqlCluster) GetSelectorLabels() labels.Set { // GetMySQLVersion returns the MySQL server version. func (c *MysqlCluster) GetMySQLVersion() string { - var version string - // Lookup for an alias, this will solve MySQL tags: 5.7 --> 5.7.x - if v, ok := utils.MySQLTagsToSemVer[c.Spec.MysqlVersion]; ok { - version = v + if _, _, imageTag, err := utils.ParseImageName(c.Spec.MysqlOpts.Image); err == nil { + return imageTag } else { - errmsg := "Invalid mysql version option:" + c.Spec.MysqlVersion - c.log.Error(errors.New(errmsg), "currently we do not support mysql 5.6 or earlier version, default mysql version option should be 5.7 or 8.0") return utils.InvalidMySQLVersion } - - // Check if has specified image. - if _, ok := utils.MysqlImageVersions[version]; !ok { - version = utils.MySQLDefaultVersion - } - - return version } // CreatePeers create peers for xenon. diff --git a/mysqlcluster/mysqlcluster_test.go b/mysqlcluster/mysqlcluster_test.go index 77754e806..7ee386260 100644 --- a/mysqlcluster/mysqlcluster_test.go +++ b/mysqlcluster/mysqlcluster_test.go @@ -43,7 +43,9 @@ var ( Name: "sample", }, Spec: mysqlv1alpha1.MysqlClusterSpec{ - MysqlVersion: "5.7", + MysqlOpts: mysqlv1alpha1.MysqlOpts{ + Image: "percona/percona-server:5.7.35", + }, }, } testCluster = MysqlCluster{ @@ -139,7 +141,7 @@ func TestGetMySQLVersion(t *testing.T) { // Invalid, currently not support: 8.0 -> 0.0.0 { testMysqlCluster := mysqlCluster - testMysqlCluster.Spec.MysqlVersion = "8.0" + testMysqlCluster.Spec.MysqlOpts.Image = "percona/percona-server:8.0.25" testCase := MysqlCluster{ MysqlCluster: &testMysqlCluster, log: logf.Log.WithName("mysqlcluster"), @@ -150,18 +152,18 @@ func TestGetMySQLVersion(t *testing.T) { // MySQLTagsToSemVer 5.7 -> 5.7.34 { testMysqlCluster := mysqlCluster - testMysqlCluster.Spec.MysqlVersion = "5.7" + testMysqlCluster.Spec.MysqlOpts.Image = "percona/percona-server:5.7.35" testCase := MysqlCluster{ MysqlCluster: &testMysqlCluster, log: logf.Log.WithName("mysqlcluster"), } - want := "5.7.34" + want := "5.7.35" assert.Equal(t, want, testCase.GetMySQLVersion()) } // Invalid, not support MysqlImageVersions 5.7.34 -> 5.7.34 { testMysqlCluster := mysqlCluster - testMysqlCluster.Spec.MysqlVersion = "5.7.34" + testMysqlCluster.Spec.MysqlOpts.Image = "5.7.35" testCase := MysqlCluster{ MysqlCluster: &testMysqlCluster, log: logf.Log.WithName("mysqlcluster"), @@ -387,7 +389,6 @@ func TestEnsureVolumeClaimTemplates(t *testing.T) { Labels: nil, }, Spec: mysqlv1alpha1.MysqlClusterSpec{ - MysqlVersion: "5.7", Persistence: mysqlv1alpha1.Persistence{ AccessModes: nil, StorageClass: &storageClass, diff --git a/mysqlcluster/syncer/mysql_cm.go b/mysqlcluster/syncer/mysql_cm.go index 1b4930ec2..0b28573ad 100644 --- a/mysqlcluster/syncer/mysql_cm.go +++ b/mysqlcluster/syncer/mysql_cm.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "sort" + "strings" "github.com/go-ini/ini" "github.com/presslabs/controller-util/syncer" @@ -73,8 +74,13 @@ func buildMysqlConf(c *mysqlcluster.MysqlCluster) (string, error) { sec := cfg.Section("mysqld") c.EnsureMysqlConf() - - switch c.Spec.MysqlVersion { + mysqlVersion := "" + if strings.Contains(c.Spec.MysqlOpts.Image, "8.0") { + mysqlVersion = "8.0" + } else if strings.Contains(c.Spec.MysqlOpts.Image, "5.7") { + mysqlVersion = "5.7" + } + switch mysqlVersion { case "8.0": addKVConfigsToSection(sec, mysql80Configs) case "5.7": diff --git a/test/e2e/framework/cluster_util.go b/test/e2e/framework/cluster_util.go index 763cd6a9a..d49d6b35c 100644 --- a/test/e2e/framework/cluster_util.go +++ b/test/e2e/framework/cluster_util.go @@ -41,8 +41,7 @@ func newCluster(name, ns string, replicas int32) *apiv1alpha1.MysqlCluster { Namespace: ns, }, Spec: apiv1alpha1.MysqlClusterSpec{ - Replicas: &replicas, - MysqlVersion: TestContext.MysqlVersion, + Replicas: &replicas, PodPolicy: apiv1alpha1.PodPolicy{ SidecarImage: TestContext.SidecarImagePath, }, diff --git a/utils/common.go b/utils/common.go index 5715119b3..fbcfec0be 100644 --- a/utils/common.go +++ b/utils/common.go @@ -22,6 +22,7 @@ import ( "io" "io/ioutil" "os" + "path/filepath" "sort" "strconv" "strings" @@ -136,3 +137,16 @@ func UnmarshalJSON(in io.Reader, obj interface{}) error { } return nil } + +// Parase image prefix,image name,image tag. eg: percona/percona-server:5.7.35 -> percona,percona-server,5.7.35 +func ParseImageName(image string) (string, string, string, error) { + imagePrefix, imageString := filepath.Split(image) + imagePrefix = strings.TrimSuffix(imagePrefix, "/") + imageNameArry := strings.Split(imageString, ":") + if len(imageNameArry) <= 1 { + return "", "", "", fmt.Errorf("image name or tag is empty") + } + imageName := imageNameArry[0] + imageTag := imageNameArry[1] + return imagePrefix, imageName, imageTag, nil +} diff --git a/utils/constants.go b/utils/constants.go index 1add85912..cc15aceba 100644 --- a/utils/constants.go +++ b/utils/constants.go @@ -25,20 +25,6 @@ var ( // InvalidMySQLVersion is used for set invalid version that we do not support. InvalidMySQLVersion = "0.0.0" - // MySQLTagsToSemVer maps simple version to semver versions - MySQLTagsToSemVer = map[string]string{ - "5.7": "5.7.34", - "8.0": "8.0.25", - } - - // MysqlImageVersions is a map of supported mysql version and their image - MysqlImageVersions = map[string]string{ - "5.7.33": "percona/percona-server:5.7.33", - "5.7.34": "percona/percona-server:5.7.34", - "8.0.25": "percona/percona-server:8.0.25", - "0.0.0": "errimage", - } - // XenonHttpUrls saves the xenon http url and its corresponding request type. XenonHttpUrls = map[XenonHttpUrl]string{ RaftStatus: http.MethodGet, From 6b50990e13b9c0a2f7b3b6aaac92d64c168bf193 Mon Sep 17 00:00:00 2001 From: cris Date: Fri, 9 Sep 2022 09:57:54 +0800 Subject: [PATCH 2/2] webhook:add webhook for prevent update whe image and mysqlversion are conflict --- Dockerfile | 4 ++++ Dockerfile.sidecar | 5 ++++- Makefile | 9 +++++---- api/v1alpha1/mysqlcluster_webhook.go | 13 +++++++++++++ api/v1alpha1/webhook_suite_test.go | 29 ++++++++++++++++++++++++++++ build/mysql/Dockerfile | 4 ++++ build/xenon/Dockerfile | 4 ++++ mysqlcluster/mysqlcluster.go | 2 +- utils/constants.go | 6 ++++++ 9 files changed, 70 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index e33a9222d..75edacb6d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,10 @@ WORKDIR /workspace # Copy the Go Modules manifests COPY go.mod go.mod COPY go.sum go.sum +ARG GO_PROXY=off +RUN if [ "$GO_PROXY" = "on" ]; then \ + go env -w GOPROXY=https://goproxy.cn,direct; \ + fi # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer RUN go mod download diff --git a/Dockerfile.sidecar b/Dockerfile.sidecar index 46f541f18..aea09983c 100644 --- a/Dockerfile.sidecar +++ b/Dockerfile.sidecar @@ -8,7 +8,10 @@ WORKDIR /workspace # Copy the Go Modules manifests COPY go.mod go.mod COPY go.sum go.sum - +ARG GO_PROXY=off +RUN if [ "$GO_PROXY" = "on" ]; then \ + go env -w GOPROXY=https://goproxy.cn,direct; \ + fi # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer # go mod download diff --git a/Makefile b/Makefile index dc41dd3c0..467ad407c 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ IMG ?= $(IMGPREFIX)mysql-operator:latest SIDECAR57_IMG ?= $(IMGPREFIX)mysql57-sidecar:latest SIDECAR80_IMG ?= $(IMGPREFIX)mysql80-sidecar:latest XENON_IMG ?= $(IMGPREFIX)xenon:latest +GO_PORXY ?= off # Produce CRDs that work back to Kubernetes 1.11 (no version conversion) CRD_OPTIONS ?= "crd:trivialVersions=true,preserveUnknownFields=false" @@ -72,10 +73,10 @@ run: manifests generate fmt vet ## Run a controller from your host. go run ./cmd/manager/main.go docker-build: test ## Build docker image with the manager. - docker build -t ${IMG} . - docker build -f Dockerfile.sidecar -t ${SIDECAR57_IMG} . - docker build -f build/xenon/Dockerfile -t ${XENON_IMG} . - docker build --build-arg XTRABACKUP_PKG=percona-xtrabackup-80 -f Dockerfile.sidecar -t ${SIDECAR80_IMG} . + docker build --build-arg GO_PROXY=${GO_PORXY} -t ${IMG} . + docker build -f Dockerfile.sidecar --build-arg GO_PROXY=${GO_PORXY} -t ${SIDECAR57_IMG} . + docker build -f build/xenon/Dockerfile --build-arg GO_PROXY=${GO_PORXY} -t ${XENON_IMG} . + docker build --build-arg XTRABACKUP_PKG=percona-xtrabackup-80 --build-arg GO_PROXY=${GO_PORXY} -f Dockerfile.sidecar -t ${SIDECAR80_IMG} . docker-push: ## Push docker image with the manager. docker push ${IMG} docker push ${SIDECAR_IMG} diff --git a/api/v1alpha1/mysqlcluster_webhook.go b/api/v1alpha1/mysqlcluster_webhook.go index 315e486a0..207b12fc4 100644 --- a/api/v1alpha1/mysqlcluster_webhook.go +++ b/api/v1alpha1/mysqlcluster_webhook.go @@ -71,6 +71,9 @@ func (r *MysqlCluster) ValidateUpdate(old runtime.Object) error { if err := r.validateLowTableCase(oldCluster); err != nil { return err } + if err := r.validateMysqlVersionAndImage(); err != nil { + return err + } if err := r.validateNFSServerAddress(oldCluster); err != nil { return err } @@ -124,3 +127,13 @@ func (r *MysqlCluster) validateLowTableCase(oldCluster *MysqlCluster) error { } return nil } + +// Validate MysqlVersion and spec.MysqlOpts.image are conflict. +func (r *MysqlCluster) validateMysqlVersionAndImage() error { + if r.Spec.MysqlOpts.Image != "" && r.Spec.MysqlVersion != "" { + if !strings.Contains(r.Spec.MysqlOpts.Image, r.Spec.MysqlVersion) { + return apierrors.NewForbidden(schema.GroupResource{}, "", fmt.Errorf("spec.MysqlOpts.Image and spec.MysqlVersion are conflict")) + } + } + return nil +} diff --git a/api/v1alpha1/webhook_suite_test.go b/api/v1alpha1/webhook_suite_test.go index f2c07b38d..ae7994a52 100644 --- a/api/v1alpha1/webhook_suite_test.go +++ b/api/v1alpha1/webhook_suite_test.go @@ -27,6 +27,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" admissionv1beta1 "k8s.io/api/admission/v1beta1" //+kubebuilder:scaffold:imports @@ -126,3 +127,31 @@ var _ = AfterSuite(func() { err := testEnv.Stop() Expect(err).NotTo(HaveOccurred()) }) + +// test validateMysqlVersionAndImage for webhook +func TestValidateUpdate(t *testing.T) { + { + mysqlcluster := &MysqlCluster{ + Spec: MysqlClusterSpec{ + MysqlVersion: "8.0", + MysqlOpts: MysqlOpts{ + Image: "percona/percona-server:5.7.34", + }, + }, + } + err := mysqlcluster.validateMysqlVersionAndImage() + assert.Error(t, err) + } + { + mysqlcluster := &MysqlCluster{ + Spec: MysqlClusterSpec{ + MysqlVersion: "8.0", + MysqlOpts: MysqlOpts{ + Image: "percona/percona-server:8.0.25", + }, + }, + } + err := mysqlcluster.validateMysqlVersionAndImage() + assert.NoError(t, err) + } +} diff --git a/build/mysql/Dockerfile b/build/mysql/Dockerfile index 20a52d1c0..8b2626207 100644 --- a/build/mysql/Dockerfile +++ b/build/mysql/Dockerfile @@ -4,6 +4,10 @@ WORKDIR / # Copy the Go Modules manifests COPY go.mod go.mod COPY go.sum go.sum +ARG GO_PROXY=off +RUN if [ "$GO_PROXY" = "on" ]; then \ + go env -w GOPROXY=https://goproxy.cn,direct; \ + fi # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer # go mod download diff --git a/build/xenon/Dockerfile b/build/xenon/Dockerfile index d0a8f5696..ba713fce8 100644 --- a/build/xenon/Dockerfile +++ b/build/xenon/Dockerfile @@ -18,6 +18,10 @@ COPY cmd/xenon/main.go cmd/xenon/main.go COPY utils/ utils/ COPY go.mod go.mod COPY go.sum go.sum +ARG GO_PROXY=off +RUN if [ "$GO_PROXY" = "on" ]; then \ + go env -w GOPROXY=https://goproxy.cn,direct; \ + fi RUN go env -w GO111MODULE=on && go mod download # Build RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o xenonchecker cmd/xenon/main.go diff --git a/mysqlcluster/mysqlcluster.go b/mysqlcluster/mysqlcluster.go index 6bd25fdc6..1afc7cbe0 100644 --- a/mysqlcluster/mysqlcluster.go +++ b/mysqlcluster/mysqlcluster.go @@ -128,7 +128,7 @@ func (c *MysqlCluster) GetSelectorLabels() labels.Set { } } -// GetMySQLVersion returns the MySQL server version. If MySQLVersion is set, then return the coreect verison. +// GetMySQLVersion returns the MySQL server version. If MySQLVersion is set, then validate the coreect verison. func (c *MysqlCluster) GetMySQLVersion() string { if _, _, imageTag, err := utils.ParseImageName(c.Spec.MysqlOpts.Image); err == nil { return imageTag diff --git a/utils/constants.go b/utils/constants.go index 8247ab408..8cab16bf7 100644 --- a/utils/constants.go +++ b/utils/constants.go @@ -199,3 +199,9 @@ type JsonResult struct { BackupName string `json:"backupName"` Date string `json:"date"` } + +// MySQLDefaultVersionMap is a map of supported mysql version and their image +var MySQLDefaultVersionMap = map[string]string{ + "5.7": "percona/percona-server:5.7.34", + "8.0": "percona/percona-server:8.0.25", +}