github.skymusic.top/operator-framework/operator-sdk@v0.8.2/pkg/test/e2eutil/wait_util.go (about)

     1  // Copyright 2018 The Operator-SDK Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package e2eutil
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/operator-framework/operator-sdk/pkg/test"
    23  
    24  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apimachinery/pkg/util/wait"
    28  	"k8s.io/client-go/kubernetes"
    29  	"sigs.k8s.io/controller-runtime/pkg/client"
    30  )
    31  
    32  // WaitForDeployment checks to see if a given deployment has a certain number of available replicas after a specified amount of time
    33  // If the deployment does not have the required number of replicas after 5 * retries seconds, the function returns an error
    34  // This can be used in multiple ways, like verifying that a required resource is ready before trying to use it, or to test
    35  // failure handling, like simulated in SimulatePodFail.
    36  func WaitForDeployment(t *testing.T, kubeclient kubernetes.Interface, namespace, name string, replicas int, retryInterval, timeout time.Duration) error {
    37  	return waitForDeployment(t, kubeclient, namespace, name, replicas, retryInterval, timeout, false)
    38  }
    39  
    40  // WaitForOperatorDeployment has the same functionality as WaitForDeployment but will no wait for the deployment if the
    41  // test was run with a locally run operator (--up-local flag)
    42  func WaitForOperatorDeployment(t *testing.T, kubeclient kubernetes.Interface, namespace, name string, replicas int, retryInterval, timeout time.Duration) error {
    43  	return waitForDeployment(t, kubeclient, namespace, name, replicas, retryInterval, timeout, true)
    44  }
    45  
    46  func waitForDeployment(t *testing.T, kubeclient kubernetes.Interface, namespace, name string, replicas int, retryInterval, timeout time.Duration, isOperator bool) error {
    47  	if isOperator && test.Global.LocalOperator {
    48  		t.Log("Operator is running locally; skip waitForDeployment")
    49  		return nil
    50  	}
    51  	err := wait.Poll(retryInterval, timeout, func() (done bool, err error) {
    52  		deployment, err := kubeclient.AppsV1().Deployments(namespace).Get(name, metav1.GetOptions{IncludeUninitialized: true})
    53  		if err != nil {
    54  			if apierrors.IsNotFound(err) {
    55  				t.Logf("Waiting for availability of %s deployment\n", name)
    56  				return false, nil
    57  			}
    58  			return false, err
    59  		}
    60  
    61  		if int(deployment.Status.AvailableReplicas) == replicas {
    62  			return true, nil
    63  		}
    64  		t.Logf("Waiting for full availability of %s deployment (%d/%d)\n", name, deployment.Status.AvailableReplicas, replicas)
    65  		return false, nil
    66  	})
    67  	if err != nil {
    68  		return err
    69  	}
    70  	t.Logf("Deployment available (%d/%d)\n", replicas, replicas)
    71  	return nil
    72  }
    73  
    74  func WaitForDeletion(t *testing.T, dynclient client.Client, obj runtime.Object, retryInterval, timeout time.Duration) error {
    75  	key, err := client.ObjectKeyFromObject(obj)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	kind := obj.GetObjectKind().GroupVersionKind().Kind
    81  	ctx, cancel := context.WithTimeout(context.Background(), timeout)
    82  	defer cancel()
    83  	err = wait.Poll(retryInterval, timeout, func() (done bool, err error) {
    84  		err = dynclient.Get(ctx, key, obj)
    85  		if apierrors.IsNotFound(err) {
    86  			return true, nil
    87  		}
    88  		if err != nil {
    89  			return false, err
    90  		}
    91  		t.Logf("Waiting for %s %s to be deleted\n", kind, key)
    92  		return false, nil
    93  	})
    94  	if err != nil {
    95  		return err
    96  	}
    97  	t.Logf("%s %s was deleted\n", kind, key)
    98  	return nil
    99  }