...

Source file src/k8s.io/kubernetes/test/e2e/framework/service/resource.go

Documentation: k8s.io/kubernetes/test/e2e/framework/service

     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 service
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"time"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/labels"
    28  	"k8s.io/apimachinery/pkg/util/intstr"
    29  	clientset "k8s.io/client-go/kubernetes"
    30  	restclient "k8s.io/client-go/rest"
    31  	"k8s.io/kubernetes/test/e2e/framework"
    32  	e2enode "k8s.io/kubernetes/test/e2e/framework/node"
    33  	testutils "k8s.io/kubernetes/test/utils"
    34  )
    35  
    36  // GetServicesProxyRequest returns a request for a service proxy.
    37  func GetServicesProxyRequest(c clientset.Interface, request *restclient.Request) (*restclient.Request, error) {
    38  	return request.Resource("services").SubResource("proxy"), nil
    39  }
    40  
    41  // CreateServiceSpec returns a Service object for testing.
    42  func CreateServiceSpec(serviceName, externalName string, isHeadless bool, selector map[string]string) *v1.Service {
    43  	headlessService := &v1.Service{
    44  		ObjectMeta: metav1.ObjectMeta{
    45  			Name: serviceName,
    46  		},
    47  		Spec: v1.ServiceSpec{
    48  			Selector: selector,
    49  		},
    50  	}
    51  	if externalName != "" {
    52  		headlessService.Spec.Type = v1.ServiceTypeExternalName
    53  		headlessService.Spec.ExternalName = externalName
    54  	} else {
    55  		headlessService.Spec.Ports = []v1.ServicePort{
    56  			{Port: 80, Name: "http", Protocol: v1.ProtocolTCP},
    57  		}
    58  	}
    59  	if isHeadless {
    60  		headlessService.Spec.ClusterIP = "None"
    61  	}
    62  	return headlessService
    63  }
    64  
    65  // UpdateService fetches a service, calls the update function on it,
    66  // and then attempts to send the updated service. It retries up to 2
    67  // times in the face of timeouts and conflicts.
    68  func UpdateService(ctx context.Context, c clientset.Interface, namespace, serviceName string, update func(*v1.Service)) (*v1.Service, error) {
    69  	var service *v1.Service
    70  	var err error
    71  	for i := 0; i < 3; i++ {
    72  		service, err = c.CoreV1().Services(namespace).Get(ctx, serviceName, metav1.GetOptions{})
    73  		if err != nil {
    74  			return service, err
    75  		}
    76  
    77  		update(service)
    78  
    79  		service, err = c.CoreV1().Services(namespace).Update(ctx, service, metav1.UpdateOptions{})
    80  
    81  		if !apierrors.IsConflict(err) && !apierrors.IsServerTimeout(err) {
    82  			return service, err
    83  		}
    84  	}
    85  	return service, err
    86  }
    87  
    88  // CleanupServiceResources cleans up service Type=LoadBalancer resources.
    89  func CleanupServiceResources(ctx context.Context, c clientset.Interface, loadBalancerName, region, zone string) {
    90  	framework.TestContext.CloudConfig.Provider.CleanupServiceResources(ctx, c, loadBalancerName, region, zone)
    91  }
    92  
    93  // GetIngressPoint returns a host on which ingress serves.
    94  func GetIngressPoint(ing *v1.LoadBalancerIngress) string {
    95  	host := ing.IP
    96  	if host == "" {
    97  		host = ing.Hostname
    98  	}
    99  	return host
   100  }
   101  
   102  // GetServiceLoadBalancerCreationTimeout returns a timeout value for creating a load balancer of a service.
   103  func GetServiceLoadBalancerCreationTimeout(ctx context.Context, cs clientset.Interface) time.Duration {
   104  	nodes, err := e2enode.GetReadySchedulableNodes(ctx, cs)
   105  	framework.ExpectNoError(err)
   106  	if len(nodes.Items) > LargeClusterMinNodesNumber {
   107  		return loadBalancerCreateTimeoutLarge
   108  	}
   109  	return loadBalancerCreateTimeoutDefault
   110  }
   111  
   112  // GetServiceLoadBalancerPropagationTimeout returns a timeout value for propagating a load balancer of a service.
   113  func GetServiceLoadBalancerPropagationTimeout(ctx context.Context, cs clientset.Interface) time.Duration {
   114  	nodes, err := e2enode.GetReadySchedulableNodes(ctx, cs)
   115  	framework.ExpectNoError(err)
   116  	if len(nodes.Items) > LargeClusterMinNodesNumber {
   117  		return loadBalancerPropagationTimeoutLarge
   118  	}
   119  	return loadBalancerPropagationTimeoutDefault
   120  }
   121  
   122  // CreateServiceForSimpleAppWithPods is a convenience wrapper to create a service and its matching pods all at once.
   123  func CreateServiceForSimpleAppWithPods(ctx context.Context, c clientset.Interface, contPort int, svcPort int, namespace, appName string, podSpec func(n v1.Node) v1.PodSpec, count int, block bool) (*v1.Service, error) {
   124  	var err error
   125  	theService := CreateServiceForSimpleApp(ctx, c, contPort, svcPort, namespace, appName)
   126  	e2enode.CreatePodsPerNodeForSimpleApp(ctx, c, namespace, appName, podSpec, count)
   127  	if block {
   128  		err = testutils.WaitForPodsWithLabelRunning(c, namespace, labels.SelectorFromSet(labels.Set(theService.Spec.Selector)))
   129  	}
   130  	return theService, err
   131  }
   132  
   133  // CreateServiceForSimpleApp returns a service that selects/exposes pods (send -1 ports if no exposure needed) with an app label.
   134  func CreateServiceForSimpleApp(ctx context.Context, c clientset.Interface, contPort, svcPort int, namespace, appName string) *v1.Service {
   135  	if appName == "" {
   136  		panic(fmt.Sprintf("no app name provided"))
   137  	}
   138  
   139  	serviceSelector := map[string]string{
   140  		"app": appName + "-pod",
   141  	}
   142  
   143  	// For convenience, user sending ports are optional.
   144  	portsFunc := func() []v1.ServicePort {
   145  		if contPort < 1 || svcPort < 1 {
   146  			return nil
   147  		}
   148  		return []v1.ServicePort{{
   149  			Protocol:   v1.ProtocolTCP,
   150  			Port:       int32(svcPort),
   151  			TargetPort: intstr.FromInt32(int32(contPort)),
   152  		}}
   153  	}
   154  	framework.Logf("Creating a service-for-%v for selecting app=%v-pod", appName, appName)
   155  	service, err := c.CoreV1().Services(namespace).Create(ctx, &v1.Service{
   156  		ObjectMeta: metav1.ObjectMeta{
   157  			Name: "service-for-" + appName,
   158  			Labels: map[string]string{
   159  				"app": appName + "-service",
   160  			},
   161  		},
   162  		Spec: v1.ServiceSpec{
   163  			Ports:    portsFunc(),
   164  			Selector: serviceSelector,
   165  		},
   166  	}, metav1.CreateOptions{})
   167  	framework.ExpectNoError(err)
   168  	return service
   169  }
   170  

View as plain text