Skip to content

Commit cd18bd6

Browse files
committed
Merge remote-tracking branch 'origin/main' into bugfix/10755-cluster-restore-finalizer
2 parents 243d4b8 + cdc2d7d commit cd18bd6

31 files changed

Lines changed: 1113 additions & 76 deletions

apis/dataprotection/v1alpha1/restore_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ type BackupRef struct {
105105
Name string `json:"name"`
106106

107107
// Specifies the backup namespace.
108+
// Cross-namespace VolumeSnapshot restores are NOT supported.
108109
//
109110
// +kubebuilder:validation:Required
110111
Namespace string `json:"namespace"`

apis/operations/v1alpha1/opsrequest_types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,9 @@ type FromBackup struct {
513513
// +kubebuilder:validation:Required
514514
Name string `json:"name"`
515515

516-
// Specifies the namespace of the Backup namespace.
516+
// Specifies the namespace of the Backup.
517517
// If not specified, the namespace of the OpsRequest will be used.
518+
// Cross-namespace VolumeSnapshot restores are NOT supported.
518519
// +optional
519520
Namespace string `json:"namespace,omitempty"`
520521

apis/workloads/v1/instance_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ type InstanceStatus2 struct {
153153
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
154154

155155
// Represents the latest available observations of an instance's current state.
156-
// Known .status.conditions.type are: "InstanceFailure", "InstanceReady", "InstanceAvailable"
156+
// Known .status.conditions.type are: "InstanceFailure", "InstanceReady", "InstanceAvailable", "Restore"
157157
//
158158
// +optional
159159
Conditions []metav1.Condition `json:"conditions,omitempty"`

apis/workloads/v1/instanceset_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ const (
738738
// InstanceFailure is added in an instance set when at least one of its instances(pods) is in a `Failed` phase.
739739
InstanceFailure ConditionType = "InstanceFailure"
740740

741-
// InstanceRestore indicates whether the initial data restore for this InstanceSet has completed.
741+
// InstanceRestore indicates whether the initial data restore for this Instance or InstanceSet has completed.
742742
InstanceRestore ConditionType = "Restore"
743743

744744
// InstanceUpdateRestricted represents a ConditionType that indicates updates to an InstanceSet are blocked(when the

config/crd/bases/dataprotection.kubeblocks.io_restores.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ spec:
8383
description: Specifies the backup name.
8484
type: string
8585
namespace:
86-
description: Specifies the backup namespace.
86+
description: |-
87+
Specifies the backup namespace.
88+
Cross-namespace VolumeSnapshot restores are NOT supported.
8789
type: string
8890
sourceTargetName:
8991
description: Specifies the source target for restoration, identified

config/crd/bases/operations.kubeblocks.io_opsrequests.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,8 +619,9 @@ spec:
619619
type: string
620620
namespace:
621621
description: |-
622-
Specifies the namespace of the Backup namespace.
622+
Specifies the namespace of the Backup.
623623
If not specified, the namespace of the OpsRequest will be used.
624+
Cross-namespace VolumeSnapshot restores are NOT supported.
624625
type: string
625626
restoreEnv:
626627
description: |-

config/crd/bases/workloads.kubeblocks.io_instances.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10267,7 +10267,7 @@ spec:
1026710267
conditions:
1026810268
description: |-
1026910269
Represents the latest available observations of an instance's current state.
10270-
Known .status.conditions.type are: "InstanceFailure", "InstanceReady", "InstanceAvailable"
10270+
Known .status.conditions.type are: "InstanceFailure", "InstanceReady", "InstanceAvailable", "Restore"
1027110271
items:
1027210272
description: Condition contains details for one aspect of the current
1027310273
state of this API Resource.

controllers/dataprotection/volumepopulator_controller.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,13 +1000,13 @@ func (r *VolumePopulatorReconciler) validateRestoreAndBuildMGR(reqCtx intctrluti
10001000
}
10011001
}
10021002
}
1003-
if err = r.restoreSystemAccountSecrets(reqCtx, pvc, backupNamespace); err != nil {
1004-
return nil, err
1005-
}
10061003
restoreMgr := dprestore.NewRestoreManager(restore, r.Recorder, r.Scheme, r.Client)
10071004
if err = dprestore.ValidateAndInitRestoreMGR(reqCtx, r.Client, restoreMgr); err != nil {
10081005
return nil, err
10091006
}
1007+
if err = r.restoreSystemAccountSecrets(reqCtx, pvc, backupNamespace); err != nil {
1008+
return nil, err
1009+
}
10101010
if decision.mode == pvcRestoreModeProvisionOnly {
10111011
restoreMgr.PrepareDataBackupSets = nil
10121012
}

controllers/dataprotection/volumepopulator_controller_test.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,21 @@ var _ = Describe("Volume Populator Controller test", func() {
774774
g.Expect(restoreCondition).ShouldNot(BeNil())
775775
g.Expect(restoreCondition.Status).Should(Equal(corev1.ConditionUnknown))
776776
})).Should(Succeed())
777+
778+
populateKey := types.NamespacedName{
779+
Namespace: testCtx.DefaultNamespace,
780+
Name: getPopulatePVCName(pvc.UID),
781+
}
782+
Eventually(testapps.CheckObjExists(&testCtx, populateKey,
783+
&corev1.PersistentVolumeClaim{}, true)).Should(Succeed())
784+
Eventually(testapps.CheckObjExists(&testCtx, populateKey,
785+
&dpv1alpha1.Restore{}, true)).Should(Succeed())
786+
787+
By("clean resources created by the case")
788+
cleanEnv()
789+
testapps.DeleteObject(&testCtx, secretKey, &corev1.Secret{})
790+
Eventually(testapps.CheckObjExists(&testCtx, secretKey,
791+
&corev1.Secret{}, false)).Should(Succeed())
777792
})
778793

779794
It("test VolumePopulator when it fails", func() {
@@ -2735,6 +2750,151 @@ func TestRestoreSystemAccountSecretsUsesShardingSecretName(t *testing.T) {
27352750
systemAccountSecretName(systemAccountSecretScopeComponent, "cluster", "mysql", "admin"))
27362751
}
27372752

2753+
func TestValidateRestoreBeforeRestoringSystemAccountSecrets(t *testing.T) {
2754+
scheme := runtime.NewScheme()
2755+
require.NoError(t, corev1.AddToScheme(scheme))
2756+
require.NoError(t, kbappsv1.AddToScheme(scheme))
2757+
require.NoError(t, dpv1alpha1.AddToScheme(scheme))
2758+
require.NoError(t, workloadsv1.AddToScheme(scheme))
2759+
2760+
const (
2761+
sourceNamespace = "source"
2762+
targetNamespace = "target"
2763+
clusterName = "cluster"
2764+
componentName = "mysql"
2765+
accountName = "admin"
2766+
)
2767+
actionSet := &dpv1alpha1.ActionSet{
2768+
ObjectMeta: metav1.ObjectMeta{Name: "snapshot-action"},
2769+
Spec: dpv1alpha1.ActionSetSpec{
2770+
BackupType: dpv1alpha1.BackupTypeFull,
2771+
Restore: &dpv1alpha1.RestoreActionSpec{
2772+
PrepareData: &dpv1alpha1.JobActionSpec{},
2773+
},
2774+
},
2775+
}
2776+
encryptor := intctrlutil.NewEncryptor(viper.GetString(constant.CfgKeyDPEncryptionKey))
2777+
encryptedPassword, err := encryptor.Encrypt([]byte("restored-password"))
2778+
require.NoError(t, err)
2779+
accounts, err := json.Marshal(map[string]map[string]string{
2780+
componentName: {accountName: encryptedPassword},
2781+
})
2782+
require.NoError(t, err)
2783+
backup := &dpv1alpha1.Backup{
2784+
ObjectMeta: metav1.ObjectMeta{
2785+
Namespace: sourceNamespace,
2786+
Name: "backup",
2787+
Annotations: map[string]string{
2788+
constant.EncryptedSystemAccountsAnnotationKey: string(accounts),
2789+
},
2790+
},
2791+
Status: dpv1alpha1.BackupStatus{
2792+
Phase: dpv1alpha1.BackupPhaseCompleted,
2793+
BackupMethod: &dpv1alpha1.BackupMethod{
2794+
Name: "snapshot",
2795+
ActionSetName: actionSet.Name,
2796+
SnapshotVolumes: ptr.To(true),
2797+
TargetVolumes: &dpv1alpha1.TargetVolumeInfo{Volumes: []string{"data"}},
2798+
},
2799+
},
2800+
}
2801+
cluster := &kbappsv1.Cluster{
2802+
ObjectMeta: metav1.ObjectMeta{Namespace: targetNamespace, Name: clusterName, UID: types.UID("cluster-uid")},
2803+
Spec: kbappsv1.ClusterSpec{
2804+
Restore: &kbappsv1.ClusterRestore{
2805+
Source: kbappsv1.ClusterRestoreSource{
2806+
APIGroup: dptypes.DataprotectionAPIGroup,
2807+
Kind: dptypes.BackupKind,
2808+
Name: backup.Name,
2809+
Namespace: backup.Namespace,
2810+
},
2811+
},
2812+
},
2813+
}
2814+
component := &kbappsv1.Component{
2815+
ObjectMeta: metav1.ObjectMeta{
2816+
Namespace: targetNamespace,
2817+
Name: constant.GenerateClusterComponentName(clusterName, componentName),
2818+
UID: types.UID("component-uid"),
2819+
},
2820+
}
2821+
instanceSet := &workloadsv1.InstanceSet{
2822+
TypeMeta: metav1.TypeMeta{APIVersion: workloadsv1.GroupVersion.String(), Kind: workloadsv1.InstanceSetKind},
2823+
ObjectMeta: metav1.ObjectMeta{
2824+
Namespace: targetNamespace,
2825+
Name: "cluster-mysql",
2826+
UID: types.UID("instanceset-uid"),
2827+
Labels: map[string]string{
2828+
constant.AppInstanceLabelKey: clusterName,
2829+
constant.KBAppComponentLabelKey: componentName,
2830+
},
2831+
},
2832+
Spec: workloadsv1.InstanceSetSpec{
2833+
Replicas: ptr.To[int32](1),
2834+
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{{
2835+
ObjectMeta: metav1.ObjectMeta{Name: "data"},
2836+
}},
2837+
},
2838+
}
2839+
apiGroup := dptypes.DataprotectionAPIGroup
2840+
pvc := &corev1.PersistentVolumeClaim{
2841+
ObjectMeta: metav1.ObjectMeta{
2842+
Namespace: targetNamespace,
2843+
Name: "data-cluster-mysql-0",
2844+
Labels: map[string]string{
2845+
constant.AppInstanceLabelKey: clusterName,
2846+
constant.KBAppComponentLabelKey: componentName,
2847+
constant.KBAppPodNameLabelKey: "cluster-mysql-0",
2848+
constant.VolumeClaimTemplateNameLabelKey: "data",
2849+
},
2850+
Annotations: map[string]string{
2851+
constant.RestoreSourceNamespaceAnnotationKey: sourceNamespace,
2852+
constant.RestoreVolumeTemplateAnnotationKey: "data",
2853+
},
2854+
OwnerReferences: []metav1.OwnerReference{{
2855+
APIVersion: workloadsv1.GroupVersion.String(),
2856+
Kind: workloadsv1.InstanceSetKind,
2857+
Name: instanceSet.Name,
2858+
UID: instanceSet.UID,
2859+
Controller: ptr.To(true),
2860+
}},
2861+
},
2862+
Spec: corev1.PersistentVolumeClaimSpec{
2863+
DataSourceRef: &corev1.TypedObjectReference{
2864+
APIGroup: &apiGroup,
2865+
Kind: dptypes.BackupKind,
2866+
Name: backup.Name,
2867+
},
2868+
},
2869+
}
2870+
secret := &corev1.Secret{
2871+
ObjectMeta: metav1.ObjectMeta{
2872+
Namespace: targetNamespace,
2873+
Name: constant.GenerateAccountSecretName(clusterName, componentName, accountName),
2874+
},
2875+
Data: map[string][]byte{
2876+
constant.AccountNameForSecret: []byte(accountName),
2877+
constant.AccountPasswdForSecret: []byte("existing-password"),
2878+
},
2879+
}
2880+
reconciler := &VolumePopulatorReconciler{
2881+
Client: fake.NewClientBuilder().WithScheme(scheme).WithObjects(
2882+
actionSet, backup, cluster, component, instanceSet, secret,
2883+
).Build(),
2884+
Scheme: scheme,
2885+
}
2886+
2887+
_, err = reconciler.validateRestoreAndBuildMGR(intctrlutil.RequestCtx{Ctx: context.Background()}, pvc)
2888+
require.ErrorContains(t, err, "cross-namespace VolumeSnapshot")
2889+
require.True(t, intctrlutil.IsTargetError(err, intctrlutil.ErrorTypeFatal))
2890+
2891+
got := &corev1.Secret{}
2892+
require.NoError(t, reconciler.Client.Get(context.Background(), client.ObjectKeyFromObject(secret), got))
2893+
require.Equal(t, []byte("existing-password"), got.Data[constant.AccountPasswdForSecret])
2894+
require.NotContains(t, got.Annotations, constant.SystemAccountProvisionedAnnotationKey)
2895+
require.Empty(t, got.OwnerReferences)
2896+
}
2897+
27382898
func TestRestoreSystemAccountSecretsRestoresComponentAndShardingSecrets(t *testing.T) {
27392899
scheme := runtime.NewScheme()
27402900
require.NoError(t, corev1.AddToScheme(scheme))

deploy/helm/crds/dataprotection.kubeblocks.io_restores.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ spec:
8383
description: Specifies the backup name.
8484
type: string
8585
namespace:
86-
description: Specifies the backup namespace.
86+
description: |-
87+
Specifies the backup namespace.
88+
Cross-namespace VolumeSnapshot restores are NOT supported.
8789
type: string
8890
sourceTargetName:
8991
description: Specifies the source target for restoration, identified

0 commit comments

Comments
 (0)