mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-10-21 22:03:09 +00:00
BACKPORT-CONFLICT
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
committed by
github-actions[bot]
parent
882d409195
commit
757928ed76
@@ -335,7 +335,29 @@ func (p *pvcBackupItemAction) Execute(
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
vs, err := p.getVolumeSnapshotReference(context.TODO(), pvc, backup)
|
||||
=======
|
||||
// validate that the node-agent daemonset is ready when snapshot data movement with
|
||||
// the built-in data mover is requested. Without this, the DataUpload CR will be
|
||||
// created but never processed (the DataUpload controller runs inside node-agent),
|
||||
// causing the backup to hang until itemOperationTimeout expires.
|
||||
if boolptr.IsSetToTrue(backup.Spec.SnapshotMoveData) && datamover.IsBuiltInDataMover(backup.Spec.DataMover) {
|
||||
if err := nodeagent.IsReady(ctx, backup.Namespace, p.crClient); err != nil {
|
||||
p.log.WithError(err).Error("cannot perform snapshot data movement without running node-agent pods")
|
||||
return nil, nil, "", nil, errors.Wrap(err, "CSI PVC BIA cannot proceed: node-agent is not ready for snapshot data movement")
|
||||
}
|
||||
}
|
||||
|
||||
policySnapshotClass, scErr := vh.GetSnapshotClass(item, kuberesource.PersistentVolumeClaims)
|
||||
if scErr != nil {
|
||||
p.log.WithError(scErr).Warn("failed to get snapshotClass from volume policy, proceeding without it")
|
||||
} else if policySnapshotClass != "" {
|
||||
p.log.Infof("Volume policy specifies snapshotClass=%s for PVC %s/%s", policySnapshotClass, pvc.Namespace, pvc.Name)
|
||||
}
|
||||
|
||||
vs, err := p.getVolumeSnapshotReference(ctx, pvc, backup, policySnapshotClass)
|
||||
>>>>>>> 41687279a (fix node agent rediness check issue (#10397))
|
||||
if err != nil {
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
appsv1api "k8s.io/api/apps/v1"
|
||||
>>>>>>> 41687279a (fix node agent rediness check issue (#10397))
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -80,6 +84,39 @@ func KbClientIsRunningInNode(ctx context.Context, namespace string, nodeName str
|
||||
return isRunningInNode(ctx, namespace, nodeName, nil, kubeClient)
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
// IsReady checks whether the node-agent daemonset has at least one ready pod
|
||||
// by inspecting the DaemonSet status.
|
||||
func IsReady(ctx context.Context, namespace string, crClient ctrlclient.Client) error {
|
||||
dsLinux := new(appsv1api.DaemonSet)
|
||||
if err := crClient.Get(ctx, ctrlclient.ObjectKey{Namespace: namespace, Name: daemonSet}, dsLinux); err != nil {
|
||||
dsLinux = nil
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return errors.Wrap(err, "failed to get linux node-agent daemonset")
|
||||
}
|
||||
}
|
||||
|
||||
dsWindows := new(appsv1api.DaemonSet)
|
||||
if err := crClient.Get(ctx, ctrlclient.ObjectKey{Namespace: namespace, Name: daemonsetWindows}, dsWindows); err != nil {
|
||||
dsWindows = nil
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return errors.Wrap(err, "failed to get windows node-agent daemonset")
|
||||
}
|
||||
}
|
||||
|
||||
if dsLinux != nil && dsLinux.Status.NumberReady > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if dsWindows != nil && dsWindows.Status.NumberReady > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("node-agent is not ready: no ready pods found")
|
||||
}
|
||||
|
||||
>>>>>>> 41687279a (fix node agent rediness check issue (#10397))
|
||||
// IsRunningInNode checks if the node agent pod is running properly in a specified node through controller client. If not, return the error found
|
||||
func IsRunningInNode(ctx context.Context, namespace string, nodeName string, crClient ctrlclient.Client) error {
|
||||
return isRunningInNode(ctx, namespace, nodeName, crClient, nil)
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package nodeagent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
@@ -28,7 +29,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
clientTesting "k8s.io/client-go/testing"
|
||||
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
clientFake "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
velerotypes "github.com/vmware-tanzu/velero/pkg/types"
|
||||
@@ -213,6 +216,155 @@ func TestIsRunningInNode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
func TestIsReady(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
appsv1api.AddToScheme(scheme)
|
||||
|
||||
dsLinuxNotReady := &appsv1api.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "fake-ns", Name: "node-agent"},
|
||||
Status: appsv1api.DaemonSetStatus{NumberReady: 0},
|
||||
}
|
||||
dsLinuxReady := &appsv1api.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "fake-ns", Name: "node-agent"},
|
||||
Status: appsv1api.DaemonSetStatus{NumberReady: 3},
|
||||
}
|
||||
dsWindowsNotReady := &appsv1api.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "fake-ns", Name: "node-agent-windows"},
|
||||
Status: appsv1api.DaemonSetStatus{NumberReady: 0},
|
||||
}
|
||||
dsWindowsReady := &appsv1api.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "fake-ns", Name: "node-agent-windows"},
|
||||
Status: appsv1api.DaemonSetStatus{NumberReady: 2},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
kubeClientObj []runtime.Object
|
||||
namespace string
|
||||
interceptor *interceptor.Funcs
|
||||
expectErr string
|
||||
}{
|
||||
{
|
||||
name: "both daemonsets not found",
|
||||
namespace: "fake-ns",
|
||||
expectErr: "node-agent is not ready: no ready pods found",
|
||||
},
|
||||
{
|
||||
name: "linux daemonset get error",
|
||||
namespace: "fake-ns",
|
||||
interceptor: &interceptor.Funcs{
|
||||
Get: func(ctx context.Context, c ctrlclient.WithWatch, key ctrlclient.ObjectKey, obj ctrlclient.Object, opts ...ctrlclient.GetOption) error {
|
||||
if key.Name == "node-agent" {
|
||||
return errors.New("fake-get-error")
|
||||
}
|
||||
return c.Get(ctx, key, obj, opts...)
|
||||
},
|
||||
},
|
||||
expectErr: "failed to get linux node-agent daemonset: fake-get-error",
|
||||
},
|
||||
{
|
||||
name: "windows daemonset get error",
|
||||
namespace: "fake-ns",
|
||||
interceptor: &interceptor.Funcs{
|
||||
Get: func(ctx context.Context, c ctrlclient.WithWatch, key ctrlclient.ObjectKey, obj ctrlclient.Object, opts ...ctrlclient.GetOption) error {
|
||||
if key.Name == "node-agent-windows" {
|
||||
return errors.New("fake-get-error")
|
||||
}
|
||||
return c.Get(ctx, key, obj, opts...)
|
||||
},
|
||||
},
|
||||
expectErr: "failed to get windows node-agent daemonset: fake-get-error",
|
||||
},
|
||||
{
|
||||
name: "linux ds exist but no ready pods",
|
||||
namespace: "fake-ns",
|
||||
kubeClientObj: []runtime.Object{
|
||||
dsLinuxNotReady,
|
||||
},
|
||||
expectErr: "node-agent is not ready: no ready pods found",
|
||||
},
|
||||
{
|
||||
name: "linux ds with ready pods",
|
||||
namespace: "fake-ns",
|
||||
kubeClientObj: []runtime.Object{
|
||||
dsLinuxReady,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "windows ds exist but no ready pods",
|
||||
namespace: "fake-ns",
|
||||
kubeClientObj: []runtime.Object{
|
||||
dsWindowsNotReady,
|
||||
},
|
||||
expectErr: "node-agent is not ready: no ready pods found",
|
||||
},
|
||||
{
|
||||
name: "windows ds with ready pods",
|
||||
namespace: "fake-ns",
|
||||
kubeClientObj: []runtime.Object{
|
||||
dsWindowsReady,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "both daemonsets exist but no ready pods",
|
||||
namespace: "fake-ns",
|
||||
kubeClientObj: []runtime.Object{
|
||||
dsLinuxNotReady,
|
||||
dsWindowsNotReady,
|
||||
},
|
||||
expectErr: "node-agent is not ready: no ready pods found",
|
||||
},
|
||||
{
|
||||
name: "both daemonsets exist, linux ready",
|
||||
namespace: "fake-ns",
|
||||
kubeClientObj: []runtime.Object{
|
||||
dsLinuxReady,
|
||||
dsWindowsNotReady,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "both daemonsets exist, windows ready",
|
||||
namespace: "fake-ns",
|
||||
kubeClientObj: []runtime.Object{
|
||||
dsLinuxNotReady,
|
||||
dsWindowsReady,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "both daemonsets exist, both ready",
|
||||
namespace: "fake-ns",
|
||||
kubeClientObj: []runtime.Object{
|
||||
dsLinuxReady,
|
||||
dsWindowsReady,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
builder := clientFake.NewClientBuilder().
|
||||
WithScheme(scheme).
|
||||
WithRuntimeObjects(test.kubeClientObj...)
|
||||
|
||||
if test.interceptor != nil {
|
||||
builder = builder.WithInterceptorFuncs(*test.interceptor)
|
||||
}
|
||||
|
||||
fakeClient := builder.Build()
|
||||
|
||||
err := IsReady(t.Context(), test.namespace, fakeClient)
|
||||
if test.expectErr == "" {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.ErrorContains(t, err, test.expectErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
>>>>>>> 41687279a (fix node agent rediness check issue (#10397))
|
||||
func TestGetPodSpec(t *testing.T) {
|
||||
podSpec := corev1api.PodSpec{
|
||||
NodeName: "fake-node",
|
||||
|
||||
Reference in New Issue
Block a user