From e0bd32ab32f8d99e855cd161a952a1a8427fd1c1 Mon Sep 17 00:00:00 2001 From: wangyelei Date: Wed, 25 Sep 2024 10:04:38 +0800 Subject: [PATCH] chore: remove the deprecated apis from the opsRequest (#8191) --- .../v1alpha1/opsdefinition_types.go | 24 - .../v1alpha1/opsrequest_conditions.go | 8 +- .../v1alpha1/opsrequest_conditions_test.go | 9 +- apis/operations/v1alpha1/opsrequest_types.go | 75 +-- .../v1alpha1/opsrequest_validation.go | 17 +- .../v1alpha1/zz_generated.deepcopy.go | 78 --- .../operations.kubeblocks.io_opsrequests.yaml | 519 +----------------- .../operations/opsrequest_controller.go | 5 - .../operations/opsrequest_controller_test.go | 57 +- .../operations.kubeblocks.io_opsrequests.yaml | 519 +----------------- pkg/dataprotection/backup/scheduler.go | 24 +- pkg/operations/horizontal_scaling.go | 21 +- pkg/operations/horizontal_scaling_test.go | 84 ++- pkg/operations/ops_progress_util_test.go | 12 +- pkg/operations/ops_util_test.go | 24 +- pkg/operations/reconfigure.go | 13 - pkg/operations/reconfigure_test.go | 60 +- pkg/operations/upgrade.go | 46 +- 18 files changed, 180 insertions(+), 1415 deletions(-) diff --git a/apis/operations/v1alpha1/opsdefinition_types.go b/apis/operations/v1alpha1/opsdefinition_types.go index 1aa626777fa..8854921e008 100644 --- a/apis/operations/v1alpha1/opsdefinition_types.go +++ b/apis/operations/v1alpha1/opsdefinition_types.go @@ -77,30 +77,6 @@ type OpsDefinitionSpec struct { type PreCondition struct { // Specifies the conditions that must be met for the operation to execute. Rule *Rule `json:"rule,omitempty"` - - // Represents a job that will be run to execute the PreCondition. - // The operation will only be executed if the job is successful. - // +optional - // Exec *PreConditionExec `json:"exec,omitempty"` -} - -// PreConditionExec is deprecated. -type PreConditionExec struct { - // Specifies the name of the image used for execution. - // +kubebuilder:validation:Required - Image string `json:"image"` - - // Specifies a list of environment variables to be set in the container. - // +optional - Env []corev1.EnvVar `json:"env,omitempty"` - - // Specifies the command to be executed in the container. - // +optional - Command []string `json:"command,omitempty"` - - // Specifies the arguments to be passed to the command in the container. - // +optional - Args []string `json:"args,omitempty"` } type Rule struct { diff --git a/apis/operations/v1alpha1/opsrequest_conditions.go b/apis/operations/v1alpha1/opsrequest_conditions.go index d77f1c6b02d..9704a7b1622 100644 --- a/apis/operations/v1alpha1/opsrequest_conditions.go +++ b/apis/operations/v1alpha1/opsrequest_conditions.go @@ -18,6 +18,7 @@ package v1alpha1 import ( "fmt" + "strings" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -319,10 +320,11 @@ func NewReconfigureRunningCondition(ops *OpsRequest, conditionType string, confi } func getComponentName(request OpsRequestSpec) string { - if request.Reconfigure != nil { - return request.Reconfigure.ComponentName + var compNames []string + for _, v := range request.Reconfigures { + compNames = append(compNames, v.ComponentName) } - return "" + return strings.Join(compNames, ",") } // NewReconfigureFailedCondition creates a condition for the failed reconfigure. diff --git a/apis/operations/v1alpha1/opsrequest_conditions_test.go b/apis/operations/v1alpha1/opsrequest_conditions_test.go index 374b8e8657e..5a969be74bb 100644 --- a/apis/operations/v1alpha1/opsrequest_conditions_test.go +++ b/apis/operations/v1alpha1/opsrequest_conditions_test.go @@ -51,9 +51,12 @@ func TestNewAllCondition(t *testing.T) { NewReconfigureFailedCondition(opsRequest, errors.New("reconfigure opsRequest failed")) NewBackupCondition(opsRequest) - opsRequest.Spec.Reconfigure = &Reconfigure{ - ComponentOps: ComponentOps{ - ComponentName: "testReconfiguring", + opsRequest.Spec.Reconfigures = []Reconfigure{ + { + + ComponentOps: ComponentOps{ + ComponentName: "testReconfiguring", + }, }, } NewReconfigureCondition(opsRequest) diff --git a/apis/operations/v1alpha1/opsrequest_types.go b/apis/operations/v1alpha1/opsrequest_types.go index 3dad9956ef2..dc35a314084 100644 --- a/apis/operations/v1alpha1/opsrequest_types.go +++ b/apis/operations/v1alpha1/opsrequest_types.go @@ -35,12 +35,6 @@ type OpsRequestSpec struct { // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="forbidden to update spec.clusterName" ClusterName string `json:"clusterName,omitempty"` - // Deprecated: since v0.9, use clusterName instead. - // Specifies the name of the Cluster resource that this operation is targeting. - // +kubebuilder:deprecatedversion:warning="This field has been deprecated since 0.9.0" - // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="forbidden to update spec.clusterRef" - ClusterRef string `json:"clusterRef,omitempty"` - // Indicates whether the current operation should be canceled and terminated gracefully if it's in the // "Pending", "Creating", or "Running" state. // @@ -173,13 +167,6 @@ type SpecificOpsRequest struct { // +listMapKey=componentName VerticalScalingList []VerticalScaling `json:"verticalScaling,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"componentName"` - // Specifies a component and its configuration updates. - // - // This field is deprecated and replaced by `reconfigures`. - // - // +optional - Reconfigure *Reconfigure `json:"reconfigure,omitempty"` - // Lists Reconfigure objects, each specifying a Component and its configuration updates. // // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="forbidden to update spec.reconfigure" @@ -195,33 +182,20 @@ type SpecificOpsRequest struct { // +optional ExposeList []Expose `json:"expose,omitempty"` - // Specifies the parameters to backup a Cluster. + // Specifies the parameters to back up a Cluster. // +optional Backup *Backup `json:"backup,omitempty"` - // Deprecated: since v0.9, use backup instead. - // Specifies the parameters to backup a Cluster. - // +optional - // +kubebuilder:deprecatedversion:warning="This field has been deprecated since 0.9.0" - BackupSpec *Backup `json:"backupSpec,omitempty"` - // Specifies the parameters to restore a Cluster. // Note that this restore operation will roll back cluster services. // // +optional Restore *Restore `json:"restore,omitempty"` - // Deprecated: since v0.9, use restore instead. - // Specifies the parameters to restore a Cluster. - // Note that this restore operation will roll back cluster services. - // +kubebuilder:deprecatedversion:warning="This field has been deprecated since 0.9.0" - // +optional - RestoreSpec *Restore `json:"restoreSpec,omitempty"` - // Specifies the parameters to rebuild some instances. // Rebuilding an instance involves restoring its data from a backup or another database replica. // The instances being rebuilt usually serve as standby in the cluster. - // Hence rebuilding instances is often also referred to as "standby reconstruction". + // Hence, rebuilding instances is often also referred to as "standby reconstruction". // // +optional // +patchMergeKey=componentName @@ -323,12 +297,6 @@ type Switchover struct { // Upgrade defines the parameters for an upgrade operation. type Upgrade struct { - // Deprecated: since v0.9 because ClusterVersion is deprecated. - // Specifies the name of the target ClusterVersion for the upgrade. - // - // +kubebuilder:deprecatedversion:warning="This field has been deprecated since 0.9.0" - ClusterVersionRef *string `json:"clusterVersionRef,omitempty"` - // Lists components to be upgrade based on desired ComponentDefinition and ServiceVersion. // From the perspective of cluster API, the reasonable combinations should be: // 1. (comp-def, service-ver) - upgrade to the specified service version and component definition, the user takes the responsibility to ensure that they are compatible. @@ -451,13 +419,6 @@ type HorizontalScaling struct { // Specifies the name of the Component. ComponentOps `json:",inline"` - // Deprecated: since v0.9, use scaleOut and scaleIn instead. - // Specifies the number of replicas for the component. Cannot be used with "scaleIn" and "scaleOut". - // +kubebuilder:deprecatedversion:warning="This field has been deprecated since 0.9.0" - // +kubebuilder:validation:Minimum=0 - // +optional - Replicas *int32 `json:"replicas,omitempty"` - // Specifies the replica changes for scaling out components and instance templates, // and brings offline instances back online. Can be used in conjunction with the "scaleIn" operation. // Note: Any configuration that deletes instances is considered invalid. @@ -995,11 +956,6 @@ type OpsRequestStatus struct { // +optional CancelTimestamp metav1.Time `json:"cancelTimestamp,omitempty"` - // Deprecated: Replaced by ReconfiguringStatusAsComponent. - // Defines the status information of reconfiguring. - // +optional - ReconfiguringStatus *ReconfiguringStatus `json:"reconfiguringStatus,omitempty"` - // Records the status of a reconfiguring operation if `opsRequest.spec.type` equals to "Reconfiguring". // +optional ReconfiguringStatusAsComponent map[string]*ReconfiguringStatus `json:"reconfiguringStatusAsComponent,omitempty"` @@ -1113,10 +1069,6 @@ type LastComponentConfiguration struct { } type LastConfiguration struct { - // Specifies the name of the ClusterVersion. - // Deprecated and should be removed in the future version. - // +optional - ClusterVersionRef string `json:"clusterVersionRef,omitempty"` // Records the configuration of each Component prior to any changes. // +optional @@ -1152,14 +1104,6 @@ type OpsRequestComponentStatus struct { Message string `json:"message,omitempty" protobuf:"bytes,6,opt,name=message"` } -type OverrideBy struct { - // Indicates the name of the OpsRequest. - // +optional - OpsName string `json:"opsName"` - - LastComponentConfiguration `json:",inline"` -} - type PreCheckResult struct { // Indicates whether the preCheck operation passed or failed. // +kubebuilder:validation:Required @@ -1312,24 +1256,15 @@ func (r OpsRequestSpec) ToExposeListToMap() map[string]Expose { } func (r OpsRequestSpec) GetClusterName() string { - if r.ClusterName != "" { - return r.ClusterName - } - return r.ClusterRef + return r.ClusterName } func (r OpsRequestSpec) GetBackup() *Backup { - if r.Backup != nil { - return r.Backup - } - return r.BackupSpec + return r.Backup } func (r OpsRequestSpec) GetRestore() *Restore { - if r.Restore != nil { - return r.Restore - } - return r.RestoreSpec + return r.Restore } func (p *ProgressStatusDetail) SetStatusAndMessage(status ProgressStatus, message string) { diff --git a/apis/operations/v1alpha1/opsrequest_validation.go b/apis/operations/v1alpha1/opsrequest_validation.go index 91975256578..948f3a0c05e 100644 --- a/apis/operations/v1alpha1/opsrequest_validation.go +++ b/apis/operations/v1alpha1/opsrequest_validation.go @@ -201,9 +201,6 @@ func (r *OpsRequest) validateUpgrade(ctx context.Context, k8sClient client.Clien if upgrade == nil { return notEmptyError("spec.upgrade") } - if upgrade.ClusterVersionRef != nil && *upgrade.ClusterVersionRef != "" { - return fmt.Errorf("not supported") - } if len(r.Spec.Upgrade.Components) == 0 { return notEmptyError("spec.upgrade.components") } @@ -245,12 +242,8 @@ func (r *OpsRequest) validateVerticalScaling(cluster *appsv1.Cluster) error { func (r *OpsRequest) validateReconfigure(ctx context.Context, k8sClient client.Client, cluster *appsv1.Cluster) error { - reconfigure := r.Spec.Reconfigure - if reconfigure == nil && len(r.Spec.Reconfigures) == 0 { - return notEmptyError("spec.reconfigure") - } - if reconfigure != nil { - return r.validateReconfigureParams(ctx, k8sClient, cluster, reconfigure) + if len(r.Spec.Reconfigures) == 0 { + return notEmptyError("spec.reconfigures") } for _, reconfigure := range r.Spec.Reconfigures { if err := r.validateReconfigureParams(ctx, k8sClient, cluster, &reconfigure); err != nil { @@ -367,12 +360,6 @@ func (r *OpsRequest) CountOfflineOrOnlineInstances(clusterName, componentName st func (r *OpsRequest) validateHorizontalScalingSpec(hScale HorizontalScaling, compSpec appsv1.ClusterComponentSpec, clusterName string, isSharding bool) error { scaleIn := hScale.ScaleIn scaleOut := hScale.ScaleOut - if hScale.Replicas != nil && (scaleIn != nil || scaleOut != nil) { - return fmt.Errorf(`"replicas" has been deprecated and cannot be used with "scaleOut" and "scaleIn"`) - } - if hScale.Replicas != nil { - return nil - } if lastCompConfiguration, ok := r.Status.LastConfiguration.Components[hScale.ComponentName]; ok { // use last component configuration snapshot compSpec.Instances = lastCompConfiguration.Instances diff --git a/apis/operations/v1alpha1/zz_generated.deepcopy.go b/apis/operations/v1alpha1/zz_generated.deepcopy.go index d6627aea4a7..b4683da1b3b 100644 --- a/apis/operations/v1alpha1/zz_generated.deepcopy.go +++ b/apis/operations/v1alpha1/zz_generated.deepcopy.go @@ -263,11 +263,6 @@ func (in *Expose) DeepCopy() *Expose { func (in *HorizontalScaling) DeepCopyInto(out *HorizontalScaling) { *out = *in out.ComponentOps = in.ComponentOps - if in.Replicas != nil { - in, out := &in.Replicas, &out.Replicas - *out = new(int32) - **out = **in - } if in.ScaleOut != nil { in, out := &in.ScaleOut, &out.ScaleOut *out = new(ScaleOut) @@ -827,11 +822,6 @@ func (in *OpsRequestStatus) DeepCopyInto(out *OpsRequestStatus) { in.StartTimestamp.DeepCopyInto(&out.StartTimestamp) in.CompletionTimestamp.DeepCopyInto(&out.CompletionTimestamp) in.CancelTimestamp.DeepCopyInto(&out.CancelTimestamp) - if in.ReconfiguringStatus != nil { - in, out := &in.ReconfiguringStatus, &out.ReconfiguringStatus - *out = new(ReconfiguringStatus) - (*in).DeepCopyInto(*out) - } if in.ReconfiguringStatusAsComponent != nil { in, out := &in.ReconfiguringStatusAsComponent, &out.ReconfiguringStatusAsComponent *out = make(map[string]*ReconfiguringStatus, len(*in)) @@ -992,22 +982,6 @@ func (in *OpsWorkloadAction) DeepCopy() *OpsWorkloadAction { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OverrideBy) DeepCopyInto(out *OverrideBy) { - *out = *in - in.LastComponentConfiguration.DeepCopyInto(&out.LastComponentConfiguration) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverrideBy. -func (in *OverrideBy) DeepCopy() *OverrideBy { - if in == nil { - return nil - } - out := new(OverrideBy) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Parameter) DeepCopyInto(out *Parameter) { *out = *in @@ -1184,38 +1158,6 @@ func (in *PreCondition) DeepCopy() *PreCondition { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PreConditionExec) DeepCopyInto(out *PreConditionExec) { - *out = *in - if in.Env != nil { - in, out := &in.Env, &out.Env - *out = make([]v1.EnvVar, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Command != nil { - in, out := &in.Command, &out.Command - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Args != nil { - in, out := &in.Args, &out.Args - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PreConditionExec. -func (in *PreConditionExec) DeepCopy() *PreConditionExec { - if in == nil { - return nil - } - out := new(PreConditionExec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProgressStatusDetail) DeepCopyInto(out *ProgressStatusDetail) { *out = *in @@ -1483,11 +1425,6 @@ func (in *SpecificOpsRequest) DeepCopyInto(out *SpecificOpsRequest) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.Reconfigure != nil { - in, out := &in.Reconfigure, &out.Reconfigure - *out = new(Reconfigure) - (*in).DeepCopyInto(*out) - } if in.Reconfigures != nil { in, out := &in.Reconfigures, &out.Reconfigures *out = make([]Reconfigure, len(*in)) @@ -1507,21 +1444,11 @@ func (in *SpecificOpsRequest) DeepCopyInto(out *SpecificOpsRequest) { *out = new(Backup) **out = **in } - if in.BackupSpec != nil { - in, out := &in.BackupSpec, &out.BackupSpec - *out = new(Backup) - **out = **in - } if in.Restore != nil { in, out := &in.Restore, &out.Restore *out = new(Restore) (*in).DeepCopyInto(*out) } - if in.RestoreSpec != nil { - in, out := &in.RestoreSpec, &out.RestoreSpec - *out = new(Restore) - (*in).DeepCopyInto(*out) - } if in.RebuildFrom != nil { in, out := &in.RebuildFrom, &out.RebuildFrom *out = make([]RebuildInstance, len(*in)) @@ -1621,11 +1548,6 @@ func (in *UpdatedParameters) DeepCopy() *UpdatedParameters { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Upgrade) DeepCopyInto(out *Upgrade) { *out = *in - if in.ClusterVersionRef != nil { - in, out := &in.ClusterVersionRef, &out.ClusterVersionRef - *out = new(string) - **out = **in - } if in.Components != nil { in, out := &in.Components, &out.Components *out = make([]UpgradeComponent, len(*in)) diff --git a/config/crd/bases/operations.kubeblocks.io_opsrequests.yaml b/config/crd/bases/operations.kubeblocks.io_opsrequests.yaml index 7c4a3331798..13120663916 100644 --- a/config/crd/bases/operations.kubeblocks.io_opsrequests.yaml +++ b/config/crd/bases/operations.kubeblocks.io_opsrequests.yaml @@ -65,66 +65,7 @@ spec: description: OpsRequestSpec defines the desired state of OpsRequest properties: backup: - description: Specifies the parameters to backup a Cluster. - properties: - backupMethod: - description: |- - Specifies the name of BackupMethod. - The specified BackupMethod must be defined in the BackupPolicy. - type: string - backupName: - description: Specifies the name of the Backup custom resource. - type: string - backupPolicyName: - description: Indicates the name of the BackupPolicy applied to - perform this Backup. - type: string - deletionPolicy: - default: Delete - description: |- - Determines whether the backup contents stored in backup repository - should be deleted when the Backup custom resource is deleted. - Supported values are `Retain` and `Delete`. - - `Retain` means that the backup content and its physical snapshot on backup repository are kept. - - `Delete` means that the backup content and its physical snapshot on backup repository are deleted. - enum: - - Delete - - Retain - type: string - parentBackupName: - description: If the specified BackupMethod is incremental, `parentBackupName` - is required. - type: string - retentionPeriod: - description: |- - Determines the duration for which the Backup custom resources should be retained. - - - The controller will automatically remove all Backup objects that are older than the specified RetentionPeriod. - For example, RetentionPeriod of `30d` will keep only the Backup objects of last 30 days. - Sample duration format: - - - - years: 2y - - months: 6mo - - days: 30d - - hours: 12h - - minutes: 30m - - - You can also combine the above durations. For example: 30d12h30m. - If not set, the Backup objects will be kept forever. - - - If the `deletionPolicy` is set to 'Delete', then the associated backup data will also be deleted - along with the Backup object. - Otherwise, only the Backup custom resource will be deleted. - type: string - type: object - backupSpec: - description: |- - Deprecated: since v0.9, use backup instead. - Specifies the parameters to backup a Cluster. + description: Specifies the parameters to back up a Cluster. properties: backupMethod: description: |- @@ -198,14 +139,6 @@ spec: x-kubernetes-validations: - message: forbidden to update spec.clusterName rule: self == oldSelf - clusterRef: - description: |- - Deprecated: since v0.9, use clusterName instead. - Specifies the name of the Cluster resource that this operation is targeting. - type: string - x-kubernetes-validations: - - message: forbidden to update spec.clusterRef - rule: self == oldSelf custom: description: Specifies a custom operation defined by OpsDefinition. properties: @@ -558,13 +491,6 @@ spec: componentName: description: Specifies the name of the Component. type: string - replicas: - description: |- - Deprecated: since v0.9, use scaleOut and scaleIn instead. - Specifies the number of replicas for the component. Cannot be used with "scaleIn" and "scaleOut". - format: int32 - minimum: 0 - type: integer scaleIn: description: |- Specifies the replica changes for scaling in components and instance templates, @@ -3988,7 +3914,7 @@ spec: Specifies the parameters to rebuild some instances. Rebuilding an instance involves restoring its data from a backup or another database replica. The instances being rebuilt usually serve as standby in the cluster. - Hence rebuilding instances is often also referred to as "standby reconstruction". + Hence, rebuilding instances is often also referred to as "standby reconstruction". items: properties: backupName: @@ -4167,100 +4093,6 @@ spec: x-kubernetes-validations: - message: forbidden to update spec.rebuildFrom rule: self == oldSelf - reconfigure: - description: |- - Specifies a component and its configuration updates. - - - This field is deprecated and replaced by `reconfigures`. - properties: - componentName: - description: Specifies the name of the Component. - type: string - configurations: - description: |- - Contains a list of ConfigurationItem objects, specifying the Component's configuration template name, - upgrade policy, and parameter key-value pairs to be updated. - items: - properties: - keys: - description: |- - Sets the configuration files and their associated parameters that need to be updated. - It should contain at least one item. - items: - properties: - fileContent: - description: |- - Specifies the content of the entire configuration file. - This field is used to update the complete configuration file. - - - Either the `parameters` field or the `fileContent` field must be set, but not both. - type: string - key: - description: |- - Represents a key in the configuration template(as ConfigMap). - Each key in the ConfigMap corresponds to a specific configuration file. - type: string - parameters: - description: |- - Specifies a list of key-value pairs representing parameters and their corresponding values - within a single configuration file. - This field is used to override or set the values of parameters without modifying the entire configuration file. - - - Either the `parameters` field or the `fileContent` field must be set, but not both. - items: - properties: - key: - description: Represents the name of the parameter - that is to be updated. - type: string - value: - description: |- - Represents the parameter values that are to be updated. - If set to nil, the parameter defined by the Key field will be removed from the configuration file. - type: string - required: - - key - type: object - type: array - required: - - key - type: object - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - key - x-kubernetes-list-type: map - name: - description: Specifies the name of the configuration template. - maxLength: 63 - pattern: ^[a-z0-9]([a-z0-9\.\-]*[a-z0-9])?$ - type: string - policy: - description: Defines the upgrade policy for the configuration. - enum: - - simple - - parallel - - rolling - - autoReload - - operatorSyncUpdate - - dynamicReloadBeginRestart - type: string - required: - - keys - - name - type: object - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - required: - - componentName - - configurations - type: object reconfigures: description: Lists Reconfigure objects, each specifying a Component and its configuration updates. @@ -4535,169 +4367,6 @@ spec: Support values: - - "Serial" - - "Parallel" - enum: - - Serial - - Parallel - type: string - required: - - backupName - type: object - restoreSpec: - description: |- - Deprecated: since v0.9, use restore instead. - Specifies the parameters to restore a Cluster. - Note that this restore operation will roll back cluster services. - properties: - backupName: - description: Specifies the name of the Backup custom resource. - type: string - deferPostReadyUntilClusterRunning: - description: |- - Controls the timing of PostReady actions during the recovery process. - - - If false (default), PostReady actions execute when the Component reaches the "Running" state. - If true, PostReady actions are delayed until the entire Cluster is "Running," - ensuring the cluster's overall stability before proceeding. - - - This setting is useful for coordinating PostReady operations across the Cluster for optimal cluster conditions. - type: boolean - env: - description: Specifies a list of environment variables to be set - in the container. - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - x-kubernetes-preserve-unknown-fields: true - restorePointInTime: - description: |- - Specifies the point in time to which the restore should be performed. - Supported time formats: - - - - RFC3339 format, e.g. "2023-11-25T18:52:53Z" - - A human-readable date-time format, e.g. "Jul 25,2023 18:52:53 UTC+0800" - type: string - volumeRestorePolicy: - default: Parallel - description: |- - Specifies the policy for restoring volume claims of a Component's Pods. - It determines whether the volume claims should be restored sequentially (one by one) or in parallel (all at once). - Support values: - - - "Serial" - "Parallel" enum: @@ -4799,11 +4468,6 @@ spec: Note: This field is immutable once set. properties: - clusterVersionRef: - description: |- - Deprecated: since v0.9 because ClusterVersion is deprecated. - Specifies the name of the target ClusterVersion for the upgrade. - type: string components: description: |- Lists components to be upgrade based on desired ComponentDefinition and ServiceVersion. @@ -5320,11 +4984,6 @@ spec: lastConfiguration: description: Records the configuration prior to any changes. properties: - clusterVersionRef: - description: |- - Specifies the name of the ClusterVersion. - Deprecated and should be removed in the future version. - type: string components: additionalProperties: description: LastComponentConfiguration can be used to track @@ -8810,180 +8469,6 @@ spec: description: Represents the progress of the OpsRequest. pattern: ^(\d+|\-)/(\d+|\-)$ type: string - reconfiguringStatus: - description: |- - Deprecated: Replaced by ReconfiguringStatusAsComponent. - Defines the status information of reconfiguring. - properties: - conditions: - description: |- - Describes the reconfiguring detail status. - Possible condition types include "Creating", "Init", "Running", "Pending", "Merged", "MergeFailed", "FailedAndPause", - "Upgrading", "Deleting", "FailedAndRetry", "Finished", "ReconfigurePersisting", "ReconfigurePersisted". - items: - description: "Condition contains details for one aspect of the - current state of this API Resource.\n---\nThis struct is intended - for direct use as an array at the field path .status.conditions. - \ For example,\n\n\n\ttype FooStatus struct{\n\t // Represents - the observations of a foo's current state.\n\t // Known - .status.conditions.type are: \"Available\", \"Progressing\", - and \"Degraded\"\n\t // +patchMergeKey=type\n\t // +patchStrategy=merge\n\t - \ // +listType=map\n\t // +listMapKey=type\n\t Conditions - []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" - patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - configurationStatus: - description: Describes the status of the component reconfiguring. - items: - properties: - expectedCount: - default: -1 - description: Represents the total count of pods intended - to be updated by a configuration change. - format: int32 - type: integer - lastAppliedConfiguration: - additionalProperties: - type: string - description: Stores the last applied configuration. - type: object - lastStatus: - description: |- - Records the last state of the reconfiguration finite state machine. - Possible values include "None", "Retry", "Failed", "NotSupport", "FailedAndRetry". - - - - "None" describes fsm has finished and quit. - - "Retry" describes fsm is running. - - "Failed" describes fsm is failed and exited. - - "NotSupport" describes fsm does not support the feature. - - "FailedAndRetry" describes fsm is failed in current state, but can be retried. - type: string - message: - description: Provides details about the operation. - type: string - name: - description: Indicates the name of the configuration template - (as ConfigMap). - maxLength: 63 - pattern: ^[a-z0-9]([a-z0-9\.\-]*[a-z0-9])?$ - type: string - status: - description: |- - Represents the current state of the reconfiguration state machine. - Possible values include "Creating", "Init", "Running", "Pending", "Merged", "MergeFailed", "FailedAndPause", - "Upgrading", "Deleting", "FailedAndRetry", "Finished", "ReconfigurePersisting", "ReconfigurePersisted". - type: string - succeedCount: - default: 0 - description: Records the number of pods successfully updated - following a configuration change. - format: int32 - type: integer - updatePolicy: - description: Records the UpgradePolicy of the configuration - change operation. - enum: - - simple - - parallel - - rolling - - autoReload - - operatorSyncUpdate - - dynamicReloadBeginRestart - type: string - updatedParameters: - description: Contains the updated parameters. - properties: - addedKeys: - additionalProperties: - type: string - description: Maps newly added configuration files to - their content. - type: object - deletedKeys: - additionalProperties: - type: string - description: Lists the name of configuration files that - have been deleted. - type: object - updatedKeys: - additionalProperties: - type: string - description: Maps the name of configuration files to - their updated content, detailing the changes made. - type: object - type: object - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - required: - - configurationStatus - type: object reconfiguringStatusAsComponent: additionalProperties: properties: diff --git a/controllers/operations/opsrequest_controller.go b/controllers/operations/opsrequest_controller.go index 1d4f934d698..6672688ac33 100644 --- a/controllers/operations/opsrequest_controller.go +++ b/controllers/operations/opsrequest_controller.go @@ -314,11 +314,6 @@ func (r *OpsRequestReconciler) addClusterLabelAndSetOwnerReference(reqCtx intctr if err := controllerutil.SetOwnerReference(opsRes.Cluster, opsRequest, scheme); err != nil { return intctrlutil.ResultToP(intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "")) } - // mutate the clusterRef to clusterName. - // TODO: remove it after 0.9.0 - if opsRequest.Spec.ClusterName == "" { - opsRequest.Spec.ClusterName = opsRequest.Spec.ClusterRef - } if err := r.Client.Patch(reqCtx.Ctx, opsRequest, patch); err != nil { return intctrlutil.ResultToP(intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "")) } diff --git a/controllers/operations/opsrequest_controller_test.go b/controllers/operations/opsrequest_controller_test.go index e96043c03a9..06d99e4eb10 100644 --- a/controllers/operations/opsrequest_controller_test.go +++ b/controllers/operations/opsrequest_controller_test.go @@ -88,7 +88,6 @@ var _ = Describe("OpsRequest Controller", func() { testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, intctrlutil.VolumeSnapshotSignature, true, inNS) // delete cluster(and all dependent sub-resources), cluster definition - // TODO(review): why finalizers not removed testapps.ClearClusterResourcesWithRemoveFinalizerOption(&testCtx) testapps.ClearResources(&testCtx, intctrlutil.StorageClassSignature, ml) @@ -113,7 +112,6 @@ var _ = Describe("OpsRequest Controller", func() { mockSetClusterStatusPhaseToRunning := func(namespacedName types.NamespacedName) { Expect(testapps.GetAndChangeObjStatus(&testCtx, namespacedName, func(fetched *appsv1.Cluster) { - // TODO: would be better to have hint for cluster.status.phase is mocked, // i.e., add annotation info for the mocked context fetched.Status.Phase = appsv1.RunningClusterPhase if len(fetched.Status.Components) == 0 { @@ -366,7 +364,7 @@ var _ = Describe("OpsRequest Controller", func() { })).Should(Succeed()) } - createClusterHscaleOps := func(replicas int32) *opsv1alpha1.OpsRequest { + createClusterHScaleOps := func(replicaChanges int32, isScaleOut bool) *opsv1alpha1.OpsRequest { By("create a opsRequest to horizontal scale") opsName := "hscale-ops-" + testCtx.GetRandomStr() ops := testops.NewOpsRequestObj(opsName, testCtx.DefaultNamespace, @@ -374,9 +372,21 @@ var _ = Describe("OpsRequest Controller", func() { ops.Spec.HorizontalScalingList = []opsv1alpha1.HorizontalScaling{ { ComponentOps: opsv1alpha1.ComponentOps{ComponentName: mysqlCompName}, - Replicas: pointer.Int32(replicas), }, } + if isScaleOut { + ops.Spec.HorizontalScalingList[0].ScaleOut = &opsv1alpha1.ScaleOut{ + ReplicaChanger: opsv1alpha1.ReplicaChanger{ + ReplicaChanges: &replicaChanges, + }, + } + } else { + ops.Spec.HorizontalScalingList[0].ScaleIn = &opsv1alpha1.ScaleIn{ + ReplicaChanger: opsv1alpha1.ReplicaChanger{ + ReplicaChanges: &replicaChanges, + }, + } + } // for reconciling the ops labels ops.Labels = nil Expect(testCtx.CreateObj(testCtx.Ctx, ops)).Should(Succeed()) @@ -401,7 +411,7 @@ var _ = Describe("OpsRequest Controller", func() { initGeneration := cluster.Status.ObservedGeneration Eventually(testapps.GetClusterObservedGeneration(&testCtx, clusterKey)).Should(Equal(initGeneration)) - ops := createClusterHscaleOps(5) + ops := createClusterHScaleOps(2, true) opsKey := client.ObjectKeyFromObject(ops) By("expect component is Running if don't support volume snapshot during doing h-scale ops") @@ -439,8 +449,7 @@ var _ = Describe("OpsRequest Controller", func() { oldReplicas := int32(3) createMysqlCluster(oldReplicas) - replicas := int32(5) - ops := createClusterHscaleOps(replicas) + ops := createClusterHScaleOps(2, true) opsKey := client.ObjectKeyFromObject(ops) By("expect cluster and component is reconciling the new spec") @@ -481,9 +490,9 @@ var _ = Describe("OpsRequest Controller", func() { } Expect(k8sClient.Create(testCtx.Ctx, vs)).Should(Succeed()) Eventually(testapps.CheckObjExists(&testCtx, backupKey, vs, true)).Should(Succeed()) - + expectReplicas := int32(5) mockComponentPVCsAndBound := func(comp *appsv1.ClusterComponentSpec) { - for i := 0; i < int(replicas); i++ { + for i := 0; i < int(expectReplicas); i++ { for _, vct := range comp.VolumeClaimTemplates { pvcKey := types.NamespacedName{ Namespace: clusterKey.Namespace, @@ -509,20 +518,20 @@ var _ = Describe("OpsRequest Controller", func() { // mock pvcs have restored mockComponentPVCsAndBound(clusterObj.GetComponentByName(mysqlCompName)) // check restore CR and mock it to Completed - testdp.CheckRestoreAndSetCompleted(&testCtx, clusterKey, mysqlCompName, int(replicas-oldReplicas)) + testdp.CheckRestoreAndSetCompleted(&testCtx, clusterKey, mysqlCompName, int(expectReplicas-oldReplicas)) By("check the underlying workload been updated") Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(componentWorkload()), func(g Gomega, its *workloads.InstanceSet) { - g.Expect(*its.Spec.Replicas).Should(Equal(replicas)) + g.Expect(*its.Spec.Replicas).Should(Equal(expectReplicas)) })).Should(Succeed()) its := componentWorkload() Eventually(testapps.GetAndChangeObj(&testCtx, client.ObjectKeyFromObject(its), func(its *workloads.InstanceSet) { - its.Spec.Replicas = &replicas + its.Spec.Replicas = &expectReplicas })).Should(Succeed()) Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(componentWorkload()), func(g Gomega, its *workloads.InstanceSet) { - g.Expect(*its.Spec.Replicas).Should(Equal(replicas)) + g.Expect(*its.Spec.Replicas).Should(Equal(expectReplicas)) })).Should(Succeed()) By("Checking pvc created") @@ -530,10 +539,10 @@ var _ = Describe("OpsRequest Controller", func() { client.MatchingLabels{ constant.AppInstanceLabelKey: clusterKey.Name, constant.KBAppComponentLabelKey: mysqlCompName, - }, client.InNamespace(clusterKey.Namespace))).Should(HaveLen(int(replicas))) + }, client.InNamespace(clusterKey.Namespace))).Should(HaveLen(int(expectReplicas))) By("mock all new PVCs scaled bounded") - for i := 0; i < int(replicas); i++ { + for i := 0; i < int(expectReplicas); i++ { pvcKey := types.NamespacedName{ Namespace: testCtx.DefaultNamespace, Name: fmt.Sprintf("%s-%s-%s-%d", testapps.DataVolumeName, clusterKey.Name, mysqlCompName, i), @@ -547,7 +556,7 @@ var _ = Describe("OpsRequest Controller", func() { Eventually(testapps.CheckObjExists(&testCtx, backupKey, backup, false)).Should(Succeed()) By("mock component workload is running and expect cluster and component are running") - mockCompRunning(replicas, false) + mockCompRunning(expectReplicas, false) Eventually(testapps.CheckObj(&testCtx, clusterKey, func(g Gomega, cluster *appsv1.Cluster) { g.Expect(cluster.Status.Components[mysqlCompName].Phase).Should(Equal(appsv1.RunningClusterCompPhase)) g.Expect(cluster.Status.Phase).Should(Equal(appsv1.RunningClusterPhase)) @@ -570,8 +579,7 @@ var _ = Describe("OpsRequest Controller", func() { By("scale in the cluster replicas to 2") phase := opsv1alpha1.OpsPendingPhase - replicas := int32(2) - ops := createClusterHscaleOps(replicas) + ops := createClusterHScaleOps(2, false) Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(ops), func(g Gomega, ops *opsv1alpha1.OpsRequest) { phases := []opsv1alpha1.OpsPhase{opsv1alpha1.OpsRunningPhase, opsv1alpha1.OpsFailedPhase} g.Expect(slices.Contains(phases, ops.Status.Phase)).Should(BeTrue()) @@ -592,17 +600,18 @@ var _ = Describe("OpsRequest Controller", func() { })).Should(Succeed()) By("check the underlying workload been updated") + expectReplicas := int32(2) Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(componentWorkload()), func(g Gomega, its *workloads.InstanceSet) { - g.Expect(*its.Spec.Replicas).Should(Equal(replicas)) + g.Expect(*its.Spec.Replicas).Should(Equal(expectReplicas)) })).Should(Succeed()) its := componentWorkload() Eventually(testapps.GetAndChangeObj(&testCtx, client.ObjectKeyFromObject(its), func(its *workloads.InstanceSet) { - its.Spec.Replicas = &replicas + its.Spec.Replicas = &expectReplicas })).Should(Succeed()) Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(componentWorkload()), func(g Gomega, its *workloads.InstanceSet) { - g.Expect(*its.Spec.Replicas).Should(Equal(replicas)) + g.Expect(*its.Spec.Replicas).Should(Equal(expectReplicas)) })).Should(Succeed()) By("mock scale down successfully by deleting one pod ") @@ -611,7 +620,7 @@ var _ = Describe("OpsRequest Controller", func() { testapps.DeleteObject(&testCtx, dPodKeys, &corev1.Pod{}) By("expect opsRequest phase to Succeed after cluster is Running") - mockCompRunning(replicas, false) + mockCompRunning(expectReplicas, false) Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(ops), func(g Gomega, ops *opsv1alpha1.OpsRequest) { g.Expect(ops.Status.Phase).Should(Equal(opsv1alpha1.OpsSucceedPhase)) g.Expect(ops.Status.Progress).Should(Equal("2/2")) @@ -622,7 +631,7 @@ var _ = Describe("OpsRequest Controller", func() { By("Create a horizontalScaling ops") testk8s.MockEnableVolumeSnapshot(&testCtx, testk8s.DefaultStorageClassName) createMysqlCluster(3) - ops := createClusterHscaleOps(5) + ops := createClusterHScaleOps(2, true) opsKey := client.ObjectKeyFromObject(ops) Eventually(testops.GetOpsRequestPhase(&testCtx, opsKey)).Should(Equal(opsv1alpha1.OpsRunningPhase)) @@ -654,7 +663,7 @@ var _ = Describe("OpsRequest Controller", func() { mockCompRunning(oldReplicas, false) By("create a horizontalScaling ops") - ops := createClusterHscaleOps(5) + ops := createClusterHScaleOps(2, true) opsKey := client.ObjectKeyFromObject(ops) Eventually(testops.GetOpsRequestPhase(&testCtx, opsKey)).Should(Equal(opsv1alpha1.OpsRunningPhase)) Eventually(testapps.GetClusterPhase(&testCtx, clusterKey)).Should(Equal(appsv1.UpdatingClusterPhase)) diff --git a/deploy/helm/crds/operations.kubeblocks.io_opsrequests.yaml b/deploy/helm/crds/operations.kubeblocks.io_opsrequests.yaml index 7c4a3331798..13120663916 100755 --- a/deploy/helm/crds/operations.kubeblocks.io_opsrequests.yaml +++ b/deploy/helm/crds/operations.kubeblocks.io_opsrequests.yaml @@ -65,66 +65,7 @@ spec: description: OpsRequestSpec defines the desired state of OpsRequest properties: backup: - description: Specifies the parameters to backup a Cluster. - properties: - backupMethod: - description: |- - Specifies the name of BackupMethod. - The specified BackupMethod must be defined in the BackupPolicy. - type: string - backupName: - description: Specifies the name of the Backup custom resource. - type: string - backupPolicyName: - description: Indicates the name of the BackupPolicy applied to - perform this Backup. - type: string - deletionPolicy: - default: Delete - description: |- - Determines whether the backup contents stored in backup repository - should be deleted when the Backup custom resource is deleted. - Supported values are `Retain` and `Delete`. - - `Retain` means that the backup content and its physical snapshot on backup repository are kept. - - `Delete` means that the backup content and its physical snapshot on backup repository are deleted. - enum: - - Delete - - Retain - type: string - parentBackupName: - description: If the specified BackupMethod is incremental, `parentBackupName` - is required. - type: string - retentionPeriod: - description: |- - Determines the duration for which the Backup custom resources should be retained. - - - The controller will automatically remove all Backup objects that are older than the specified RetentionPeriod. - For example, RetentionPeriod of `30d` will keep only the Backup objects of last 30 days. - Sample duration format: - - - - years: 2y - - months: 6mo - - days: 30d - - hours: 12h - - minutes: 30m - - - You can also combine the above durations. For example: 30d12h30m. - If not set, the Backup objects will be kept forever. - - - If the `deletionPolicy` is set to 'Delete', then the associated backup data will also be deleted - along with the Backup object. - Otherwise, only the Backup custom resource will be deleted. - type: string - type: object - backupSpec: - description: |- - Deprecated: since v0.9, use backup instead. - Specifies the parameters to backup a Cluster. + description: Specifies the parameters to back up a Cluster. properties: backupMethod: description: |- @@ -198,14 +139,6 @@ spec: x-kubernetes-validations: - message: forbidden to update spec.clusterName rule: self == oldSelf - clusterRef: - description: |- - Deprecated: since v0.9, use clusterName instead. - Specifies the name of the Cluster resource that this operation is targeting. - type: string - x-kubernetes-validations: - - message: forbidden to update spec.clusterRef - rule: self == oldSelf custom: description: Specifies a custom operation defined by OpsDefinition. properties: @@ -558,13 +491,6 @@ spec: componentName: description: Specifies the name of the Component. type: string - replicas: - description: |- - Deprecated: since v0.9, use scaleOut and scaleIn instead. - Specifies the number of replicas for the component. Cannot be used with "scaleIn" and "scaleOut". - format: int32 - minimum: 0 - type: integer scaleIn: description: |- Specifies the replica changes for scaling in components and instance templates, @@ -3988,7 +3914,7 @@ spec: Specifies the parameters to rebuild some instances. Rebuilding an instance involves restoring its data from a backup or another database replica. The instances being rebuilt usually serve as standby in the cluster. - Hence rebuilding instances is often also referred to as "standby reconstruction". + Hence, rebuilding instances is often also referred to as "standby reconstruction". items: properties: backupName: @@ -4167,100 +4093,6 @@ spec: x-kubernetes-validations: - message: forbidden to update spec.rebuildFrom rule: self == oldSelf - reconfigure: - description: |- - Specifies a component and its configuration updates. - - - This field is deprecated and replaced by `reconfigures`. - properties: - componentName: - description: Specifies the name of the Component. - type: string - configurations: - description: |- - Contains a list of ConfigurationItem objects, specifying the Component's configuration template name, - upgrade policy, and parameter key-value pairs to be updated. - items: - properties: - keys: - description: |- - Sets the configuration files and their associated parameters that need to be updated. - It should contain at least one item. - items: - properties: - fileContent: - description: |- - Specifies the content of the entire configuration file. - This field is used to update the complete configuration file. - - - Either the `parameters` field or the `fileContent` field must be set, but not both. - type: string - key: - description: |- - Represents a key in the configuration template(as ConfigMap). - Each key in the ConfigMap corresponds to a specific configuration file. - type: string - parameters: - description: |- - Specifies a list of key-value pairs representing parameters and their corresponding values - within a single configuration file. - This field is used to override or set the values of parameters without modifying the entire configuration file. - - - Either the `parameters` field or the `fileContent` field must be set, but not both. - items: - properties: - key: - description: Represents the name of the parameter - that is to be updated. - type: string - value: - description: |- - Represents the parameter values that are to be updated. - If set to nil, the parameter defined by the Key field will be removed from the configuration file. - type: string - required: - - key - type: object - type: array - required: - - key - type: object - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - key - x-kubernetes-list-type: map - name: - description: Specifies the name of the configuration template. - maxLength: 63 - pattern: ^[a-z0-9]([a-z0-9\.\-]*[a-z0-9])?$ - type: string - policy: - description: Defines the upgrade policy for the configuration. - enum: - - simple - - parallel - - rolling - - autoReload - - operatorSyncUpdate - - dynamicReloadBeginRestart - type: string - required: - - keys - - name - type: object - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - required: - - componentName - - configurations - type: object reconfigures: description: Lists Reconfigure objects, each specifying a Component and its configuration updates. @@ -4535,169 +4367,6 @@ spec: Support values: - - "Serial" - - "Parallel" - enum: - - Serial - - Parallel - type: string - required: - - backupName - type: object - restoreSpec: - description: |- - Deprecated: since v0.9, use restore instead. - Specifies the parameters to restore a Cluster. - Note that this restore operation will roll back cluster services. - properties: - backupName: - description: Specifies the name of the Backup custom resource. - type: string - deferPostReadyUntilClusterRunning: - description: |- - Controls the timing of PostReady actions during the recovery process. - - - If false (default), PostReady actions execute when the Component reaches the "Running" state. - If true, PostReady actions are delayed until the entire Cluster is "Running," - ensuring the cluster's overall stability before proceeding. - - - This setting is useful for coordinating PostReady operations across the Cluster for optimal cluster conditions. - type: boolean - env: - description: Specifies a list of environment variables to be set - in the container. - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - x-kubernetes-preserve-unknown-fields: true - restorePointInTime: - description: |- - Specifies the point in time to which the restore should be performed. - Supported time formats: - - - - RFC3339 format, e.g. "2023-11-25T18:52:53Z" - - A human-readable date-time format, e.g. "Jul 25,2023 18:52:53 UTC+0800" - type: string - volumeRestorePolicy: - default: Parallel - description: |- - Specifies the policy for restoring volume claims of a Component's Pods. - It determines whether the volume claims should be restored sequentially (one by one) or in parallel (all at once). - Support values: - - - "Serial" - "Parallel" enum: @@ -4799,11 +4468,6 @@ spec: Note: This field is immutable once set. properties: - clusterVersionRef: - description: |- - Deprecated: since v0.9 because ClusterVersion is deprecated. - Specifies the name of the target ClusterVersion for the upgrade. - type: string components: description: |- Lists components to be upgrade based on desired ComponentDefinition and ServiceVersion. @@ -5320,11 +4984,6 @@ spec: lastConfiguration: description: Records the configuration prior to any changes. properties: - clusterVersionRef: - description: |- - Specifies the name of the ClusterVersion. - Deprecated and should be removed in the future version. - type: string components: additionalProperties: description: LastComponentConfiguration can be used to track @@ -8810,180 +8469,6 @@ spec: description: Represents the progress of the OpsRequest. pattern: ^(\d+|\-)/(\d+|\-)$ type: string - reconfiguringStatus: - description: |- - Deprecated: Replaced by ReconfiguringStatusAsComponent. - Defines the status information of reconfiguring. - properties: - conditions: - description: |- - Describes the reconfiguring detail status. - Possible condition types include "Creating", "Init", "Running", "Pending", "Merged", "MergeFailed", "FailedAndPause", - "Upgrading", "Deleting", "FailedAndRetry", "Finished", "ReconfigurePersisting", "ReconfigurePersisted". - items: - description: "Condition contains details for one aspect of the - current state of this API Resource.\n---\nThis struct is intended - for direct use as an array at the field path .status.conditions. - \ For example,\n\n\n\ttype FooStatus struct{\n\t // Represents - the observations of a foo's current state.\n\t // Known - .status.conditions.type are: \"Available\", \"Progressing\", - and \"Degraded\"\n\t // +patchMergeKey=type\n\t // +patchStrategy=merge\n\t - \ // +listType=map\n\t // +listMapKey=type\n\t Conditions - []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" - patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - configurationStatus: - description: Describes the status of the component reconfiguring. - items: - properties: - expectedCount: - default: -1 - description: Represents the total count of pods intended - to be updated by a configuration change. - format: int32 - type: integer - lastAppliedConfiguration: - additionalProperties: - type: string - description: Stores the last applied configuration. - type: object - lastStatus: - description: |- - Records the last state of the reconfiguration finite state machine. - Possible values include "None", "Retry", "Failed", "NotSupport", "FailedAndRetry". - - - - "None" describes fsm has finished and quit. - - "Retry" describes fsm is running. - - "Failed" describes fsm is failed and exited. - - "NotSupport" describes fsm does not support the feature. - - "FailedAndRetry" describes fsm is failed in current state, but can be retried. - type: string - message: - description: Provides details about the operation. - type: string - name: - description: Indicates the name of the configuration template - (as ConfigMap). - maxLength: 63 - pattern: ^[a-z0-9]([a-z0-9\.\-]*[a-z0-9])?$ - type: string - status: - description: |- - Represents the current state of the reconfiguration state machine. - Possible values include "Creating", "Init", "Running", "Pending", "Merged", "MergeFailed", "FailedAndPause", - "Upgrading", "Deleting", "FailedAndRetry", "Finished", "ReconfigurePersisting", "ReconfigurePersisted". - type: string - succeedCount: - default: 0 - description: Records the number of pods successfully updated - following a configuration change. - format: int32 - type: integer - updatePolicy: - description: Records the UpgradePolicy of the configuration - change operation. - enum: - - simple - - parallel - - rolling - - autoReload - - operatorSyncUpdate - - dynamicReloadBeginRestart - type: string - updatedParameters: - description: Contains the updated parameters. - properties: - addedKeys: - additionalProperties: - type: string - description: Maps newly added configuration files to - their content. - type: object - deletedKeys: - additionalProperties: - type: string - description: Lists the name of configuration files that - have been deleted. - type: object - updatedKeys: - additionalProperties: - type: string - description: Maps the name of configuration files to - their updated content, detailing the changes made. - type: object - type: object - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - required: - - configurationStatus - type: object reconfiguringStatusAsComponent: additionalProperties: properties: diff --git a/pkg/dataprotection/backup/scheduler.go b/pkg/dataprotection/backup/scheduler.go index d9af66c904e..d94e10bf066 100644 --- a/pkg/dataprotection/backup/scheduler.go +++ b/pkg/dataprotection/backup/scheduler.go @@ -419,17 +419,19 @@ func (s *Scheduler) reconfigure(schedulePolicy *dpv1alpha1.SchedulePolicy) error Type: opsv1alpha1.ReconfiguringType, ClusterName: clusterName, SpecificOpsRequest: opsv1alpha1.SpecificOpsRequest{ - Reconfigure: &opsv1alpha1.Reconfigure{ - ComponentOps: opsv1alpha1.ComponentOps{ - ComponentName: targetPodSelector.MatchLabels[constant.KBAppComponentLabelKey], - }, - Configurations: []opsv1alpha1.ConfigurationItem{ - { - Name: configRef.Name, - Keys: []opsv1alpha1.ParameterConfig{ - { - Key: configRef.Key, - Parameters: parameters, + Reconfigures: []opsv1alpha1.Reconfigure{ + { + ComponentOps: opsv1alpha1.ComponentOps{ + ComponentName: targetPodSelector.MatchLabels[constant.KBAppComponentLabelKey], + }, + Configurations: []opsv1alpha1.ConfigurationItem{ + { + Name: configRef.Name, + Keys: []opsv1alpha1.ParameterConfig{ + { + Key: configRef.Key, + Parameters: parameters, + }, }, }, }, diff --git a/pkg/operations/horizontal_scaling.go b/pkg/operations/horizontal_scaling.go index 9d0b82c4ae4..86ca7199905 100644 --- a/pkg/operations/horizontal_scaling.go +++ b/pkg/operations/horizontal_scaling.go @@ -80,10 +80,6 @@ func (hs horizontalScalingOpsHandler) Action(reqCtx intctrlutil.RequestCtx, cli return false, nil } currHorizontalScaling := compOps.(opsv1alpha1.HorizontalScaling) - // abort the opsRequest for overwrite replicas operation. - if currHorizontalScaling.Replicas != nil || v.Replicas != nil { - return true, nil - } // if the earlier opsRequest is pending and not `Overwrite` operator, return false. if earlierOps.Status.Phase == opsv1alpha1.OpsPendingPhase { return false, nil @@ -295,14 +291,9 @@ func (hs horizontalScalingOpsHandler) getExpectedCompValues( compSpec *appsv1.ClusterComponentSpec, lastCompConfiguration opsv1alpha1.LastComponentConfiguration, horizontalScaling opsv1alpha1.HorizontalScaling) (int32, []appsv1.InstanceTemplate, []string, error) { - compReplicas := compSpec.Replicas - compInstanceTpls := compSpec.Instances - compOfflineInstances := compSpec.OfflineInstances - if horizontalScaling.Replicas == nil { - compReplicas = *lastCompConfiguration.Replicas - compInstanceTpls = slices.Clone(lastCompConfiguration.Instances) - compOfflineInstances = lastCompConfiguration.OfflineInstances - } + compReplicas := *lastCompConfiguration.Replicas + compInstanceTpls := slices.Clone(lastCompConfiguration.Instances) + compOfflineInstances := lastCompConfiguration.OfflineInstances expectOfflineInstances := hs.getCompExpectedOfflineInstances(compOfflineInstances, horizontalScaling) err := hs.autoSyncReplicaChanges(opsRes, horizontalScaling, compReplicas, compInstanceTpls, expectOfflineInstances) if err != nil { @@ -379,9 +370,6 @@ func (hs horizontalScalingOpsHandler) autoSyncReplicaChanges( // getCompExpectReplicas gets the expected replicas for the component. func (hs horizontalScalingOpsHandler) getCompExpectReplicas(horizontalScaling opsv1alpha1.HorizontalScaling, compReplicas int32) int32 { - if horizontalScaling.Replicas != nil { - return *horizontalScaling.Replicas - } if horizontalScaling.ScaleOut != nil && horizontalScaling.ScaleOut.ReplicaChanges != nil { compReplicas += *horizontalScaling.ScaleOut.ReplicaChanges } @@ -396,9 +384,6 @@ func (hs horizontalScalingOpsHandler) getCompExpectedInstances( compInstanceTpls []appsv1.InstanceTemplate, horizontalScaling opsv1alpha1.HorizontalScaling, ) []appsv1.InstanceTemplate { - if horizontalScaling.Replicas != nil { - return compInstanceTpls - } compInsTplSet := map[string]int{} for i := range compInstanceTpls { compInsTplSet[compInstanceTpls[i].Name] = i diff --git a/pkg/operations/horizontal_scaling_test.go b/pkg/operations/horizontal_scaling_test.go index 505404d21a8..0716ce18b49 100644 --- a/pkg/operations/horizontal_scaling_test.go +++ b/pkg/operations/horizontal_scaling_test.go @@ -113,18 +113,28 @@ var _ = Describe("HorizontalScaling OpsRequest", func() { _, err = GetOpsManager().Do(reqCtx, k8sClient, opsRes) Expect(err).ShouldNot(HaveOccurred()) Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(opsRes.Cluster), func(g Gomega, tmpCluster *appsv1.Cluster) { - if horizontalScaling.Replicas == nil { - return - } lastCompConfiguration := opsRes.OpsRequest.Status.LastConfiguration.Components[defaultCompName] - var expectedCompReplicas int32 - switch { - case horizontalScaling.ScaleIn != nil: - expectedCompReplicas = *lastCompConfiguration.Replicas - *horizontalScaling.ScaleIn.ReplicaChanges - case horizontalScaling.ScaleOut != nil: - expectedCompReplicas = *lastCompConfiguration.Replicas + *horizontalScaling.ScaleOut.ReplicaChanges - default: - expectedCompReplicas = *horizontalScaling.Replicas + expectedCompReplicas := *lastCompConfiguration.Replicas + scaleIn := horizontalScaling.ScaleIn + if scaleIn != nil { + if scaleIn.ReplicaChanges != nil { + expectedCompReplicas -= *scaleIn.ReplicaChanges + } else { + expectedCompReplicas -= int32(len(scaleIn.OnlineInstancesToOffline)) + } + } + scaleOut := horizontalScaling.ScaleOut + if scaleOut != nil { + switch { + case scaleOut.ReplicaChanges != nil: + expectedCompReplicas += *scaleOut.ReplicaChanges + case len(scaleOut.NewInstances) > 0: + for _, v := range scaleOut.NewInstances { + expectedCompReplicas += *v.Replicas + } + default: + expectedCompReplicas += int32(len(scaleOut.OfflineInstancesToOnline)) + } } g.Expect(tmpCluster.Spec.GetComponentByName(defaultCompName).Replicas).Should(BeEquivalentTo(expectedCompReplicas)) })).Should(Succeed()) @@ -218,26 +228,6 @@ var _ = Describe("HorizontalScaling OpsRequest", func() { getProgressObjectKey(constant.PodKind, pod.Name)).Status).Should(Equal(opsv1alpha1.SucceedProgressStatus)) } - It("test to scale in replicas with `replicas`", func() { - By("scale in replicas from 3 to 1 ") - horizontalScaling := opsv1alpha1.HorizontalScaling{} - horizontalScaling.Replicas = pointer.Int32(1) - testHScaleReplicas(nil, horizontalScaling, func(podList []*corev1.Pod) { - By("delete the pods") - deletePods(podList[1], podList[2]) - }) - }) - - It("test to scale out replicas with `replicas`", func() { - By("scale out replicas from 3 to 5") - horizontalScaling := opsv1alpha1.HorizontalScaling{} - horizontalScaling.Replicas = pointer.Int32(5) - testHScaleReplicas(nil, horizontalScaling, func(podList []*corev1.Pod) { - By("create the pods(ordinal:[3,4])") - createPods("", 3, 4) - }) - }) - It("test to scale out replicas with `scaleOut`", func() { By("scale out replicas from 3 to 5 with `scaleOut`") horizontalScaling := opsv1alpha1.HorizontalScaling{ScaleOut: &opsv1alpha1.ScaleOut{}} @@ -260,12 +250,20 @@ var _ = Describe("HorizontalScaling OpsRequest", func() { It("cancel the opsRequest which scaling in replicas with `replicas`", func() { By("scale in replicas of component from 3 to 1") - testCancelHScale(opsv1alpha1.HorizontalScaling{Replicas: pointer.Int32(1)}, true) + testCancelHScale(opsv1alpha1.HorizontalScaling{ScaleIn: &opsv1alpha1.ScaleIn{ + ReplicaChanger: opsv1alpha1.ReplicaChanger{ + ReplicaChanges: pointer.Int32(2), + }, + }}, true) }) It("cancel the opsRequest which scaling out replicas with `replicas`", func() { By("scale out replicas of component from 3 to 5") - testCancelHScale(opsv1alpha1.HorizontalScaling{Replicas: pointer.Int32(5)}, false) + testCancelHScale(opsv1alpha1.HorizontalScaling{ScaleOut: &opsv1alpha1.ScaleOut{ + ReplicaChanger: opsv1alpha1.ReplicaChanger{ + ReplicaChanges: pointer.Int32(2), + }, + }}, false) }) It("cancel the opsRequest which scaling out replicas with `scaleOut`", func() { @@ -508,13 +506,13 @@ var _ = Describe("HorizontalScaling OpsRequest", func() { testapps.MockInstanceSetComponent(&testCtx, clusterName, defaultCompName) reqCtx := intctrlutil.RequestCtx{Ctx: ctx} By("create first opsRequest to add 1 replicas with `scaleOut` field and expect replicas to 4") - ops1 := createOpsAndToCreatingPhase(reqCtx, opsRes, opsv1alpha1.HorizontalScaling{ + createOpsAndToCreatingPhase(reqCtx, opsRes, opsv1alpha1.HorizontalScaling{ ScaleOut: &opsv1alpha1.ScaleOut{ReplicaChanger: opsv1alpha1.ReplicaChanger{ReplicaChanges: pointer.Int32(1)}}, }) Expect(opsRes.Cluster.Spec.GetComponentByName(defaultCompName).Replicas).Should(BeEquivalentTo(4)) By("create secondary opsRequest to add 1 replicas with `replicasToAdd` field and expect replicas to 5") - ops2 := createOpsAndToCreatingPhase(reqCtx, opsRes, opsv1alpha1.HorizontalScaling{ + createOpsAndToCreatingPhase(reqCtx, opsRes, opsv1alpha1.HorizontalScaling{ ScaleOut: &opsv1alpha1.ScaleOut{ReplicaChanger: opsv1alpha1.ReplicaChanger{ReplicaChanges: pointer.Int32(1)}}, }) Expect(opsRes.Cluster.Spec.GetComponentByName(defaultCompName).Replicas).Should(BeEquivalentTo(5)) @@ -538,22 +536,6 @@ var _ = Describe("HorizontalScaling OpsRequest", func() { Eventually(testops.GetOpsRequestPhase(&testCtx, client.ObjectKeyFromObject(opsRes.OpsRequest))).Should(Equal(opsv1alpha1.OpsFailedPhase)) conditions = opsRes.OpsRequest.Status.Conditions Expect(conditions[len(conditions)-1].Message).Should(ContainSubstring(`cannot be taken offline as it has been created by another running opsRequest`)) - - By("create a opsRequest with `replicas` field and expect to abort the running ops") - // if existing an overwrite replicas operation for a component or instanceTemplate, need to abort. - ops3 := createOpsAndToCreatingPhase(reqCtx, opsRes, opsv1alpha1.HorizontalScaling{ - Replicas: pointer.Int32(3), - }) - Eventually(testops.GetOpsRequestPhase(&testCtx, client.ObjectKeyFromObject(ops1))).Should(Equal(opsv1alpha1.OpsAbortedPhase)) - Eventually(testops.GetOpsRequestPhase(&testCtx, client.ObjectKeyFromObject(ops2))).Should(Equal(opsv1alpha1.OpsAbortedPhase)) - - By("create a opsRequest with `scaleOut` field and expect to abort last running ops") - // if running opsRequest exists an overwrite replicas operation for a component or instanceTemplate, need to abort. - createOpsAndToCreatingPhase(reqCtx, opsRes, opsv1alpha1.HorizontalScaling{ - ScaleOut: &opsv1alpha1.ScaleOut{ReplicaChanger: opsv1alpha1.ReplicaChanger{ReplicaChanges: pointer.Int32(1)}}, - }) - Eventually(testops.GetOpsRequestPhase(&testCtx, client.ObjectKeyFromObject(ops3))).Should(Equal(opsv1alpha1.OpsAbortedPhase)) - Expect(opsRes.Cluster.Spec.GetComponentByName(defaultCompName).Replicas).Should(BeEquivalentTo(4)) }) }) }) diff --git a/pkg/operations/ops_progress_util_test.go b/pkg/operations/ops_progress_util_test.go index 2cd006327f8..75c49448ed8 100644 --- a/pkg/operations/ops_progress_util_test.go +++ b/pkg/operations/ops_progress_util_test.go @@ -126,7 +126,11 @@ var _ = Describe("Ops ProgressDetails", func() { By("create horizontalScaling operation to test the progressDetails when scaling in the replicas") opsRes.OpsRequest = createHorizontalScaling(clusterName, opsv1alpha1.HorizontalScaling{ ComponentOps: opsv1alpha1.ComponentOps{ComponentName: defaultCompName}, - Replicas: pointer.Int32(1), + ScaleIn: &opsv1alpha1.ScaleIn{ + ReplicaChanger: opsv1alpha1.ReplicaChanger{ + ReplicaChanges: pointer.Int32(2), + }, + }, }) mockComponentIsOperating(opsRes.Cluster, appsv1.UpdatingClusterCompPhase, defaultCompName) // appsv1.HorizontalScalingPhase initClusterForOps(opsRes) @@ -179,7 +183,11 @@ var _ = Describe("Ops ProgressDetails", func() { By("create horizontalScaling operation to test the progressDetails when scaling out the replicas ") opsRes.OpsRequest = createHorizontalScaling(clusterName, opsv1alpha1.HorizontalScaling{ ComponentOps: opsv1alpha1.ComponentOps{ComponentName: defaultCompName}, - Replicas: pointer.Int32(4), + ScaleOut: &opsv1alpha1.ScaleOut{ + ReplicaChanger: opsv1alpha1.ReplicaChanger{ + ReplicaChanges: pointer.Int32(1), + }, + }, }) mockComponentIsOperating(opsRes.Cluster, appsv1.UpdatingClusterCompPhase, defaultCompName) // appsv1.HorizontalScalingPhase initClusterForOps(opsRes) diff --git a/pkg/operations/ops_util_test.go b/pkg/operations/ops_util_test.go index 43b2fdd71ab..2c78bbd5972 100644 --- a/pkg/operations/ops_util_test.go +++ b/pkg/operations/ops_util_test.go @@ -82,7 +82,11 @@ var _ = Describe("OpsUtil functions", func() { By("Test the functions in ops_util.go") opsRes.OpsRequest = createHorizontalScaling(clusterName, opsv1alpha1.HorizontalScaling{ ComponentOps: opsv1alpha1.ComponentOps{ComponentName: defaultCompName}, - Replicas: pointer.Int32(1), + ScaleIn: &opsv1alpha1.ScaleIn{ + ReplicaChanger: opsv1alpha1.ReplicaChanger{ + ReplicaChanges: pointer.Int32(2), + }, + }, }) Expect(patchValidateErrorCondition(ctx, k8sClient, opsRes, "validate error")).Should(Succeed()) Expect(PatchOpsHandlerNotSupported(ctx, k8sClient, opsRes)).Should(Succeed()) @@ -200,7 +204,11 @@ var _ = Describe("OpsUtil functions", func() { runHscaleOps := func(expectPhase opsv1alpha1.OpsPhase) *opsv1alpha1.OpsRequest { ops := createHorizontalScaling(clusterName, opsv1alpha1.HorizontalScaling{ ComponentOps: opsv1alpha1.ComponentOps{ComponentName: defaultCompName}, - Replicas: pointer.Int32(1), + ScaleIn: &opsv1alpha1.ScaleIn{ + ReplicaChanger: opsv1alpha1.ReplicaChanger{ + ReplicaChanges: pointer.Int32(1), + }, + }, }) opsRes.OpsRequest = ops _, err := GetOpsManager().Do(reqCtx, k8sClient, opsRes) @@ -316,7 +324,11 @@ var _ = Describe("OpsUtil functions", func() { By("expect the ops phase is failed") opsRes.OpsRequest = createHorizontalScaling(clusterName, opsv1alpha1.HorizontalScaling{ ComponentOps: opsv1alpha1.ComponentOps{ComponentName: defaultCompName}, - Replicas: pointer.Int32(1), + ScaleIn: &opsv1alpha1.ScaleIn{ + ReplicaChanger: opsv1alpha1.ReplicaChanger{ + ReplicaChanges: pointer.Int32(1), + }, + }, }) reqCtx := intctrlutil.RequestCtx{Ctx: testCtx.Ctx} _, _ = GetOpsManager().Do(reqCtx, k8sClient, opsRes) @@ -325,7 +337,11 @@ var _ = Describe("OpsUtil functions", func() { By("Test EnqueueOnForce=true") opsRes.OpsRequest = createHorizontalScaling(clusterName, opsv1alpha1.HorizontalScaling{ ComponentOps: opsv1alpha1.ComponentOps{ComponentName: defaultCompName}, - Replicas: pointer.Int32(1), + ScaleIn: &opsv1alpha1.ScaleIn{ + ReplicaChanger: opsv1alpha1.ReplicaChanger{ + ReplicaChanges: pointer.Int32(1), + }, + }, }) opsRes.OpsRequest.Spec.Force = true opsRes.OpsRequest.Spec.EnqueueOnForce = true diff --git a/pkg/operations/reconfigure.go b/pkg/operations/reconfigure.go index d589891a735..92a6ce87685 100644 --- a/pkg/operations/reconfigure.go +++ b/pkg/operations/reconfigure.go @@ -143,10 +143,6 @@ func (r *reconfigureAction) ReconcileAction(reqCtx intctrlutil.RequestCtx, cli c func fromReconfigureOperations(request opsv1alpha1.OpsRequestSpec, reqCtx intctrlutil.RequestCtx, cli client.Client, resource *OpsResource) (reconfigures []reconfigureParams) { var operations []opsv1alpha1.Reconfigure - - if request.Reconfigure != nil { - operations = append(operations, *request.Reconfigure) - } operations = append(operations, request.Reconfigures...) for _, reconfigure := range operations { @@ -319,15 +315,6 @@ func isExpectedPhase(condition metav1.Condition, expectedTypes []string, expecte func initReconfigureStatus(opsRequest *opsv1alpha1.OpsRequest, componentName string) *opsv1alpha1.ReconfiguringStatus { status := &opsRequest.Status - if componentName == "" || (opsRequest.Spec.Reconfigure != nil && opsRequest.Spec.Reconfigure.ComponentName == componentName) { - if status.ReconfiguringStatus == nil { - status.ReconfiguringStatus = &opsv1alpha1.ReconfiguringStatus{ - ConfigurationStatus: make([]opsv1alpha1.ConfigurationItemStatus, 0), - } - } - return status.ReconfiguringStatus - } - if status.ReconfiguringStatusAsComponent == nil { status.ReconfiguringStatusAsComponent = make(map[string]*opsv1alpha1.ReconfiguringStatus) } diff --git a/pkg/operations/reconfigure_test.go b/pkg/operations/reconfigure_test.go index 9dc84b73e2c..aec9c37fcdb 100644 --- a/pkg/operations/reconfigure_test.go +++ b/pkg/operations/reconfigure_test.go @@ -190,24 +190,26 @@ var _ = Describe("Reconfigure OpsRequest", func() { By("mock reconfigure success") ops := testops.NewOpsRequestObj("reconfigure-ops-"+randomStr, testCtx.DefaultNamespace, clusterName, opsv1alpha1.ReconfiguringType) - ops.Spec.Reconfigure = &opsv1alpha1.Reconfigure{ - Configurations: []opsv1alpha1.ConfigurationItem{{ - Name: "mysql-test", - Keys: []opsv1alpha1.ParameterConfig{{ - Key: "my.cnf", - Parameters: []opsv1alpha1.ParameterPair{ - { - Key: "binlog_stmt_cache_size", - Value: func() *string { v := "4096"; return &v }(), + ops.Spec.Reconfigures = []opsv1alpha1.Reconfigure{ + { + Configurations: []opsv1alpha1.ConfigurationItem{{ + Name: "mysql-test", + Keys: []opsv1alpha1.ParameterConfig{{ + Key: "my.cnf", + Parameters: []opsv1alpha1.ParameterPair{ + { + Key: "binlog_stmt_cache_size", + Value: func() *string { v := "4096"; return &v }(), + }, + { + Key: "key", + Value: func() *string { v := "abcd"; return &v }(), + }, }, - { - Key: "key", - Value: func() *string { v := "abcd"; return &v }(), - }, - }, + }}, }}, - }}, - ComponentOps: opsv1alpha1.ComponentOps{ComponentName: defaultCompName}, + ComponentOps: opsv1alpha1.ComponentOps{ComponentName: defaultCompName}, + }, } By("Init Reconfiguring opsrequest") @@ -285,19 +287,21 @@ var _ = Describe("Reconfigure OpsRequest", func() { By("mock reconfigure success") ops := testops.NewOpsRequestObj("reconfigure-ops-"+randomStr+"-reload", testCtx.DefaultNamespace, clusterName, opsv1alpha1.ReconfiguringType) - ops.Spec.Reconfigure = &opsv1alpha1.Reconfigure{ - Configurations: []opsv1alpha1.ConfigurationItem{{ - Name: "mysql-test", - Keys: []opsv1alpha1.ParameterConfig{{ - Key: "my.cnf", - Parameters: []opsv1alpha1.ParameterPair{ - { - Key: "binlog_stmt_cache_size", - Value: func() *string { v := "4096"; return &v }(), - }}, + ops.Spec.Reconfigures = []opsv1alpha1.Reconfigure{ + { + Configurations: []opsv1alpha1.ConfigurationItem{{ + Name: "mysql-test", + Keys: []opsv1alpha1.ParameterConfig{{ + Key: "my.cnf", + Parameters: []opsv1alpha1.ParameterPair{ + { + Key: "binlog_stmt_cache_size", + Value: func() *string { v := "4096"; return &v }(), + }}, + }}, }}, - }}, - ComponentOps: opsv1alpha1.ComponentOps{ComponentName: defaultCompName}, + ComponentOps: opsv1alpha1.ComponentOps{ComponentName: defaultCompName}, + }, } By("Init Reconfiguring opsrequest") diff --git a/pkg/operations/upgrade.go b/pkg/operations/upgrade.go index 7a064e1bbf9..935e8331561 100644 --- a/pkg/operations/upgrade.go +++ b/pkg/operations/upgrade.go @@ -58,29 +58,22 @@ func (u upgradeOpsHandler) ActionStartedCondition(reqCtx intctrlutil.RequestCtx, func (u upgradeOpsHandler) Action(reqCtx intctrlutil.RequestCtx, cli client.Client, opsRes *OpsResource) error { var compOpsHelper componentOpsHelper upgradeSpec := opsRes.OpsRequest.Spec.Upgrade - if u.existClusterVersion(opsRes.OpsRequest) { - return fmt.Errorf("not implemented") - } else { - compOpsHelper = newComponentOpsHelper(upgradeSpec.Components) - if err := compOpsHelper.updateClusterComponentsAndShardings(opsRes.Cluster, func(compSpec *appsv1.ClusterComponentSpec, obj ComponentOpsInterface) error { - upgradeComp := obj.(opsv1alpha1.UpgradeComponent) - if u.needUpdateCompDef(upgradeComp, opsRes.Cluster) { - compSpec.ComponentDef = *upgradeComp.ComponentDefinitionName - } - if upgradeComp.ServiceVersion != nil { - compSpec.ServiceVersion = *upgradeComp.ServiceVersion - } - return nil - }); err != nil { - return err + compOpsHelper = newComponentOpsHelper(upgradeSpec.Components) + if err := compOpsHelper.updateClusterComponentsAndShardings(opsRes.Cluster, func(compSpec *appsv1.ClusterComponentSpec, obj ComponentOpsInterface) error { + upgradeComp := obj.(opsv1alpha1.UpgradeComponent) + if u.needUpdateCompDef(upgradeComp, opsRes.Cluster) { + compSpec.ComponentDef = *upgradeComp.ComponentDefinitionName } + if upgradeComp.ServiceVersion != nil { + compSpec.ServiceVersion = *upgradeComp.ServiceVersion + } + return nil + }); err != nil { + return err } // abort earlier running upgrade opsRequest. if err := abortEarlierOpsRequestWithSameKind(reqCtx, cli, opsRes, []opsv1alpha1.OpsType{opsv1alpha1.UpgradeType}, func(earlierOps *opsv1alpha1.OpsRequest) (bool, error) { - if u.existClusterVersion(earlierOps) { - return true, nil - } for _, v := range earlierOps.Spec.Upgrade.Components { // abort the earlierOps if exists the same component. if _, ok := compOpsHelper.componentOpsSet[v.ComponentName]; ok { @@ -103,13 +96,9 @@ func (u upgradeOpsHandler) ReconcileAction(reqCtx intctrlutil.RequestCtx, cli cl componentDefMap map[string]*appsv1.ComponentDefinition err error ) - if u.existClusterVersion(opsRes.OpsRequest) { - return opsv1alpha1.OpsFailedPhase, 0, fmt.Errorf("not implemented") - } else { - compOpsHelper = newComponentOpsHelper(upgradeSpec.Components) - if componentDefMap, err = u.getComponentDefMapWithUpdatedImages(reqCtx, cli, opsRes); err != nil { - return opsRes.OpsRequest.Status.Phase, 0, err - } + compOpsHelper = newComponentOpsHelper(upgradeSpec.Components) + if componentDefMap, err = u.getComponentDefMapWithUpdatedImages(reqCtx, cli, opsRes); err != nil { + return opsRes.OpsRequest.Status.Phase, 0, err } componentUpgraded := func(cluster *appsv1.Cluster, lastCompConfiguration opsv1alpha1.LastComponentConfiguration, @@ -128,9 +117,6 @@ func (u upgradeOpsHandler) ReconcileAction(reqCtx intctrlutil.RequestCtx, cli cl pod *corev1.Pod, compOps ComponentOpsInterface, insTemplateName string) bool { - if u.existClusterVersion(opsRes.OpsRequest) { - return false - } upgradeComponent := compOps.(opsv1alpha1.UpgradeComponent) lastCompConfiguration := opsRes.OpsRequest.Status.LastConfiguration.Components[compOps.GetComponentName()] if !componentUpgraded(opsRes.Cluster, lastCompConfiguration, upgradeComponent) { @@ -209,10 +195,6 @@ func (u upgradeOpsHandler) podImageApplied(pod *corev1.Pod, expectContainers []c return true } -func (u upgradeOpsHandler) existClusterVersion(ops *opsv1alpha1.OpsRequest) bool { - return ops.Spec.Upgrade.ClusterVersionRef != nil && *ops.Spec.Upgrade.ClusterVersionRef != "" -} - func (u upgradeOpsHandler) needUpdateCompDef(upgradeComp opsv1alpha1.UpgradeComponent, cluster *appsv1.Cluster) bool { if upgradeComp.ComponentDefinitionName == nil { return false