k8s.io/kubernetes@v1.29.3/test/e2e/network/fixture.go (about)

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package network
    18  
    19  import (
    20  	"context"
    21  
    22  	v1 "k8s.io/api/core/v1"
    23  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/util/intstr"
    26  	"k8s.io/apimachinery/pkg/util/uuid"
    27  	clientset "k8s.io/client-go/kubernetes"
    28  	"k8s.io/client-go/util/retry"
    29  	imageutils "k8s.io/kubernetes/test/utils/image"
    30  
    31  	"github.com/onsi/ginkgo/v2"
    32  )
    33  
    34  // TestFixture is a simple helper class to avoid too much boilerplate in tests
    35  type TestFixture struct {
    36  	ServiceName string
    37  	Namespace   string
    38  	Client      clientset.Interface
    39  
    40  	TestID string
    41  	Labels map[string]string
    42  
    43  	rcs      map[string]bool
    44  	services map[string]bool
    45  	Name     string
    46  	Image    string
    47  }
    48  
    49  // NewServerTest creates a new TestFixture for the tests.
    50  func NewServerTest(client clientset.Interface, namespace string, serviceName string) *TestFixture {
    51  	t := &TestFixture{}
    52  	t.Client = client
    53  	t.Namespace = namespace
    54  	t.ServiceName = serviceName
    55  	t.TestID = t.ServiceName + "-" + string(uuid.NewUUID())
    56  	t.Labels = map[string]string{
    57  		"testid": t.TestID,
    58  	}
    59  
    60  	t.rcs = make(map[string]bool)
    61  	t.services = make(map[string]bool)
    62  
    63  	t.Name = "webserver"
    64  	t.Image = imageutils.GetE2EImage(imageutils.Agnhost)
    65  
    66  	return t
    67  }
    68  
    69  // BuildServiceSpec builds default config for a service (which can then be changed)
    70  func (t *TestFixture) BuildServiceSpec() *v1.Service {
    71  	service := &v1.Service{
    72  		ObjectMeta: metav1.ObjectMeta{
    73  			Name:      t.ServiceName,
    74  			Namespace: t.Namespace,
    75  		},
    76  		Spec: v1.ServiceSpec{
    77  			Selector: t.Labels,
    78  			Ports: []v1.ServicePort{{
    79  				Port:       80,
    80  				TargetPort: intstr.FromInt32(80),
    81  			}},
    82  		},
    83  	}
    84  	return service
    85  }
    86  
    87  // CreateRC creates a replication controller and records it for cleanup.
    88  func (t *TestFixture) CreateRC(rc *v1.ReplicationController) (*v1.ReplicationController, error) {
    89  	rc, err := t.Client.CoreV1().ReplicationControllers(t.Namespace).Create(context.TODO(), rc, metav1.CreateOptions{})
    90  	if err == nil {
    91  		t.rcs[rc.Name] = true
    92  	}
    93  	return rc, err
    94  }
    95  
    96  // CreateService creates a service, and record it for cleanup
    97  func (t *TestFixture) CreateService(service *v1.Service) (*v1.Service, error) {
    98  	result, err := t.Client.CoreV1().Services(t.Namespace).Create(context.TODO(), service, metav1.CreateOptions{})
    99  	if err == nil {
   100  		t.services[service.Name] = true
   101  	}
   102  	return result, err
   103  }
   104  
   105  // DeleteService deletes a service, and remove it from the cleanup list
   106  func (t *TestFixture) DeleteService(serviceName string) error {
   107  	err := t.Client.CoreV1().Services(t.Namespace).Delete(context.TODO(), serviceName, metav1.DeleteOptions{})
   108  	if err == nil {
   109  		delete(t.services, serviceName)
   110  	}
   111  	return err
   112  }
   113  
   114  // Cleanup cleans all ReplicationControllers and Services which this object holds.
   115  func (t *TestFixture) Cleanup() []error {
   116  	var errs []error
   117  	for rcName := range t.rcs {
   118  		ginkgo.By("stopping RC " + rcName + " in namespace " + t.Namespace)
   119  		err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
   120  			// First, resize the RC to 0.
   121  			old, err := t.Client.CoreV1().ReplicationControllers(t.Namespace).Get(context.TODO(), rcName, metav1.GetOptions{})
   122  			if err != nil {
   123  				if apierrors.IsNotFound(err) {
   124  					return nil
   125  				}
   126  				return err
   127  			}
   128  			x := int32(0)
   129  			old.Spec.Replicas = &x
   130  			if _, err := t.Client.CoreV1().ReplicationControllers(t.Namespace).Update(context.TODO(), old, metav1.UpdateOptions{}); err != nil {
   131  				if apierrors.IsNotFound(err) {
   132  					return nil
   133  				}
   134  				return err
   135  			}
   136  			return nil
   137  		})
   138  		if err != nil {
   139  			errs = append(errs, err)
   140  		}
   141  		// TODO(mikedanese): Wait.
   142  		// Then, delete the RC altogether.
   143  		if err := t.Client.CoreV1().ReplicationControllers(t.Namespace).Delete(context.TODO(), rcName, metav1.DeleteOptions{}); err != nil {
   144  			if !apierrors.IsNotFound(err) {
   145  				errs = append(errs, err)
   146  			}
   147  		}
   148  	}
   149  
   150  	for serviceName := range t.services {
   151  		ginkgo.By("deleting service " + serviceName + " in namespace " + t.Namespace)
   152  		err := t.Client.CoreV1().Services(t.Namespace).Delete(context.TODO(), serviceName, metav1.DeleteOptions{})
   153  		if err != nil {
   154  			if !apierrors.IsNotFound(err) {
   155  				errs = append(errs, err)
   156  			}
   157  		}
   158  	}
   159  
   160  	return errs
   161  }