From d85cece6ec577694647bd8dc5c43c045d17d60f1 Mon Sep 17 00:00:00 2001 From: zhyass <34016424+zhyass@users.noreply.github.com> Date: Fri, 23 Jul 2021 11:02:23 +0800 Subject: [PATCH] *: add pattern validation for cluster --- api/v1alpha1/cluster_types.go | 12 ++++++++++-- .../crds/mysql.radondb.com_clusters.yaml | 17 ++++++++++++++--- cluster/cluster.go | 8 ++++++++ .../crd/bases/mysql.radondb.com_clusters.yaml | 17 ++++++++++++++--- controllers/cluster_controller.go | 4 ++++ internal/sql_runner.go | 12 +++--------- sidecar/init.go | 2 +- utils/common.go | 9 +++++++++ 8 files changed, 63 insertions(+), 18 deletions(-) diff --git a/api/v1alpha1/cluster_types.go b/api/v1alpha1/cluster_types.go index 63abbe433..0f8fda452 100644 --- a/api/v1alpha1/cluster_types.go +++ b/api/v1alpha1/cluster_types.go @@ -70,9 +70,12 @@ type ClusterSpec struct { // MysqlOpts defines the options of MySQL container. type MysqlOpts struct { - // Password for the root user. + // 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. + // Special characters are supported: @#$%^&*_+-=. // +optional // +kubebuilder:default:="" + // +kubebuilder:validation:Pattern="^$|^[A-Za-z0-9@#$%^&*_+\\-=]{8,32}$" RootPassword string `json:"rootPassword,omitempty"` // The root user's host. @@ -81,13 +84,18 @@ type MysqlOpts struct { RootHost string `json:"rootHost,omitempty"` // Username of new user to create. + // Only be a combination of letters, numbers or underlines. The length can not exceed 26 characters. // +optional // +kubebuilder:default:="qc_usr" + // +kubebuilder:validation:Pattern="^[A-Za-z0-9_]{2,26}$" User string `json:"user,omitempty"` - // Password for the new user. + // Password for the new user, must be 8~32 characters long. + // Only be a combination of uppercase letters, lowercase letters, numbers or special characters. + // Special characters are supported: @#$%^&*_+-=. // +optional // +kubebuilder:default:="Qing@123" + // +kubebuilder:validation:Pattern="^[A-Za-z0-9@#$%^&*_+\\-=]{8,32}$" Password string `json:"password,omitempty"` // Name for new database to create. diff --git a/charts/mysql-operator/crds/mysql.radondb.com_clusters.yaml b/charts/mysql-operator/crds/mysql.radondb.com_clusters.yaml index 36a3eff30..4fff576f9 100644 --- a/charts/mysql-operator/crds/mysql.radondb.com_clusters.yaml +++ b/charts/mysql-operator/crds/mysql.radondb.com_clusters.yaml @@ -139,7 +139,11 @@ spec: type: object password: default: Qing@123 - description: Password for the new user. + description: 'Password for the new user, must be 8~32 characters + long. Only be a combination of uppercase letters, lowercase + letters, numbers or special characters. Special characters are + supported: @#$%^&*_+-=.' + pattern: ^[A-Za-z0-9@#$%^&*_+\-=]{8,32}$ type: string resources: default: @@ -180,11 +184,18 @@ spec: type: string rootPassword: default: "" - description: Password for the root user. + description: '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. Special characters + are supported: @#$%^&*_+-=.' + pattern: ^$|^[A-Za-z0-9@#$%^&*_+\-=]{8,32}$ type: string user: default: qc_usr - description: Username of new user to create. + description: Username of new user to create. Only be a combination + of letters, numbers or underlines. The length can not exceed + 26 characters. + pattern: ^[A-Za-z0-9_]{2,26}$ type: string type: object mysqlVersion: diff --git a/cluster/cluster.go b/cluster/cluster.go index 08b30e8f3..432289029 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -59,6 +59,14 @@ func (c *Cluster) Unwrap() *apiv1alpha1.Cluster { return c.Cluster } +func (c *Cluster) Validate() error { + if utils.StringInArray(c.Spec.MysqlOpts.User, []string{"root", utils.ReplicationUser, utils.OperatorUser, utils.MetricsUser}) { + return fmt.Errorf("spec.mysqlOpts.user cannot be root|%s|%s|%s", utils.ReplicationUser, utils.OperatorUser, utils.MetricsUser) + } + + return nil +} + // GetLabels returns cluster labels func (c *Cluster) GetLabels() labels.Set { instance := c.Name diff --git a/config/crd/bases/mysql.radondb.com_clusters.yaml b/config/crd/bases/mysql.radondb.com_clusters.yaml index 36a3eff30..4fff576f9 100644 --- a/config/crd/bases/mysql.radondb.com_clusters.yaml +++ b/config/crd/bases/mysql.radondb.com_clusters.yaml @@ -139,7 +139,11 @@ spec: type: object password: default: Qing@123 - description: Password for the new user. + description: 'Password for the new user, must be 8~32 characters + long. Only be a combination of uppercase letters, lowercase + letters, numbers or special characters. Special characters are + supported: @#$%^&*_+-=.' + pattern: ^[A-Za-z0-9@#$%^&*_+\-=]{8,32}$ type: string resources: default: @@ -180,11 +184,18 @@ spec: type: string rootPassword: default: "" - description: Password for the root user. + description: '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. Special characters + are supported: @#$%^&*_+-=.' + pattern: ^$|^[A-Za-z0-9@#$%^&*_+\-=]{8,32}$ type: string user: default: qc_usr - description: Username of new user to create. + description: Username of new user to create. Only be a combination + of letters, numbers or underlines. The length can not exceed + 26 characters. + pattern: ^[A-Za-z0-9_]{2,26}$ type: string type: object mysqlVersion: diff --git a/controllers/cluster_controller.go b/controllers/cluster_controller.go index 8591569a0..6a139012a 100644 --- a/controllers/cluster_controller.go +++ b/controllers/cluster_controller.go @@ -77,6 +77,10 @@ func (r *ClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct return ctrl.Result{}, err } + if err = instance.Validate(); err != nil { + return ctrl.Result{}, err + } + status := *instance.Status.DeepCopy() defer func() { if !reflect.DeepEqual(status, instance.Status) { diff --git a/internal/sql_runner.go b/internal/sql_runner.go index ac595e306..a51e425ec 100644 --- a/internal/sql_runner.go +++ b/internal/sql_runner.go @@ -19,13 +19,14 @@ package internal import ( "database/sql" "fmt" - "sort" "strconv" "strings" "time" _ "github.com/go-sql-driver/mysql" corev1 "k8s.io/api/core/v1" + + "github.com/radondb/radondb-mysql-kubernetes/utils" ) var ( @@ -118,7 +119,7 @@ func (s *SQLRunner) checkSlaveStatus() (isLagged, isReplicating corev1.Condition lastSQLError := columnValue(scanArgs, cols, "Last_SQL_Error") secondsBehindMaster := columnValue(scanArgs, cols, "Seconds_Behind_Master") - if stringInArray(slaveIOState, errorConnectionStates) { + if utils.StringInArray(slaveIOState, errorConnectionStates) { return isLagged, corev1.ConditionFalse, fmt.Errorf("Slave_IO_State: %s", slaveIOState) } @@ -227,10 +228,3 @@ func columnValue(scanArgs []interface{}, slaveCols []string, colName string) str return string(*scanArgs[columnIndex].(*sql.RawBytes)) } - -// stringInArray check whether the str is in the strArray. -func stringInArray(str string, strArray []string) bool { - sort.Strings(strArray) - index := sort.SearchStrings(strArray, str) - return index < len(strArray) && strArray[index] == str -} diff --git a/sidecar/init.go b/sidecar/init.go index eb414af10..5b2ca8524 100644 --- a/sidecar/init.go +++ b/sidecar/init.go @@ -88,7 +88,7 @@ func runInitCommand(cfg *Config) error { return fmt.Errorf("failed to save client.conf: %s", err) } - if err = os.Mkdir(extraConfPath, os.FileMode(0755)); err != nil { + if err = os.Mkdir(extraConfPath, os.FileMode(0644)); err != nil { if !os.IsExist(err) { return fmt.Errorf("error mkdir %s: %s", extraConfPath, err) } diff --git a/utils/common.go b/utils/common.go index b6a868d85..7f9b15071 100644 --- a/utils/common.go +++ b/utils/common.go @@ -16,6 +16,8 @@ limitations under the License. package utils +import "sort" + // Min returns the smallest int64 that was passed in the arguments. func Min(a, b uint64) uint64 { if a < b { @@ -31,3 +33,10 @@ func Max(a, b uint64) uint64 { } return b } + +// StringInArray check whether the str is in the strArray. +func StringInArray(str string, strArray []string) bool { + sort.Strings(strArray) + index := sort.SearchStrings(strArray, str) + return index < len(strArray) && strArray[index] == str +}