1/*
2Copyright 2019 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package service
18
19import (
20	"context"
21	"fmt"
22
23	apierrors "k8s.io/apimachinery/pkg/api/errors"
24	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25	"k8s.io/apimachinery/pkg/util/wait"
26	clientset "k8s.io/client-go/kubernetes"
27	servicehelper "k8s.io/cloud-provider/service/helpers"
28	"k8s.io/kubernetes/test/e2e/framework"
29
30	"github.com/onsi/ginkgo"
31)
32
33// WaitForServiceDeletedWithFinalizer waits for the service with finalizer to be deleted.
34func WaitForServiceDeletedWithFinalizer(cs clientset.Interface, namespace, name string) {
35	ginkgo.By("Delete service with finalizer")
36	if err := cs.CoreV1().Services(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil {
37		framework.Failf("Failed to delete service %s/%s", namespace, name)
38	}
39
40	ginkgo.By("Wait for service to disappear")
41	if pollErr := wait.PollImmediate(LoadBalancerPollInterval, GetServiceLoadBalancerCreationTimeout(cs), func() (bool, error) {
42		svc, err := cs.CoreV1().Services(namespace).Get(context.TODO(), name, metav1.GetOptions{})
43		if err != nil {
44			if apierrors.IsNotFound(err) {
45				framework.Logf("Service %s/%s is gone.", namespace, name)
46				return true, nil
47			}
48			return false, err
49		}
50		framework.Logf("Service %s/%s still exists with finalizers: %v", namespace, name, svc.Finalizers)
51		return false, nil
52	}); pollErr != nil {
53		framework.Failf("Failed to wait for service to disappear: %v", pollErr)
54	}
55}
56
57// WaitForServiceUpdatedWithFinalizer waits for the service to be updated to have or
58// don't have a finalizer.
59func WaitForServiceUpdatedWithFinalizer(cs clientset.Interface, namespace, name string, hasFinalizer bool) {
60	ginkgo.By(fmt.Sprintf("Wait for service to hasFinalizer=%t", hasFinalizer))
61	if pollErr := wait.PollImmediate(LoadBalancerPollInterval, GetServiceLoadBalancerCreationTimeout(cs), func() (bool, error) {
62		svc, err := cs.CoreV1().Services(namespace).Get(context.TODO(), name, metav1.GetOptions{})
63		if err != nil {
64			return false, err
65		}
66		foundFinalizer := false
67		for _, finalizer := range svc.Finalizers {
68			if finalizer == servicehelper.LoadBalancerCleanupFinalizer {
69				foundFinalizer = true
70				break
71			}
72		}
73		if foundFinalizer != hasFinalizer {
74			framework.Logf("Service %s/%s hasFinalizer=%t, want %t", namespace, name, foundFinalizer, hasFinalizer)
75			return false, nil
76		}
77		return true, nil
78	}); pollErr != nil {
79		framework.Failf("Failed to wait for service to hasFinalizer=%t: %v", hasFinalizer, pollErr)
80	}
81}
82