mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-20 02:11:09 +00:00
refactor: migrate node e2e tests off insecure port
Signed-off-by: knight42 <anonymousknight96@gmail.com>
This commit is contained in:
parent
2046f4212a
commit
d321ac52a2
@ -75,7 +75,7 @@ func pollConfigz(timeout time.Duration, pollInterval time.Duration, nodeName, na
|
||||
framework.Logf("http requesting node kubelet /configz")
|
||||
endpoint = fmt.Sprintf("http://127.0.0.1:%d/api/v1/nodes/%s/proxy/configz", port, nodeName)
|
||||
} else {
|
||||
endpoint = fmt.Sprintf("http://127.0.0.1:8080/api/v1/nodes/%s/proxy/configz", framework.TestContext.NodeName)
|
||||
endpoint = fmt.Sprintf("%s/api/v1/nodes/%s/proxy/configz", framework.TestContext.Host, framework.TestContext.NodeName)
|
||||
}
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
@ -83,10 +83,13 @@ func pollConfigz(timeout time.Duration, pollInterval time.Duration, nodeName, na
|
||||
client := &http.Client{Transport: tr}
|
||||
req, err := http.NewRequest("GET", endpoint, nil)
|
||||
framework.ExpectNoError(err)
|
||||
if !useProxy {
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", framework.TestContext.BearerToken))
|
||||
}
|
||||
req.Header.Add("Accept", "application/json")
|
||||
|
||||
var resp *http.Response
|
||||
wait.PollImmediate(pollInterval, timeout, func() (bool, error) {
|
||||
err = wait.PollImmediate(pollInterval, timeout, func() (bool, error) {
|
||||
resp, err = client.Do(req)
|
||||
if err != nil {
|
||||
framework.Logf("Failed to get /configz, retrying. Error: %v", err)
|
||||
@ -99,6 +102,7 @@ func pollConfigz(timeout time.Duration, pollInterval time.Duration, nodeName, na
|
||||
|
||||
return true, nil
|
||||
})
|
||||
framework.ExpectNoError(err, "Failed to get successful response from /configz")
|
||||
return resp
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,12 @@ limitations under the License.
|
||||
package framework
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
@ -32,11 +35,12 @@ import (
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultHost = "http://127.0.0.1:8080"
|
||||
defaultHost = "https://127.0.0.1:6443"
|
||||
|
||||
// DefaultNumNodes is the number of nodes. If not specified, then number of nodes is auto-detected
|
||||
DefaultNumNodes = -1
|
||||
@ -77,6 +81,7 @@ type TestContextType struct {
|
||||
KubeVolumeDir string
|
||||
CertDir string
|
||||
Host string
|
||||
BearerToken string
|
||||
// TODO: Deprecating this over time... instead just use gobindata_util.go , see #23987.
|
||||
RepoRoot string
|
||||
DockershimCheckpointDir string
|
||||
@ -286,7 +291,7 @@ func RegisterCommonFlags(flags *flag.FlagSet) {
|
||||
flags.BoolVar(&TestContext.DeleteNamespaceOnFailure, "delete-namespace-on-failure", true, "If true, framework will delete test namespace on failure. Used only during test debugging.")
|
||||
flags.IntVar(&TestContext.AllowedNotReadyNodes, "allowed-not-ready-nodes", 0, "If non-zero, framework will allow for that many non-ready nodes when checking for all ready nodes.")
|
||||
|
||||
flags.StringVar(&TestContext.Host, "host", "", fmt.Sprintf("The host, or apiserver, to connect to. Will default to %s if this argument and --kubeconfig are not set", defaultHost))
|
||||
flags.StringVar(&TestContext.Host, "host", "", fmt.Sprintf("The host, or apiserver, to connect to. Will default to %s if this argument and --kubeconfig are not set.", defaultHost))
|
||||
flags.StringVar(&TestContext.ReportPrefix, "report-prefix", "", "Optional prefix for JUnit XML reports. Default is empty, which doesn't prepend anything to the default name.")
|
||||
flags.StringVar(&TestContext.ReportDir, "report-dir", "", "Path to the directory where the JUnit XML reports should be saved. Default is empty, which doesn't generate these reports.")
|
||||
flags.Var(cliflag.NewMapStringBool(&TestContext.FeatureGates), "feature-gates", "A set of key=value pairs that describe feature gates for alpha/experimental features.")
|
||||
@ -402,6 +407,18 @@ func createKubeConfig(clientCfg *restclient.Config) *clientcmdapi.Config {
|
||||
return configCmd
|
||||
}
|
||||
|
||||
func generateSecureToken(tokenLen int) (string, error) {
|
||||
// Number of bytes to be tokenLen when base64 encoded.
|
||||
tokenSize := math.Ceil(float64(tokenLen) * 6 / 8)
|
||||
rawToken := make([]byte, int(tokenSize))
|
||||
if _, err := rand.Read(rawToken); err != nil {
|
||||
return "", err
|
||||
}
|
||||
encoded := base64.RawURLEncoding.EncodeToString(rawToken)
|
||||
token := encoded[:tokenLen]
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// AfterReadingAllFlags makes changes to the context after all flags
|
||||
// have been read.
|
||||
func AfterReadingAllFlags(t *TestContextType) {
|
||||
@ -421,6 +438,13 @@ func AfterReadingAllFlags(t *TestContextType) {
|
||||
t.Host = defaultHost
|
||||
}
|
||||
}
|
||||
if len(t.BearerToken) == 0 {
|
||||
var err error
|
||||
t.BearerToken, err = generateSecureToken(16)
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed to generate bearer token: %v", err)
|
||||
}
|
||||
}
|
||||
// Allow 1% of nodes to be unready (statistically) - relevant for large clusters.
|
||||
if t.AllowedNotReadyNodes == 0 {
|
||||
t.AllowedNotReadyNodes = t.CloudConfig.NumNodes / 100
|
||||
|
@ -467,7 +467,13 @@ func LoadConfig() (config *restclient.Config, err error) {
|
||||
|
||||
if TestContext.NodeE2E {
|
||||
// This is a node e2e test, apply the node e2e configuration
|
||||
return &restclient.Config{Host: TestContext.Host}, nil
|
||||
return &restclient.Config{
|
||||
Host: TestContext.Host,
|
||||
BearerToken: TestContext.BearerToken,
|
||||
TLSClientConfig: restclient.TLSClientConfig{
|
||||
Insecure: true,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
c, err := restclientConfig(TestContext.KubeContext)
|
||||
if err != nil {
|
||||
|
@ -56,18 +56,21 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
var e2es *services.E2EServices
|
||||
var (
|
||||
e2es *services.E2EServices
|
||||
|
||||
// TODO(random-liu): Change the following modes to sub-command.
|
||||
var runServicesMode = flag.Bool("run-services-mode", false, "If true, only run services (etcd, apiserver) in current process, and not run test.")
|
||||
var runKubeletMode = flag.Bool("run-kubelet-mode", false, "If true, only start kubelet, and not run test.")
|
||||
var systemValidateMode = flag.Bool("system-validate-mode", false, "If true, only run system validation in current process, and not run test.")
|
||||
var systemSpecFile = flag.String("system-spec-file", "", "The name of the system spec file that will be used for node conformance test. If it's unspecified or empty, the default system spec (system.DefaultSysSpec) will be used.")
|
||||
// TODO(random-liu): Change the following modes to sub-command.
|
||||
runServicesMode = flag.Bool("run-services-mode", false, "If true, only run services (etcd, apiserver) in current process, and not run test.")
|
||||
runKubeletMode = flag.Bool("run-kubelet-mode", false, "If true, only start kubelet, and not run test.")
|
||||
systemValidateMode = flag.Bool("system-validate-mode", false, "If true, only run system validation in current process, and not run test.")
|
||||
systemSpecFile = flag.String("system-spec-file", "", "The name of the system spec file that will be used for node conformance test. If it's unspecified or empty, the default system spec (system.DefaultSysSpec) will be used.")
|
||||
)
|
||||
|
||||
// registerNodeFlags registers flags specific to the node e2e test suite.
|
||||
func registerNodeFlags(flags *flag.FlagSet) {
|
||||
// Mark the test as node e2e when node flags are api.Registry.
|
||||
framework.TestContext.NodeE2E = true
|
||||
flags.StringVar(&framework.TestContext.BearerToken, "bearer-token", "", "The bearer token to authenticate with. If not specified, it would be a random token. Currently this token is only used in node e2e tests.")
|
||||
flags.StringVar(&framework.TestContext.NodeName, "node-name", "", "Name of the node to run tests on.")
|
||||
// TODO(random-liu): Move kubelet start logic out of the test.
|
||||
// TODO(random-liu): Move log fetch logic out of the test.
|
||||
@ -205,8 +208,12 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte {
|
||||
// Reference common test to make the import valid.
|
||||
commontest.CurrentSuite = commontest.NodeE2E
|
||||
|
||||
return nil
|
||||
}, func([]byte) {
|
||||
// ginkgo would spawn multiple processes to run tests.
|
||||
// Since the bearer token is generated randomly at run time,
|
||||
// we need to distribute the bearer token to other processes to make them use the same token.
|
||||
return []byte(framework.TestContext.BearerToken)
|
||||
}, func(token []byte) {
|
||||
framework.TestContext.BearerToken = string(token)
|
||||
// update test context with node configuration.
|
||||
gomega.Expect(updateTestContext()).To(gomega.Succeed(), "update test context with node config.")
|
||||
})
|
||||
|
@ -18,18 +18,17 @@ package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
|
||||
apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
|
||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
)
|
||||
|
||||
const (
|
||||
clusterIPRange = "10.0.0.1/24"
|
||||
apiserverClientURL = "http://localhost:8080"
|
||||
apiserverHealthCheckURL = apiserverClientURL + "/healthz"
|
||||
)
|
||||
const clusterIPRange = "10.0.0.1/24"
|
||||
|
||||
// APIServer is a server which manages apiserver.
|
||||
type APIServer struct {
|
||||
@ -47,14 +46,23 @@ func NewAPIServer(storageConfig storagebackend.Config) *APIServer {
|
||||
|
||||
// Start starts the apiserver, returns when apiserver is ready.
|
||||
func (a *APIServer) Start() error {
|
||||
const tokenFilePath = "known_tokens.csv"
|
||||
|
||||
o := options.NewServerRunOptions()
|
||||
o.Etcd.StorageConfig = a.storageConfig
|
||||
_, ipnet, err := net.ParseCIDR(clusterIPRange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.SecureServing.BindAddress = net.ParseIP("127.0.0.1")
|
||||
// Disable insecure serving
|
||||
o.InsecureServing.BindPort = 0
|
||||
o.ServiceClusterIPRanges = ipnet.String()
|
||||
o.AllowPrivileged = true
|
||||
if err := generateTokenFile(tokenFilePath); err != nil {
|
||||
return fmt.Errorf("failed to generate token file %s: %v", tokenFilePath, err)
|
||||
}
|
||||
o.Authentication.TokenFile.TokenFile = tokenFilePath
|
||||
o.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount", "TaintNodesByCondition"}
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
@ -71,7 +79,7 @@ func (a *APIServer) Start() error {
|
||||
}
|
||||
}()
|
||||
|
||||
err = readinessCheck("apiserver", []string{apiserverHealthCheckURL}, errCh)
|
||||
err = readinessCheck("apiserver", []string{getAPIServerHealthCheckURL()}, errCh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -96,9 +104,14 @@ func (a *APIServer) Name() string {
|
||||
}
|
||||
|
||||
func getAPIServerClientURL() string {
|
||||
return apiserverClientURL
|
||||
return framework.TestContext.Host
|
||||
}
|
||||
|
||||
func getAPIServerHealthCheckURL() string {
|
||||
return apiserverHealthCheckURL
|
||||
return framework.TestContext.Host + "/healthz"
|
||||
}
|
||||
|
||||
func generateTokenFile(tokenFilePath string) error {
|
||||
tokenFile := fmt.Sprintf("%s,kubelet,uid,system:masters\n", framework.TestContext.BearerToken)
|
||||
return ioutil.WriteFile(tokenFilePath, []byte(tokenFile), 0644)
|
||||
}
|
||||
|
@ -27,12 +27,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
"k8s.io/klog/v2"
|
||||
kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kubelet/app/options"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||
@ -356,13 +356,15 @@ func createPodDirectory() (string, error) {
|
||||
|
||||
// createKubeconfig creates a kubeconfig file at the fully qualified `path`. The parent dirs must exist.
|
||||
func createKubeconfig(path string) error {
|
||||
kubeconfig := []byte(`apiVersion: v1
|
||||
kubeconfig := []byte(fmt.Sprintf(`apiVersion: v1
|
||||
kind: Config
|
||||
users:
|
||||
- name: kubelet
|
||||
user:
|
||||
token: %s
|
||||
clusters:
|
||||
- cluster:
|
||||
server: ` + getAPIServerClientURL() + `
|
||||
server: %s
|
||||
insecure-skip-tls-verify: true
|
||||
name: local
|
||||
contexts:
|
||||
@ -370,7 +372,7 @@ contexts:
|
||||
cluster: local
|
||||
user: kubelet
|
||||
name: local-context
|
||||
current-context: local-context`)
|
||||
current-context: local-context`, framework.TestContext.BearerToken, getAPIServerClientURL()))
|
||||
|
||||
if err := ioutil.WriteFile(path, kubeconfig, 0666); err != nil {
|
||||
return err
|
||||
|
@ -19,12 +19,13 @@ package services
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/informers"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/metadata"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
namespacecontroller "k8s.io/kubernetes/pkg/controller/namespace"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -49,7 +50,13 @@ func NewNamespaceController(host string) *NamespaceController {
|
||||
|
||||
// Start starts the namespace controller.
|
||||
func (n *NamespaceController) Start() error {
|
||||
config := restclient.AddUserAgent(&restclient.Config{Host: n.host}, ncName)
|
||||
config := restclient.AddUserAgent(&restclient.Config{
|
||||
Host: n.host,
|
||||
BearerToken: framework.TestContext.BearerToken,
|
||||
TLSClientConfig: restclient.TLSClientConfig{
|
||||
Insecure: true,
|
||||
},
|
||||
}, ncName)
|
||||
|
||||
// the namespace cleanup controller is very chatty. It makes lots of discovery calls and then it makes lots of delete calls.
|
||||
config.QPS = 50
|
||||
|
@ -24,9 +24,9 @@ import (
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
)
|
||||
|
||||
@ -65,14 +65,16 @@ func NewE2EServices(monitorParent bool) *E2EServices {
|
||||
func (e *E2EServices) Start() error {
|
||||
var err error
|
||||
if !framework.TestContext.NodeConformance {
|
||||
if e.services, err = e.startInternalServices(); err != nil {
|
||||
return fmt.Errorf("failed to start internal services: %v", err)
|
||||
}
|
||||
// Start kubelet
|
||||
e.kubelet, err = e.startKubelet()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start kubelet: %v", err)
|
||||
}
|
||||
}
|
||||
e.services, err = e.startInternalServices()
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops the e2e services.
|
||||
@ -129,7 +131,11 @@ func (e *E2EServices) startInternalServices() (*server, error) {
|
||||
return nil, fmt.Errorf("can't get current binary: %v", err)
|
||||
}
|
||||
// Pass all flags into the child process, so that it will see the same flag set.
|
||||
startCmd := exec.Command(testBin, append([]string{"--run-services-mode"}, os.Args[1:]...)...)
|
||||
startCmd := exec.Command(testBin,
|
||||
append(
|
||||
[]string{"--run-services-mode", fmt.Sprintf("--bearer-token=%s", framework.TestContext.BearerToken)},
|
||||
os.Args[1:]...,
|
||||
)...)
|
||||
server := newServer("services", startCmd, nil, nil, getServicesHealthCheckURLs(), servicesLogFile, e.monitorParent, false)
|
||||
return server, server.start()
|
||||
}
|
||||
|
@ -17,13 +17,17 @@ limitations under the License.
|
||||
package services
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"k8s.io/klog/v2"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
)
|
||||
|
||||
// terminationSignals are signals that cause the program to exit in the
|
||||
@ -42,6 +46,13 @@ func waitForTerminationSignal() {
|
||||
// and return the error.
|
||||
func readinessCheck(name string, urls []string, errCh <-chan error) error {
|
||||
klog.Infof("Running readiness check for service %q", name)
|
||||
|
||||
insecureTransport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
insecureTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
insecureHTTPClient := &http.Client{
|
||||
Transport: insecureTransport,
|
||||
}
|
||||
|
||||
endTime := time.Now().Add(*serverStartTimeout)
|
||||
blockCh := make(chan error)
|
||||
defer close(blockCh)
|
||||
@ -67,8 +78,7 @@ func readinessCheck(name string, urls []string, errCh <-chan error) error {
|
||||
case <-time.After(time.Second):
|
||||
ready := true
|
||||
for _, url := range urls {
|
||||
resp, err := http.Head(url)
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
if !healthCheck(insecureHTTPClient, url) {
|
||||
ready = false
|
||||
break
|
||||
}
|
||||
@ -80,3 +90,20 @@ func readinessCheck(name string, urls []string, errCh <-chan error) error {
|
||||
}
|
||||
return fmt.Errorf("e2e service %q readiness check timeout %v", name, *serverStartTimeout)
|
||||
}
|
||||
|
||||
// Perform a health check. Anything other than a 200-response is treated as a failure.
|
||||
// Only returns non-recoverable errors.
|
||||
func healthCheck(client *http.Client, url string) bool {
|
||||
req, err := http.NewRequest("HEAD", url, nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", framework.TestContext.BearerToken))
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
klog.Warningf("Health check on %q failed, error=%v", url, err)
|
||||
} else if resp.StatusCode != http.StatusOK {
|
||||
klog.Warningf("Health check on %q failed, status=%d", url, resp.StatusCode)
|
||||
}
|
||||
return err == nil && resp.StatusCode == http.StatusOK
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user