Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added caching for namespace status check in restore path #8219

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 66 additions & 39 deletions pkg/util/kube/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"context"
"fmt"
"strings"
"sync"
"time"

"github.com/pkg/errors"
Expand Down Expand Up @@ -56,6 +57,12 @@

var ErrorPodVolumeIsNotPVC = errors.New("pod volume is not a PVC")

// Declare a global set to hold the namespace names which are present in the polling set to avoid polling for multiple resources
var (
IsNameSpacePresentInPollingSet map[string]string
pollingSetLock sync.Mutex
)

// NamespaceAndName returns a string in the format <namespace>/<name>
func NamespaceAndName(objMeta metav1.Object) string {
if objMeta.GetNamespace() == "" {
Expand All @@ -79,54 +86,74 @@
// required for keeping track of number of restored items
// if namespace is marked for deletion, and we timed out, report an error
var terminatingNamespace bool
err = wait.PollUntilContextTimeout(context.Background(), time.Second, timeout, true, func(ctx context.Context) (bool, error) {
clusterNS, err := client.Get(ctx, namespace.Name, metav1.GetOptions{})
// if namespace is marked for deletion, and we timed out, report an error

if apierrors.IsNotFound(err) {
// Namespace isn't in cluster, we're good to create.
return true, nil
}
if IsNameSpacePresentInPollingSet == nil {
IsNameSpacePresentInPollingSet = make(map[string]string)
}

if err != nil {
// Return the err and exit the loop.
return true, err
}
// Lock the mutex before accessing the map
pollingSetLock.Lock()
// Check if the namespace is already present in the polling set. If namespace already in polling set skip the entire function

if clusterNS != nil && (clusterNS.GetDeletionTimestamp() != nil || clusterNS.Status.Phase == corev1api.NamespaceTerminating) {
// Marked for deletion, keep waiting
terminatingNamespace = true
return false, nil
}
if _, exists := IsNameSpacePresentInPollingSet[namespace.Name]; exists {
pollingSetLock.Unlock()
return false, nsCreated, errors.Errorf("namespace %s is already present in the polling set to skipping", namespace.Name)

Check warning on line 100 in pkg/util/kube/utils.go

View check run for this annotation

Codecov / codecov/patch

pkg/util/kube/utils.go#L99-L100

Added lines #L99 - L100 were not covered by tests
} else {

Check failure on line 101 in pkg/util/kube/utils.go

View workflow job for this annotation

GitHub Actions / Run Linter Check

unnecessary leading newline (whitespace)

// clusterNS found, is not nil, and not marked for deletion, therefore we shouldn't create it.
ready = true
return true, nil
})
// Added the namespace to the polling set
IsNameSpacePresentInPollingSet[namespace.Name] = namespace.Name
pollingSetLock.Unlock()
err = wait.PollUntilContextTimeout(context.Background(), time.Second, timeout, true, func(ctx context.Context) (bool, error) {
clusterNS, err := client.Get(ctx, namespace.Name, metav1.GetOptions{})
// if namespace is marked for deletion, and we timed out, report an error

// err will be set if we timed out or encountered issues retrieving the namespace,
if err != nil {
if terminatingNamespace {
return false, nsCreated, errors.Wrapf(err, "timed out waiting for terminating namespace %s to disappear before restoring", namespace.Name)
if apierrors.IsNotFound(err) {
// Namespace isn't in cluster, we're good to create.
return true, nil
}

if err != nil {
// Return the err and exit the loop.
return true, err

Check warning on line 117 in pkg/util/kube/utils.go

View check run for this annotation

Codecov / codecov/patch

pkg/util/kube/utils.go#L117

Added line #L117 was not covered by tests
}

if clusterNS != nil && (clusterNS.GetDeletionTimestamp() != nil || clusterNS.Status.Phase == corev1api.NamespaceTerminating) {
// Marked for deletion, keep waiting
terminatingNamespace = true
return false, nil
}

// clusterNS found, is not nil, and not marked for deletion, therefore we shouldn't create it.
ready = true
return true, nil
})
pollingSetLock.Lock()
delete(IsNameSpacePresentInPollingSet, namespace.Name)
pollingSetLock.Unlock()
// err will be set if we timed out or encountered issues retrieving the namespace,
if err != nil {
if terminatingNamespace {
return false, nsCreated, errors.Wrapf(err, "timed out waiting for terminating namespace %s to disappear before restoring", namespace.Name)
}
return false, nsCreated, errors.Wrapf(err, "error getting namespace %s", namespace.Name)

Check warning on line 138 in pkg/util/kube/utils.go

View check run for this annotation

Codecov / codecov/patch

pkg/util/kube/utils.go#L138

Added line #L138 was not covered by tests
}
return false, nsCreated, errors.Wrapf(err, "error getting namespace %s", namespace.Name)
}

// In the case the namespace already exists and isn't marked for deletion, assume it's ready for use.
if ready {
return true, nsCreated, nil
}
// In the case the namespace already exists and isn't marked for deletion, assume it's ready for use.
if ready {
return true, nsCreated, nil
}

clusterNS, err := client.Create(context.TODO(), namespace, metav1.CreateOptions{})
if apierrors.IsAlreadyExists(err) {
if clusterNS != nil && (clusterNS.GetDeletionTimestamp() != nil || clusterNS.Status.Phase == corev1api.NamespaceTerminating) {
// Somehow created after all our polling and marked for deletion, return an error
return false, nsCreated, errors.Errorf("namespace %s created and marked for termination after timeout", namespace.Name)
clusterNS, err := client.Create(context.TODO(), namespace, metav1.CreateOptions{})
if apierrors.IsAlreadyExists(err) {
if clusterNS != nil && (clusterNS.GetDeletionTimestamp() != nil || clusterNS.Status.Phase == corev1api.NamespaceTerminating) {
// Somehow created after all our polling and marked for deletion, return an error
return false, nsCreated, errors.Errorf("namespace %s created and marked for termination after timeout", namespace.Name)
}
} else if err != nil {
return false, nsCreated, errors.Wrapf(err, "error creating namespace %s", namespace.Name)

Check warning on line 153 in pkg/util/kube/utils.go

View check run for this annotation

Codecov / codecov/patch

pkg/util/kube/utils.go#L153

Added line #L153 was not covered by tests
} else {
nsCreated = true
}
} else if err != nil {
return false, nsCreated, errors.Wrapf(err, "error creating namespace %s", namespace.Name)
} else {
nsCreated = true
}

// The namespace created successfully
Expand Down
Loading