k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e_node/services/apiserver.go (about)

     1  /*
     2  Copyright 2016 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 services
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"os"
    24  	"testing"
    25  
    26  	utiltesting "k8s.io/client-go/util/testing"
    27  
    28  	"k8s.io/apiserver/pkg/storage/storagebackend"
    29  	netutils "k8s.io/utils/net"
    30  
    31  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    32  	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
    33  	"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
    34  	"k8s.io/kubernetes/test/e2e/framework"
    35  )
    36  
    37  const (
    38  	clusterIPRange = "10.0.0.1/24"
    39  	// This key is for testing purposes only and is not considered secure.
    40  	ecdsaPrivateKey = `-----BEGIN EC PRIVATE KEY-----
    41  MHcCAQEEIEZmTmUhuanLjPA2CLquXivuwBDHTt5XYwgIr/kA1LtRoAoGCCqGSM49
    42  AwEHoUQDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPLX2i8uIp/C/ASqiIGUeeKQtX0
    43  /IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg==
    44  -----END EC PRIVATE KEY-----`
    45  )
    46  
    47  // APIServer is a server which manages apiserver.
    48  type APIServer struct {
    49  	storageConfig storagebackend.Config
    50  	cancel        func(error)
    51  }
    52  
    53  // NewAPIServer creates an apiserver.
    54  func NewAPIServer(storageConfig storagebackend.Config) *APIServer {
    55  	return &APIServer{
    56  		storageConfig: storageConfig,
    57  	}
    58  }
    59  
    60  // Start starts the apiserver, returns when apiserver is ready.
    61  // The background goroutine runs until the context is canceled
    62  // or Stop is called, whether happens first.
    63  func (a *APIServer) Start(ctx context.Context) error {
    64  	const tokenFilePath = "known_tokens.csv"
    65  
    66  	o := options.NewServerRunOptions()
    67  	o.Etcd.StorageConfig = a.storageConfig
    68  	_, ipnet, err := netutils.ParseCIDRSloppy(clusterIPRange)
    69  	if err != nil {
    70  		return err
    71  	}
    72  	if len(framework.TestContext.RuntimeConfig) > 0 {
    73  		o.APIEnablement.RuntimeConfig = framework.TestContext.RuntimeConfig
    74  	}
    75  	o.SecureServing.BindAddress = netutils.ParseIPSloppy("127.0.0.1")
    76  	o.ServiceClusterIPRanges = ipnet.String()
    77  	o.AllowPrivileged = true
    78  	if err := generateTokenFile(tokenFilePath); err != nil {
    79  		return fmt.Errorf("failed to generate token file %s: %w", tokenFilePath, err)
    80  	}
    81  	o.Authentication.TokenFile.TokenFile = tokenFilePath
    82  	o.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount", "TaintNodesByCondition"}
    83  
    84  	saSigningKeyFile, err := os.CreateTemp("/tmp", "insecure_test_key")
    85  	if err != nil {
    86  		return fmt.Errorf("create temp file failed: %w", err)
    87  	}
    88  	defer utiltesting.CloseAndRemove(&testing.T{}, saSigningKeyFile)
    89  	if err = os.WriteFile(saSigningKeyFile.Name(), []byte(ecdsaPrivateKey), 0666); err != nil {
    90  		return fmt.Errorf("write file %s failed: %w", saSigningKeyFile.Name(), err)
    91  	}
    92  	o.ServiceAccountSigningKeyFile = saSigningKeyFile.Name()
    93  	o.Authentication.APIAudiences = []string{"https://foo.bar.example.com"}
    94  	o.Authentication.ServiceAccounts.Issuers = []string{"https://foo.bar.example.com"}
    95  	o.Authentication.ServiceAccounts.KeyFiles = []string{saSigningKeyFile.Name()}
    96  
    97  	o.KubeletConfig.PreferredAddressTypes = []string{"InternalIP"}
    98  
    99  	ctx, cancel := context.WithCancelCause(ctx)
   100  	a.cancel = cancel
   101  	errCh := make(chan error)
   102  	go func() {
   103  		defer close(errCh)
   104  		defer cancel(errors.New("shutting down")) // Calling Stop is optional, but cancel always should be invoked.
   105  		completedOptions, err := o.Complete()
   106  		if err != nil {
   107  			errCh <- fmt.Errorf("set apiserver default options error: %w", err)
   108  			return
   109  		}
   110  		if errs := completedOptions.Validate(); len(errs) != 0 {
   111  			errCh <- fmt.Errorf("failed to validate ServerRunOptions: %v", utilerrors.NewAggregate(errs))
   112  			return
   113  		}
   114  
   115  		err = apiserver.Run(ctx, completedOptions)
   116  		if err != nil {
   117  			errCh <- fmt.Errorf("run apiserver error: %w", err)
   118  			return
   119  		}
   120  	}()
   121  
   122  	err = readinessCheck("apiserver", []string{getAPIServerHealthCheckURL()}, errCh)
   123  	if err != nil {
   124  		return err
   125  	}
   126  	return nil
   127  }
   128  
   129  // Stop stops the apiserver. Does not block.
   130  func (a *APIServer) Stop() error {
   131  	// nil when Start has never been called.
   132  	if a.cancel != nil {
   133  		a.cancel(errors.New("stopping API server"))
   134  	}
   135  	return nil
   136  }
   137  
   138  const apiserverName = "apiserver"
   139  
   140  // Name returns the name of APIServer.
   141  func (a *APIServer) Name() string {
   142  	return apiserverName
   143  }
   144  
   145  func getAPIServerClientURL() string {
   146  	return framework.TestContext.Host
   147  }
   148  
   149  func getAPIServerHealthCheckURL() string {
   150  	return framework.TestContext.Host + "/healthz"
   151  }
   152  
   153  func generateTokenFile(tokenFilePath string) error {
   154  	tokenFile := fmt.Sprintf("%s,kubelet,uid,system:masters\n", framework.TestContext.BearerToken)
   155  	return os.WriteFile(tokenFilePath, []byte(tokenFile), 0644)
   156  }