Merge pull request #4779 from reasonerjt/fix-restore-hook

Ensure the restore hook applied to new namespace based on the mapping
pull/4773/head
Wenkai Yin(尹文开) 2022-03-29 14:07:08 +08:00 committed by GitHub
commit 0b8f19e4d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 99 additions and 7 deletions

View File

@ -0,0 +1 @@
Ensure the restore hook applied to new namespace based on the mapping

View File

@ -104,6 +104,7 @@ func (i *InitContainerRestoreHookHandler) HandleRestoreHooks(
groupResource schema.GroupResource,
obj runtime.Unstructured,
resourceRestoreHooks []ResourceRestoreHook,
namespaceMapping map[string]string,
) (runtime.Unstructured, error) {
// We only support hooks on pods right now
if groupResource != kuberesource.Pods {
@ -141,6 +142,13 @@ func (i *InitContainerRestoreHookHandler) HandleRestoreHooks(
namespace := metadata.GetNamespace()
labels := labels.Set(metadata.GetLabels())
// Apply the hook according to the target namespace in which the pod will be restored
// more details see https://github.com/vmware-tanzu/velero/issues/4720
if namespaceMapping != nil {
if n, ok := namespaceMapping[namespace]; ok {
namespace = n
}
}
for _, rh := range resourceRestoreHooks {
if !rh.Selector.applicableTo(groupResource, namespace, labels) {
continue

View File

@ -1395,11 +1395,12 @@ func TestGetRestoreHooksFromSpec(t *testing.T) {
func TestHandleRestoreHooks(t *testing.T) {
testCases := []struct {
name string
podInput corev1api.Pod
restoreHooks []ResourceRestoreHook
expectedPod *corev1api.Pod
expectedError error
name string
podInput corev1api.Pod
restoreHooks []ResourceRestoreHook
namespaceMapping map[string]string
expectedPod *corev1api.Pod
expectedError error
}{
{
name: "should handle hook from annotation no hooks in spec on pod with no init containers",
@ -1840,6 +1841,87 @@ func TestHandleRestoreHooks(t *testing.T) {
},
restoreHooks: []ResourceRestoreHook{},
},
{
name: "should not apply init container when the namespace mapping is provided and the hook points to the original namespace",
podInput: corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "default",
},
Spec: corev1api.PodSpec{},
},
expectedError: nil,
expectedPod: &corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "default",
},
Spec: corev1api.PodSpec{},
},
restoreHooks: []ResourceRestoreHook{
{
Name: "hook1",
Selector: ResourceHookSelector{
Namespaces: collections.NewIncludesExcludes().Includes("default"),
Resources: collections.NewIncludesExcludes().Includes(kuberesource.Pods.Resource),
},
RestoreHooks: []velerov1api.RestoreResourceHook{
{
Init: &velerov1api.InitRestoreHook{
InitContainers: []corev1api.Container{
*builder.ForContainer("restore-init-container-1", "nginx").
Command([]string{"a", "b", "c"}).Result(),
},
},
},
},
},
},
namespaceMapping: map[string]string{"default": "new"},
},
{
name: "should apply init container when the namespace mapping is provided and the hook points to the new namespace",
podInput: corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "default",
},
Spec: corev1api.PodSpec{},
},
expectedError: nil,
expectedPod: &corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "default",
},
Spec: corev1api.PodSpec{
InitContainers: []corev1api.Container{
*builder.ForContainer("restore-init-container-1", "nginx").
Command([]string{"a", "b", "c"}).Result(),
},
},
},
restoreHooks: []ResourceRestoreHook{
{
Name: "hook1",
Selector: ResourceHookSelector{
Namespaces: collections.NewIncludesExcludes().Includes("new"),
Resources: collections.NewIncludesExcludes().Includes(kuberesource.Pods.Resource),
},
RestoreHooks: []velerov1api.RestoreResourceHook{
{
Init: &velerov1api.InitRestoreHook{
InitContainers: []corev1api.Container{
*builder.ForContainer("restore-init-container-1", "nginx").
Command([]string{"a", "b", "c"}).Result(),
},
},
},
},
},
},
namespaceMapping: map[string]string{"default": "new"},
},
}
for _, tc := range testCases {
@ -1847,7 +1929,7 @@ func TestHandleRestoreHooks(t *testing.T) {
handler := InitContainerRestoreHookHandler{}
podMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tc.podInput)
assert.NoError(t, err)
actual, err := handler.HandleRestoreHooks(velerotest.NewLogger(), kuberesource.Pods, &unstructured.Unstructured{Object: podMap}, tc.restoreHooks)
actual, err := handler.HandleRestoreHooks(velerotest.NewLogger(), kuberesource.Pods, &unstructured.Unstructured{Object: podMap}, tc.restoreHooks, tc.namespaceMapping)
assert.Equal(t, tc.expectedError, err)
actualPod := new(corev1api.Pod)
err = runtime.DefaultUnstructuredConverter.FromUnstructured(actual.UnstructuredContent(), actualPod)

View File

@ -49,11 +49,12 @@ func (a *InitRestoreHookPodAction) Execute(input *velero.RestoreItemActionExecut
a.logger.Infof("Executing InitRestoreHookPodAction")
// handle any init container restore hooks for the pod
restoreHooks, err := hook.GetRestoreHooksFromSpec(&input.Restore.Spec.Hooks)
nsMapping := input.Restore.Spec.NamespaceMapping
if err != nil {
return nil, errors.WithStack(err)
}
hookHandler := hook.InitContainerRestoreHookHandler{}
postHooksItem, err := hookHandler.HandleRestoreHooks(a.logger, kuberesource.Pods, input.Item, restoreHooks)
postHooksItem, err := hookHandler.HandleRestoreHooks(a.logger, kuberesource.Pods, input.Item, restoreHooks, nsMapping)
if err != nil {
return nil, errors.WithStack(err)
}