diff --git a/api/v1alpha1/mysqlcluster_types.go b/api/v1alpha1/mysqlcluster_types.go index dd6e3611..f77c1d10 100644 --- a/api/v1alpha1/mysqlcluster_types.go +++ b/api/v1alpha1/mysqlcluster_types.go @@ -227,6 +227,11 @@ type MysqlOpts struct { // +kubebuilder:validation:Minimum=0 // +optional MaxLagSeconds int `json:"maxLagTime,omitempty"` + + // LogfilePVC represents the pvc which save the mysql error log. + // Log file to pvc + // +optional + LogfilePVC *LogPVC `json:"logfilePVC,omitempty"` } // XenonOpts defines the options of xenon container. @@ -317,11 +322,6 @@ type PodPolicy struct { // +optional // +kubebuilder:default:=false AuditLogTail bool `json:"auditLogTail,omitempty"` - - // ErrorLogTail represents if tail the mysql error log. - // +optional - // +kubebuilder:default:=false - ErrorLogTail bool `json:"errorLogTail,omitempty"` } // Persistence is the desired spec for storing mysql data. Only one of its @@ -349,6 +349,27 @@ type Persistence struct { Size string `json:"size,omitempty"` } +// Persistence is the desired spec for storing mysql data. Only one of its +// members may be specified. +type LogPVC struct { + + // AccessModes contains the desired access modes the volume should have. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + // +optional + // +kubebuilder:default:={"ReadWriteOnce"} + AccessModes []corev1.PersistentVolumeAccessMode `json:"accessModes,omitempty"` + + // Name of the StorageClass required by the claim. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + // +optional + StorageClass *string `json:"storageClass,omitempty"` + + // Size of persistent volume claim. + // +optional + // +kubebuilder:default:="10Gi" + Size string `json:"size,omitempty"` +} + // bothS3NFS opt type BothS3NFSOpt struct { // NFS schedule. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 0fbc2bae..c9134a99 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -174,6 +174,31 @@ func (in *ClusterCondition) DeepCopy() *ClusterCondition { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LogPVC) DeepCopyInto(out *LogPVC) { + *out = *in + if in.AccessModes != nil { + in, out := &in.AccessModes, &out.AccessModes + *out = make([]v1.PersistentVolumeAccessMode, len(*in)) + copy(*out, *in) + } + if in.StorageClass != nil { + in, out := &in.StorageClass, &out.StorageClass + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogPVC. +func (in *LogPVC) DeepCopy() *LogPVC { + if in == nil { + return nil + } + out := new(LogPVC) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MetricsOpts) DeepCopyInto(out *MetricsOpts) { *out = *in @@ -390,6 +415,11 @@ func (in *MysqlOpts) DeepCopyInto(out *MysqlOpts) { } } in.Resources.DeepCopyInto(&out.Resources) + if in.LogfilePVC != nil { + in, out := &in.LogfilePVC, &out.LogfilePVC + *out = new(LogPVC) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MysqlOpts. diff --git a/api/v1beta1/mysqlcluster_conversion.go b/api/v1beta1/mysqlcluster_conversion.go index c04950df..27b21006 100644 --- a/api/v1beta1/mysqlcluster_conversion.go +++ b/api/v1beta1/mysqlcluster_conversion.go @@ -80,7 +80,17 @@ func Convert_v1alpha1_MysqlClusterSpec_To_v1beta1_MysqlClusterSpec(in *v1alpha1. out.Backup.Resources = in.PodPolicy.ExtraResources out.Log.SlowLogTail = in.PodPolicy.SlowLogTail out.Log.AuditLogTail = in.PodPolicy.AuditLogTail - out.Log.ErrorLogTail = in.PodPolicy.ErrorLogTail + if in.MysqlOpts.LogfilePVC != nil { + out.Log.LogfilePVC = &corev1.PersistentVolumeClaimSpec{} + out.Log.LogfilePVC.AccessModes = in.MysqlOpts.LogfilePVC.AccessModes + out.Log.LogfilePVC.Resources.Requests = map[corev1.ResourceName]resource.Quantity{ + corev1.ResourceStorage: resource.MustParse(in.MysqlOpts.LogfilePVC.Size), + } + out.Log.LogfilePVC.StorageClassName = in.MysqlOpts.LogfilePVC.StorageClass + } else { + out.Log.LogfilePVC = nil + } + out.Tolerations = in.PodPolicy.Tolerations out.PriorityClassName = in.PodPolicy.PriorityClassName out.Log.BusyboxImage = in.PodPolicy.BusyboxImage @@ -156,7 +166,17 @@ func Convert_v1beta1_MysqlClusterSpec_To_v1alpha1_MysqlClusterSpec(in *MysqlClus out.MysqlOpts.Image = in.Image out.PodPolicy.SlowLogTail = in.Log.SlowLogTail out.PodPolicy.AuditLogTail = in.Log.AuditLogTail - out.PodPolicy.ErrorLogTail = in.Log.ErrorLogTail + //out.MysqlOpts.LogfilePVC = (*v1alpha1.LogPVC)(in.Log.LogfilePVC) + if in.Log.LogfilePVC != nil { + out.MysqlOpts.LogfilePVC = &v1alpha1.LogPVC{} + out.MysqlOpts.LogfilePVC.StorageClass = in.Log.LogfilePVC.StorageClassName + out.MysqlOpts.LogfilePVC.Size = FormatQuantity(in.Log.LogfilePVC.Resources.Requests[corev1.ResourceStorage]) + out.MysqlOpts.LogfilePVC.AccessModes = in.Log.LogfilePVC.AccessModes + } else { + out.MysqlOpts.LogfilePVC = nil + } + + out.XenonOpts = v1alpha1.XenonOpts(in.Xenon) out.PodPolicy.BusyboxImage = in.Log.BusyboxImage out.MetricsOpts.Enabled = in.Monitoring.Exporter.Enabled out.PodPolicy.ImagePullPolicy = in.ImagePullPolicy diff --git a/api/v1beta1/mysqlcluster_types.go b/api/v1beta1/mysqlcluster_types.go index 013d7bca..780cd353 100644 --- a/api/v1beta1/mysqlcluster_types.go +++ b/api/v1beta1/mysqlcluster_types.go @@ -490,11 +490,10 @@ type LogOpts struct { // +kubebuilder:default:=false AuditLogTail bool `json:"auditLogTail,omitempty"` - // ErrorLogTail represents if tail the mysql error log. + // logPvc represents pvc which save the mysql error log. + // Log file to pvc // +optional - // +kubebuilder:default:=false - ErrorLogTail bool `json:"errorLogTail,omitempty"` - + LogfilePVC *corev1.PersistentVolumeClaimSpec `json:"logfilePVC,omitempty"` //Log container resources of a MySQL container. Resources corev1.ResourceRequirements `json:"resources,omitempty"` } diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 1fabd944..887cec95 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -279,6 +279,11 @@ func (in *ExporterSpec) DeepCopy() *ExporterSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LogOpts) DeepCopyInto(out *LogOpts) { *out = *in + if in.LogfilePVC != nil { + in, out := &in.LogfilePVC, &out.LogfilePVC + *out = new(v1.PersistentVolumeClaimSpec) + (*in).DeepCopyInto(*out) + } in.Resources.DeepCopyInto(&out.Resources) } diff --git a/charts/mysql-operator/templates/mysql.radondb.com_mysqlclusters.yaml b/charts/mysql-operator/templates/mysql.radondb.com_mysqlclusters.yaml index ed00f3e5..1d1cfa37 100644 --- a/charts/mysql-operator/templates/mysql.radondb.com_mysqlclusters.yaml +++ b/charts/mysql-operator/templates/mysql.radondb.com_mysqlclusters.yaml @@ -196,6 +196,27 @@ spec: default: false description: InitTokuDB represents if install tokudb engine. type: boolean + logfilePVC: + description: LogfilePVC represents the pvc which save the mysql + error log. Log file to pvc + properties: + accessModes: + default: + - ReadWriteOnce + description: 'AccessModes contains the desired access modes + the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + size: + default: 10Gi + description: Size of persistent volume claim. + type: string + storageClass: + description: 'Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + type: object maxLagTime: default: 30 description: MaxLagSeconds configures the readiness probe of mysqld @@ -1216,10 +1237,6 @@ spec: default: busybox:1.32 description: The busybox image. type: string - errorLogTail: - default: false - description: ErrorLogTail represents if tail the mysql error log. - type: boolean extraResources: default: requests: @@ -3636,15 +3653,176 @@ spec: default: false description: AuditLogTail represents if tail the mysql audit log. type: boolean - errorLogTail: - default: false - description: ErrorLogTail represents if tail the mysql error log. - type: boolean image: default: busybox:1.32 description: To specify the image that will be used for log container. The busybox image. type: string + logfilePVC: + description: logPvc represents pvc which save the mysql error + log. Log file to pvc + properties: + accessModes: + description: 'AccessModes contains the desired access modes + the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'This field can be used to specify either: * + An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) If the provisioner + or an external controller can support the specified data + source, it will create a new volume based on the contents + of the specified data source. If the AnyVolumeDataSource + feature gate is enabled, this field will always have the + same contents as the DataSourceRef field.' + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + dataSourceRef: + description: 'Specifies the object from which to populate + the volume with data, if a non-empty volume is desired. + This may be any local object from a non-empty API group + (non core object) or a PersistentVolumeClaim object. When + this field is specified, volume binding will only succeed + if the type of the specified object matches some installed + volume populator or dynamic provisioner. This field will + replace the functionality of the DataSource field and as + such if both fields are non-empty, they must have the same + value. For backwards compatibility, both fields (DataSource + and DataSourceRef) will be set to the same value automatically + if one of them is empty and the other is non-empty. There + are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, + DataSourceRef allows any non-core object, as well as PersistentVolumeClaim + objects. * While DataSource ignores disallowed values (dropping + them), DataSourceRef preserves all values, and generates + an error if a disallowed value is specified. (Alpha) Using + this field requires the AnyVolumeDataSource feature gate + to be enabled.' + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + resources: + description: 'Resources represents the minimum resources the + volume should have. If RecoverVolumeExpansionFailure feature + is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher + than capacity recorded in the status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of + compute resources required. If Requests is omitted for + a container, it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: A label query over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is + "key", the operator is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + storageClassName: + description: 'Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of volume is required + by the claim. Value of Filesystem is implied when not included + in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference to the PersistentVolume + backing this claim. + type: string + type: object resources: description: Log container resources of a MySQL container. properties: diff --git a/config/crd/bases/mysql.radondb.com_mysqlclusters.yaml b/config/crd/bases/mysql.radondb.com_mysqlclusters.yaml index 198704c9..f5e18fcc 100644 --- a/config/crd/bases/mysql.radondb.com_mysqlclusters.yaml +++ b/config/crd/bases/mysql.radondb.com_mysqlclusters.yaml @@ -178,6 +178,27 @@ spec: default: false description: InitTokuDB represents if install tokudb engine. type: boolean + logfilePVC: + description: LogfilePVC represents the pvc which save the mysql + error log. Log file to pvc + properties: + accessModes: + default: + - ReadWriteOnce + description: 'AccessModes contains the desired access modes + the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + size: + default: 10Gi + description: Size of persistent volume claim. + type: string + storageClass: + description: 'Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + type: object maxLagTime: default: 30 description: MaxLagSeconds configures the readiness probe of mysqld @@ -1198,10 +1219,6 @@ spec: default: busybox:1.32 description: The busybox image. type: string - errorLogTail: - default: false - description: ErrorLogTail represents if tail the mysql error log. - type: boolean extraResources: default: requests: @@ -3618,15 +3635,176 @@ spec: default: false description: AuditLogTail represents if tail the mysql audit log. type: boolean - errorLogTail: - default: false - description: ErrorLogTail represents if tail the mysql error log. - type: boolean image: default: busybox:1.32 description: To specify the image that will be used for log container. The busybox image. type: string + logfilePVC: + description: logPvc represents pvc which save the mysql error + log. Log file to pvc + properties: + accessModes: + description: 'AccessModes contains the desired access modes + the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'This field can be used to specify either: * + An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) If the provisioner + or an external controller can support the specified data + source, it will create a new volume based on the contents + of the specified data source. If the AnyVolumeDataSource + feature gate is enabled, this field will always have the + same contents as the DataSourceRef field.' + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + dataSourceRef: + description: 'Specifies the object from which to populate + the volume with data, if a non-empty volume is desired. + This may be any local object from a non-empty API group + (non core object) or a PersistentVolumeClaim object. When + this field is specified, volume binding will only succeed + if the type of the specified object matches some installed + volume populator or dynamic provisioner. This field will + replace the functionality of the DataSource field and as + such if both fields are non-empty, they must have the same + value. For backwards compatibility, both fields (DataSource + and DataSourceRef) will be set to the same value automatically + if one of them is empty and the other is non-empty. There + are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, + DataSourceRef allows any non-core object, as well as PersistentVolumeClaim + objects. * While DataSource ignores disallowed values (dropping + them), DataSourceRef preserves all values, and generates + an error if a disallowed value is specified. (Alpha) Using + this field requires the AnyVolumeDataSource feature gate + to be enabled.' + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + resources: + description: 'Resources represents the minimum resources the + volume should have. If RecoverVolumeExpansionFailure feature + is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher + than capacity recorded in the status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of + compute resources required. If Requests is omitted for + a container, it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: A label query over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is + "key", the operator is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + storageClassName: + description: 'Name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of volume is required + by the claim. Value of Filesystem is implied when not included + in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference to the PersistentVolume + backing this claim. + type: string + type: object resources: description: Log container resources of a MySQL container. properties: diff --git a/mysqlcluster/mysqlcluster.go b/mysqlcluster/mysqlcluster.go index 2f707eb9..fe650bdc 100644 --- a/mysqlcluster/mysqlcluster.go +++ b/mysqlcluster/mysqlcluster.go @@ -182,7 +182,16 @@ func (c *MysqlCluster) EnsureVolumes() []corev1.Volume { }, ) } - + if c.Spec.MysqlOpts.LogfilePVC == nil { + volumes = append(volumes, + corev1.Volume{ + Name: utils.LogsVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + ) + } volumes = append(volumes, corev1.Volume{ Name: utils.MysqlConfVolumeName, @@ -190,12 +199,6 @@ func (c *MysqlCluster) EnsureVolumes() []corev1.Volume { EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }, - corev1.Volume{ - Name: utils.LogsVolumeName, - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, - }, corev1.Volume{ Name: utils.MysqlCMVolumeName, VolumeSource: corev1.VolumeSource{ @@ -321,38 +324,69 @@ func (c *MysqlCluster) EnsureVolumes() []corev1.Volume { // EnsureVolumeClaimTemplates ensure the volume claim templates. func (c *MysqlCluster) EnsureVolumeClaimTemplates(schema *runtime.Scheme) ([]corev1.PersistentVolumeClaim, error) { - if !c.Spec.Persistence.Enabled { + if !c.Spec.Persistence.Enabled && c.Spec.MysqlOpts.LogfilePVC == nil { return nil, nil } + res := []corev1.PersistentVolumeClaim{} + if c.Spec.Persistence.Enabled { + if c.Spec.Persistence.StorageClass != nil { + if *c.Spec.Persistence.StorageClass == "-" { + *c.Spec.Persistence.StorageClass = "" + } + } + + data := corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: utils.DataVolumeName, + Namespace: c.Namespace, + Labels: c.GetLabels(), + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: c.Spec.Persistence.AccessModes, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse(c.Spec.Persistence.Size), + }, + }, + StorageClassName: c.Spec.Persistence.StorageClass, + }, + } - if c.Spec.Persistence.StorageClass != nil { - if *c.Spec.Persistence.StorageClass == "-" { - *c.Spec.Persistence.StorageClass = "" + if err := controllerutil.SetControllerReference(c.MysqlCluster, &data, schema); err != nil { + return nil, fmt.Errorf("failed setting controller reference: %v", err) } + res = append(res, data) } + if c.Spec.MysqlOpts.LogfilePVC != nil { + if c.Spec.MysqlOpts.LogfilePVC.StorageClass != nil { + if *c.Spec.MysqlOpts.LogfilePVC.StorageClass == "-" { + *c.Spec.MysqlOpts.LogfilePVC.StorageClass = "" + } + } - data := corev1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ - Name: utils.DataVolumeName, - Namespace: c.Namespace, - Labels: c.GetLabels(), - }, - Spec: corev1.PersistentVolumeClaimSpec{ - AccessModes: c.Spec.Persistence.AccessModes, - Resources: corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceStorage: resource.MustParse(c.Spec.Persistence.Size), + logdata := corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: utils.LogsVolumeName, + Namespace: c.Namespace, + Labels: c.GetLabels(), + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: c.Spec.Persistence.AccessModes, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse(c.Spec.Persistence.Size), + }, }, + StorageClassName: c.Spec.Persistence.StorageClass, }, - StorageClassName: c.Spec.Persistence.StorageClass, - }, - } + } - if err := controllerutil.SetControllerReference(c.MysqlCluster, &data, schema); err != nil { - return nil, fmt.Errorf("failed setting controller reference: %v", err) + if err := controllerutil.SetControllerReference(c.MysqlCluster, &logdata, schema); err != nil { + return nil, fmt.Errorf("failed setting controller reference: %v", err) + } + res = append(res, logdata) } - - return []corev1.PersistentVolumeClaim{data}, nil + return res, nil } // GetNameForResource returns the name of a resource from above @@ -461,8 +495,11 @@ func (c *MysqlCluster) EnsureMysqlConf() { } } - if c.Spec.PodPolicy.ErrorLogTail { - c.Spec.MysqlOpts.MysqlConf["log-error"] = utils.LogsVolumeMountPath + "/mysql-error.log" + + if _, ok := c.Spec.MysqlOpts.MysqlConf["log_error"]; !ok { + if c.Spec.MysqlOpts.LogfilePVC != nil { //has been set logpvc, change log error to file. + c.Spec.MysqlOpts.MysqlConf["log-error"] = utils.LogsVolumeMountPath + "/mysql-error.log" + } } } diff --git a/mysqlcluster/mysqlcluster_test.go b/mysqlcluster/mysqlcluster_test.go index 1572e973..e9a1a1cc 100644 --- a/mysqlcluster/mysqlcluster_test.go +++ b/mysqlcluster/mysqlcluster_test.go @@ -257,17 +257,18 @@ func TestGetPodHostName(t *testing.T) { func TestEnsureVolumes(t *testing.T) { volume := []corev1.Volume{ { - Name: utils.MysqlConfVolumeName, + Name: utils.LogsVolumeName, VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }, { - Name: utils.LogsVolumeName, + Name: utils.MysqlConfVolumeName, VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }, + { Name: utils.MysqlCMVolumeName, VolumeSource: corev1.VolumeSource{ diff --git a/mysqlcluster/syncer/statefulset.go b/mysqlcluster/syncer/statefulset.go index d32bd032..cbb8e0e8 100644 --- a/mysqlcluster/syncer/statefulset.go +++ b/mysqlcluster/syncer/statefulset.go @@ -432,7 +432,7 @@ func (s *StatefulSetSyncer) mutate() error { } s.sfs.Spec.Template.Spec.Tolerations = s.Spec.PodPolicy.Tolerations - if s.Spec.Persistence.Enabled { + if s.Spec.Persistence.Enabled || s.Spec.MysqlOpts.LogfilePVC != nil { if s.sfs.Spec.VolumeClaimTemplates, err = s.EnsureVolumeClaimTemplates(s.cli.Scheme()); err != nil { return err } @@ -471,10 +471,9 @@ func (s *StatefulSetSyncer) ensurePodSpec() corev1.PodSpec { if s.Spec.PodPolicy.AuditLogTail { containers = append(containers, container.EnsureContainer(utils.ContainerAuditLogName, s.MysqlCluster)) } - if s.Spec.PodPolicy.ErrorLogTail { + if s.Spec.MysqlOpts.LogfilePVC != nil { // 1.create errorLog containers = append(containers, container.EnsureContainer(utils.ContainerErrorLogName, s.MysqlCluster)) - } return corev1.PodSpec{ InitContainers: initContainers,