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