Adding fix for restic init container index on restores. (#3011)

* Adding handling of restic-wait init container at any order with warning.

Signed-off-by: Piper Dougherty <doughertypiper@gmail.com>

* Adding newline at end of files to match convention.

Signed-off-by: Piper Dougherty <doughertypiper@gmail.com>

* Formatting.

Signed-off-by: Piper Dougherty <doughertypiper@gmail.com>

* Update copyright year on modified files.

Signed-off-by: Piper Dougherty <doughertypiper@gmail.com>
This commit is contained in:
Piper Dougherty
2020-10-21 18:15:03 -04:00
committed by GitHub
parent 28a46d3a8b
commit 60ff351269
3 changed files with 133 additions and 14 deletions

View File

@@ -0,0 +1,2 @@
Allows the restic-wait container to exist in any order in the pod being restored.
Prints a warning message in the case where the restic-wait container isn't the first container in the list of initialization containers.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 the Velero contributors.
Copyright 2020 the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -155,6 +155,12 @@ func (c *podVolumeRestoreController) pvrHandler(obj interface{}) {
return
}
resticInitContainerIndex := getResticInitContainerIndex(pod)
if resticInitContainerIndex > 0 {
log.Warnf(`Init containers before the %s container may cause issues
if they interfere with volumes being restored: %s index %d`, restic.InitContainer, restic.InitContainer, resticInitContainerIndex)
}
log.Debug("Enqueueing")
c.enqueue(obj)
}
@@ -174,6 +180,12 @@ func (c *podVolumeRestoreController) podHandler(obj interface{}) {
return
}
resticInitContainerIndex := getResticInitContainerIndex(pod)
if resticInitContainerIndex > 0 {
log.Warnf(`Init containers before the %s container may cause issues
if they interfere with volumes being restored: %s index %d`, restic.InitContainer, restic.InitContainer, resticInitContainerIndex)
}
selector := labels.Set(map[string]string{
velerov1api.PodUIDLabel: string(pod.UID),
}).AsSelector()
@@ -208,18 +220,21 @@ func isPodOnNode(pod *corev1api.Pod, node string) bool {
}
func isResticInitContainerRunning(pod *corev1api.Pod) bool {
// no init containers, or the first one is not the velero restic one: return false
if len(pod.Spec.InitContainers) == 0 || pod.Spec.InitContainers[0].Name != restic.InitContainer {
return false
// Restic wait container can be anywhere in the list of init containers, but must be running.
i := getResticInitContainerIndex(pod)
return i >= 0 && pod.Status.InitContainerStatuses[i].State.Running != nil
}
func getResticInitContainerIndex(pod *corev1api.Pod) int {
// Restic wait container can be anywhere in the list of init containers so locate it.
for i, initContainer := range pod.Spec.InitContainers {
if initContainer.Name == restic.InitContainer {
return i
}
}
// status hasn't been created yet, or the first one is not yet running: return false
if len(pod.Status.InitContainerStatuses) == 0 || pod.Status.InitContainerStatuses[0].State.Running == nil {
return false
}
// else, it's running
return true
return -1
}
func (c *podVolumeRestoreController) processQueueItem(key string) error {

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 the Velero contributors.
Copyright 2020 the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -491,7 +491,7 @@ func TestIsResticContainerRunning(t *testing.T) {
expected: false,
},
{
name: "pod with running restic init container that's not first should return false",
name: "pod with running restic init container that's not first should still work",
pod: &corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns-1",
@@ -522,7 +522,7 @@ func TestIsResticContainerRunning(t *testing.T) {
},
},
},
expected: false,
expected: true,
},
{
name: "pod with restic init container as first initContainer that's not running should return false",
@@ -598,3 +598,105 @@ func TestIsResticContainerRunning(t *testing.T) {
})
}
}
func TestGetResticInitContainerIndex(t *testing.T) {
tests := []struct {
name string
pod *corev1api.Pod
expected int
}{
{
name: "init container is not present return -1",
pod: &corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns-1",
Name: "pod-1",
},
},
expected: -1,
},
{
name: "pod with no restic init container return -1",
pod: &corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns-1",
Name: "pod-1",
},
Spec: corev1api.PodSpec{
InitContainers: []corev1api.Container{
{
Name: "non-restic-init",
},
},
},
},
expected: -1,
},
{
name: "pod with restic container as second initContainern should return 1",
pod: &corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns-1",
Name: "pod-1",
},
Spec: corev1api.PodSpec{
InitContainers: []corev1api.Container{
{
Name: "non-restic-init",
},
{
Name: restic.InitContainer,
},
},
},
},
expected: 1,
},
{
name: "pod with restic init container as first initContainer should return 0",
pod: &corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns-1",
Name: "pod-1",
},
Spec: corev1api.PodSpec{
InitContainers: []corev1api.Container{
{
Name: restic.InitContainer,
},
{
Name: "non-restic-init",
},
},
},
},
expected: 0,
},
{
name: "pod with restic init container as first initContainer should return 0",
pod: &corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns-1",
Name: "pod-1",
},
Spec: corev1api.PodSpec{
InitContainers: []corev1api.Container{
{
Name: restic.InitContainer,
},
{
Name: "non-restic-init",
},
},
},
},
expected: 0,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.expected, getResticInitContainerIndex(test.pod))
})
}
}