Commit 83439992 authored by Erik Wilson's avatar Erik Wilson

Update vendor

parent f992c229

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- dep-approvers
This directory tree is generated automatically by godep.
Please do not edit.
See https://github.com/tools/godep for more information.
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app
import (
"testing"
"k8s.io/apimachinery/pkg/util/sets"
"github.com/stretchr/testify/assert"
)
func TestIsControllerEnabled(t *testing.T) {
tcs := []struct {
name string
controllerName string
controllers []string
disabledByDefaultControllers []string
expected bool
}{
{
name: "on by name",
controllerName: "bravo",
controllers: []string{"alpha", "bravo", "-charlie"},
disabledByDefaultControllers: []string{"delta", "echo"},
expected: true,
},
{
name: "off by name",
controllerName: "charlie",
controllers: []string{"alpha", "bravo", "-charlie"},
disabledByDefaultControllers: []string{"delta", "echo"},
expected: false,
},
{
name: "on by default",
controllerName: "alpha",
controllers: []string{"*"},
disabledByDefaultControllers: []string{"delta", "echo"},
expected: true,
},
{
name: "off by default",
controllerName: "delta",
controllers: []string{"*"},
disabledByDefaultControllers: []string{"delta", "echo"},
expected: false,
},
{
name: "off by default implicit, no star",
controllerName: "foxtrot",
controllers: []string{"alpha", "bravo", "-charlie"},
disabledByDefaultControllers: []string{"delta", "echo"},
expected: false,
},
}
for _, tc := range tcs {
actual := IsControllerEnabled(tc.controllerName, sets.NewString(tc.disabledByDefaultControllers...), tc.controllers)
assert.Equal(t, tc.expected, actual, "%v: expected %v, got %v", tc.name, tc.expected, actual)
}
}
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package options
import (
"flag"
"reflect"
"sort"
"strings"
"testing"
"github.com/spf13/pflag"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/cli/globalflag"
)
func TestAddCustomGlobalFlags(t *testing.T) {
namedFlagSets := &cliflag.NamedFlagSets{}
// Note that we will register all flags (including klog flags) into the same
// flag set. This allows us to test against all global flags from
// flags.CommandLine.
nfs := namedFlagSets.FlagSet("test")
globalflag.AddGlobalFlags(nfs, "test-cmd")
AddCustomGlobalFlags(nfs)
actualFlag := []string{}
nfs.VisitAll(func(flag *pflag.Flag) {
actualFlag = append(actualFlag, flag.Name)
})
// Get all flags from flags.CommandLine, except flag `test.*`.
wantedFlag := []string{"help"}
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.VisitAll(func(flag *pflag.Flag) {
if !strings.Contains(flag.Name, "test.") {
wantedFlag = append(wantedFlag, flag.Name)
}
})
sort.Strings(wantedFlag)
if !reflect.DeepEqual(wantedFlag, actualFlag) {
t.Errorf("[Default]: expected %+v, got %+v", wantedFlag, actualFlag)
}
}
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["testserver.go"],
data = glob(["testdata/**"]),
importpath = "k8s.io/kubernetes/cmd/kube-apiserver/app/testing",
deps = [
"//cmd/kube-apiserver/app:go_default_library",
"//cmd/kube-apiserver/app/options:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
-----BEGIN CERTIFICATE-----
MIIDTzCCAjegAwIBAgIBAjANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBcxMjcu
MC4wLjEtY2FAMTUzMTQ2NzU5MzAgFw0xODA3MTMwNjM5NTNaGA8yMTE4MDYxOTA2
Mzk1M1owHzEdMBsGA1UEAwwUMTI3LjAuMC4xQDE1MzE0Njc1OTMwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdTNF7rRKBvDtLOvCTDgj3utt+zv5u+23x
kCz2475DPnTZ7JK2ipCuHemyCY88M6VyaBkIqAVvvl3LZiS+Hu3gd+8elbdGrCxQ
sui1MrUcAg8OoBM+97UzoKC3HMFIFEpqzKjVJKr5PbV3F8XXIBQeS3YUCePo3m7u
OkGCXUXtWRtQTu4Dcq+tJKlJBsY+Q8CUvb1l0n5hafIFEMnFF/sKGP28CWd8gfzD
ZKKtVumvQlgcp1GdfxqKHfjQOtBo+ZBFiHgDGDrrghuQ2CxROvk5/bNrViqbWbw4
lUbU3Yn18L4UHR5xOOvQyLP2QdWAaoPutT7Xba40RMgWYlsNRaatAgMBAAGjgZAw
gY0wDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB
/wQCMAAwWAYDVR0RBFEwT4IWa3ViZXJuZXRlcy5kZWZhdWx0LnN2Y4ISa3ViZXJu
ZXRlcy5kZWZhdWx0ggprdWJlcm5ldGVzgglsb2NhbGhvc3SHBH8AAAGHBAoAAAEw
DQYJKoZIhvcNAQELBQADggEBAFkRV1oBLrY3IJDI6E9nxAK30EdyfYZqvybPCZB8
6AAErj+WleJVFi0rZJ3fRDoQ5Gelwe4Ud21DknW4+L7nZ8JRbzNkLTYTJxtkujSW
aEz7xKW1IxD+o9TEceqiVko4xGawXjUVTun7n0Upv6T4D4jC0GN9zu8oT6xbUHmd
WSSc2HjGLs8vF130xt2Oj0jx03i7AoJF4ZxMRt7dqSK7j5tfflfTS9Dxhmd9Gg5P
eGH4BWJ3IJI3r0+WUtiIgMSgV2ppTSNY2UNbNNpudsRCq55IzyHuRioFt/FH9t+8
xFaar6D9RDsm87JCv5JZ3BoVZJglmX8iqye+OBXgHgMZxx4=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIC5DCCAcygAwIBAgIBATANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBcxMjcu
MC4wLjEtY2FAMTUzMTQ2NzU5MzAgFw0xODA3MTMwNjM5NTNaGA8yMTE4MDYxOTA2
Mzk1M1owIjEgMB4GA1UEAwwXMTI3LjAuMC4xLWNhQDE1MzE0Njc1OTMwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRfS+rc4EPpDafeiRo+uIvV1812UQM
ddoaCrn2yIVSYiupsFc7goieXOpqxgI6ksUCMDUOfi3DQGC8067wX2HpMzz5J9yz
Qfamcg3SL7G9u5Vx+x+EU6qmBhXa4Z46JwTY0vYeccz2PR+Nx+HHO0DglIh3tip8
ECQ2rtpMc5YxJOCwJg3zh8pnEqLNEahm3p1lNGLbY7Kpqp7al68ZVReVg/YaoJt5
Voi7vbR38OWBChbBmwKRP4gJD8aKY2eY6Xgn8+UAAytYGOEp18y/eAvba7awKp56
wG1Y3JqWD06D8NnUCPQOO/g/KyGU77sM66xdlsOwLpSbtwWLcjC3nnvHAgMBAAGj
IzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
CwUAA4IBAQCECJvqzrh57MrVT5sj+TDmhtSwkblBBqNG03X8gvmj7PsYAnZVpaev
KbN0xfDhK6yaCJX41sZCoTaQa55a0Y9n/Lr6d2LREYPf2NdhHU2aj1UjNhhamoZk
0/MJtn/7t6UmYsdFIRlYtLJZQRfNaeO+ULpjjQeGj+Y4mR87VzyDZk2zi/fLJCtk
aVKsI2Tan9KFzwmsCp/9RH7uPhOIFsaa8ePBCvzrahMrG+b9FGV670bQTS104Gyt
HB73ixOheUPL9PuvahXKz0xlJfeKu4nFFJkqUmThj2Ybv8cyzDNrSyDywZxzNe3e
nMA3i/kfmIj33gkmwcFgYPqfKleeVZQo
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA3UzRe60Sgbw7Szrwkw4I97rbfs7+bvtt8ZAs9uO+Qz502eyS
toqQrh3psgmPPDOlcmgZCKgFb75dy2Ykvh7t4HfvHpW3RqwsULLotTK1HAIPDqAT
Pve1M6CgtxzBSBRKasyo1SSq+T21dxfF1yAUHkt2FAnj6N5u7jpBgl1F7VkbUE7u
A3KvrSSpSQbGPkPAlL29ZdJ+YWnyBRDJxRf7Chj9vAlnfIH8w2SirVbpr0JYHKdR
nX8aih340DrQaPmQRYh4Axg664IbkNgsUTr5Of2za1Yqm1m8OJVG1N2J9fC+FB0e
cTjr0Miz9kHVgGqD7rU+122uNETIFmJbDUWmrQIDAQABAoIBAFXzdhFhASUeZLEt
bS7Qbq85BfNUlgGo6eS+qJgjkEwxv9S8S6dWXiciOxgJGna5YHL093QjPilOeMN9
IpwtCxr5ugfZAlwSlwuo0TU/QpRkQFDf31m/f8NTidhU9MT4DIc6ggB2w2kWjJp6
wz5wmR/DE1NpG/ngGpmwSq1FaNlr3xz4e6b0A56ReqQr5YwYsZl2Fxf8sOBWTiPe
Iv41q8jyRXL2ytv9uTgdD7i+qLMz1/NGvy4ZWxD3yCMsDm5eEI8/4l2pOmRrrpKY
Fc14eUkbHBMyT6ibI4d7Y2aZJslq8d0HMMX1XNLvzLEnGT1+mrOjWwerI+60B0t1
6EvTfUkCgYEA/rVROq6JupfnT7BM04jEx5UuaokcLoNpn6bptZwmMakioLjgZoa2
XEZrNoRWVMQ82JuguxkLtUgLgqKQRreolDCyQtaGFjFnWdVs+1W0oIHY7oMdwOLh
XsQRtPW3HCK4HYZJcBBIh8t4USiBTrRtTpXmDinLkbCRXYOcehbRZ2cCgYEA3mwg
tsbnSDYTcFmPjJEGjISfMEjAHoka8ubPKzU6VylDnrb2k/NbDYL3NidzGbJaVJFk
YNfCsja4COz+0pBiMY2fBEzHU4RwDaRrxUr0fLVxvH7/E9JPP8y/e5CJR2Z2sDQa
yed3ArkNh0MaecGr+7IZFbv+Uj4QaBq3W77hGMsCgYB/keC1O2XQBvTbfLl92Sp1
q8orobBzu23TgI3dX+/hP40QYohB0YbUgJCCJZX3rrGq64d9LfYnPYZGT5VjVekh
D6K4xykxRF03KSYEW9Cz81TrYNAuI3QtOpaDw+2KMfl1ECUH85/gI5CHVXouKT/1
9C3dOiGzPnQQGjLtEzCeUQKBgFacZGDIM2e7Jvao6W0jTBmLyzFSIv3BBe1wU1vP
7lfiiaJUPNCAAwTP6tP7qKZo/SPROfU8D2S2ShOvtcrozlPdgf56p2OuPrQRQqYg
+fNV9GQiT9G4I4QEhsvnDI3xKGaU45mbuIwm4024o6al9AKe54W/HtmHsXvYa24e
dijhAoGARcbgcE/aT8jhdVHHCRBuSD4ZzXbB+JCetHsrjhOYnifc0graq0umiuRI
c0i+IT5OhGTdVbjnPgySHn/V/IuSYLLtKvfqSV8tQk3womXRPJ/K9BsFhelo1Vd5
MTyZ2j0XjLWHOo0DKxIPLW3P7sBYAFM2Z+/RAe1uKjISmggDhBs=
-----END RSA PRIVATE KEY-----
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"fmt"
"io/ioutil"
"net"
"os"
"path"
"runtime"
"time"
pflag "github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/registry/generic/registry"
"k8s.io/apiserver/pkg/storage/storagebackend"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/cmd/kube-apiserver/app"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
)
// TearDownFunc is to be called to tear down a test server.
type TearDownFunc func()
// TestServerInstanceOptions Instance options the TestServer
type TestServerInstanceOptions struct {
// DisableStorageCleanup Disable the automatic storage cleanup
DisableStorageCleanup bool
}
// TestServer return values supplied by kube-test-ApiServer
type TestServer struct {
ClientConfig *restclient.Config // Rest client config
ServerOpts *options.ServerRunOptions // ServerOpts
TearDownFn TearDownFunc // TearDown function
TmpDir string // Temp Dir used, by the apiserver
}
// Logger allows t.Testing and b.Testing to be passed to StartTestServer and StartTestServerOrDie
type Logger interface {
Errorf(format string, args ...interface{})
Fatalf(format string, args ...interface{})
Logf(format string, args ...interface{})
}
// NewDefaultTestServerOptions Default options for TestServer instances
func NewDefaultTestServerOptions() *TestServerInstanceOptions {
return &TestServerInstanceOptions{
DisableStorageCleanup: false,
}
}
// StartTestServer starts a etcd server and kube-apiserver. A rest client config and a tear-down func,
// and location of the tmpdir are returned.
//
// Note: we return a tear-down func instead of a stop channel because the later will leak temporary
// files that because Golang testing's call to os.Exit will not give a stop channel go routine
// enough time to remove temporary files.
func StartTestServer(t Logger, instanceOptions *TestServerInstanceOptions, customFlags []string, storageConfig *storagebackend.Config) (result TestServer, err error) {
if instanceOptions == nil {
instanceOptions = NewDefaultTestServerOptions()
}
// TODO : Remove TrackStorageCleanup below when PR
// https://github.com/kubernetes/kubernetes/pull/50690
// merges as that shuts down storage properly
if !instanceOptions.DisableStorageCleanup {
registry.TrackStorageCleanup()
}
stopCh := make(chan struct{})
tearDown := func() {
if !instanceOptions.DisableStorageCleanup {
registry.CleanupStorage()
}
close(stopCh)
if len(result.TmpDir) != 0 {
os.RemoveAll(result.TmpDir)
}
}
defer func() {
if result.TearDownFn == nil {
tearDown()
}
}()
result.TmpDir, err = ioutil.TempDir("", "kubernetes-kube-apiserver")
if err != nil {
return result, fmt.Errorf("failed to create temp dir: %v", err)
}
fs := pflag.NewFlagSet("test", pflag.PanicOnError)
s := options.NewServerRunOptions()
for _, f := range s.Flags().FlagSets {
fs.AddFlagSet(f)
}
s.InsecureServing.BindPort = 0
s.SecureServing.Listener, s.SecureServing.BindPort, err = createLocalhostListenerOnFreePort()
if err != nil {
return result, fmt.Errorf("failed to create listener: %v", err)
}
s.SecureServing.ServerCert.CertDirectory = result.TmpDir
s.SecureServing.ExternalAddress = s.SecureServing.Listener.Addr().(*net.TCPAddr).IP // use listener addr although it is a loopback device
_, thisFile, _, ok := runtime.Caller(0)
if !ok {
return result, fmt.Errorf("failed to get current file")
}
s.SecureServing.ServerCert.FixtureDirectory = path.Join(path.Dir(thisFile), "testdata")
s.ServiceClusterIPRange.IP = net.IPv4(10, 0, 0, 0)
s.ServiceClusterIPRange.Mask = net.CIDRMask(16, 32)
s.Etcd.StorageConfig = *storageConfig
s.APIEnablement.RuntimeConfig.Set("api/all=true")
fs.Parse(customFlags)
completedOptions, err := app.Complete(s)
if err != nil {
return result, fmt.Errorf("failed to set default ServerRunOptions: %v", err)
}
t.Logf("runtime-config=%v", completedOptions.APIEnablement.RuntimeConfig)
t.Logf("Starting kube-apiserver on port %d...", s.SecureServing.BindPort)
server, err := app.CreateServerChain(completedOptions, stopCh)
if err != nil {
return result, fmt.Errorf("failed to create server chain: %v", err)
}
errCh := make(chan error)
go func(stopCh <-chan struct{}) {
if err := server.PrepareRun().Run(stopCh); err != nil {
errCh <- err
}
}(stopCh)
t.Logf("Waiting for /healthz to be ok...")
client, err := kubernetes.NewForConfig(server.LoopbackClientConfig)
if err != nil {
return result, fmt.Errorf("failed to create a client: %v", err)
}
err = wait.Poll(100*time.Millisecond, 30*time.Second, func() (bool, error) {
select {
case err := <-errCh:
return false, err
default:
}
result := client.CoreV1().RESTClient().Get().AbsPath("/healthz").Do()
status := 0
result.StatusCode(&status)
if status == 200 {
return true, nil
}
return false, nil
})
if err != nil {
return result, fmt.Errorf("failed to wait for /healthz to return ok: %v", err)
}
// from here the caller must call tearDown
result.ClientConfig = server.LoopbackClientConfig
result.ServerOpts = s
result.TearDownFn = tearDown
return result, nil
}
// StartTestServerOrDie calls StartTestServer t.Fatal if it does not succeed.
func StartTestServerOrDie(t Logger, instanceOptions *TestServerInstanceOptions, flags []string, storageConfig *storagebackend.Config) *TestServer {
result, err := StartTestServer(t, instanceOptions, flags, storageConfig)
if err == nil {
return &result
}
t.Fatalf("failed to launch server: %v", err)
return nil
}
func createLocalhostListenerOnFreePort() (net.Listener, int, error) {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return nil, 0, err
}
// get port
tcpAddr, ok := ln.Addr().(*net.TCPAddr)
if !ok {
ln.Close()
return nil, 0, fmt.Errorf("invalid listen address: %q", ln.Addr().String())
}
return ln, tcpAddr.Port, nil
}
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app
import (
"net/http"
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery"
fakediscovery "k8s.io/client-go/discovery/fake"
"k8s.io/client-go/informers"
clientset "k8s.io/client-go/kubernetes"
fakeclientset "k8s.io/client-go/kubernetes/fake"
restclient "k8s.io/client-go/rest"
)
// TestClientBuilder inherits ClientBuilder and can accept a given fake clientset.
type TestClientBuilder struct {
clientset clientset.Interface
}
func (TestClientBuilder) Config(name string) (*restclient.Config, error) { return nil, nil }
func (TestClientBuilder) ConfigOrDie(name string) *restclient.Config {
return &restclient.Config{}
}
func (TestClientBuilder) Client(name string) (clientset.Interface, error) { return nil, nil }
func (m TestClientBuilder) ClientOrDie(name string) clientset.Interface {
return m.clientset
}
// FakeDiscoveryWithError inherits DiscoveryInterface(via FakeDiscovery) with some methods accepting testing data.
type FakeDiscoveryWithError struct {
fakediscovery.FakeDiscovery
PossibleResources []*metav1.APIResourceList
Err error
}
func (d FakeDiscoveryWithError) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
return d.PossibleResources, d.Err
}
// FakeDiscoveryWithError inherits Clientset(via FakeClientset) with overridden Discovery method.
type FakeClientSet struct {
fakeclientset.Clientset
DiscoveryObj *FakeDiscoveryWithError
}
func (c *FakeClientSet) Discovery() discovery.DiscoveryInterface {
return c.DiscoveryObj
}
func (c *FakeClientSet) GetPossibleResources() []*metav1.APIResourceList {
return c.DiscoveryObj.PossibleResources
}
// Create a fake Clientset with its Discovery method overridden.
func NewFakeClientset(fakeDiscovery FakeDiscoveryWithError) *FakeClientSet {
cs := &FakeClientSet{}
cs.DiscoveryObj = &fakeDiscovery
return cs
}
func possibleDiscoveryResource() []*metav1.APIResourceList {
return []*metav1.APIResourceList{
{
GroupVersion: "create/v1",
APIResources: []metav1.APIResource{
{
Name: "jobs",
Verbs: []string{"create", "list", "watch", "delete"},
ShortNames: []string{"jz"},
Categories: []string{"all"},
},
},
},
}
}
type controllerInitFunc func(ControllerContext) (http.Handler, bool, error)
func TestController_DiscoveryError(t *testing.T) {
controllerInitFuncMap := map[string]controllerInitFunc{
"ResourceQuotaController": startResourceQuotaController,
"GarbageCollectorController": startGarbageCollectorController,
}
tcs := map[string]struct {
discoveryError error
expectedErr bool
possibleResources []*metav1.APIResourceList
}{
"No Discovery Error": {
discoveryError: nil,
possibleResources: possibleDiscoveryResource(),
expectedErr: false,
},
"Discovery Calls Partially Failed": {
discoveryError: new(discovery.ErrGroupDiscoveryFailed),
possibleResources: possibleDiscoveryResource(),
expectedErr: false,
},
}
for name, test := range tcs {
testDiscovery := FakeDiscoveryWithError{Err: test.discoveryError, PossibleResources: test.possibleResources}
testClientset := NewFakeClientset(testDiscovery)
testClientBuilder := TestClientBuilder{clientset: testClientset}
ctx := ControllerContext{
ClientBuilder: testClientBuilder,
InformerFactory: informers.NewSharedInformerFactoryWithOptions(testClientset, time.Duration(1)),
InformersStarted: make(chan struct{}),
}
for funcName, controllerInit := range controllerInitFuncMap {
_, _, err := controllerInit(ctx)
if test.expectedErr != (err != nil) {
t.Errorf("%v test failed for use case: %v", funcName, name)
}
}
_, _, err := startModifiedNamespaceController(
ctx, testClientset, testClientBuilder.ConfigOrDie("namespace-controller"))
if test.expectedErr != (err != nil) {
t.Errorf("Namespace Controller test failed for use case: %v", name)
}
}
}
load("@io_bazel_rules_go//go:def.bzl", "go_library")
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_library(
name = "go_default_library",
srcs = ["testserver.go"],
importpath = "k8s.io/kubernetes/cmd/kube-controller-manager/app/testing",
visibility = ["//visibility:public"],
deps = [
"//cmd/kube-controller-manager/app:go_default_library",
"//cmd/kube-controller-manager/app/config:go_default_library",
"//cmd/kube-controller-manager/app/options:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
],
)
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"fmt"
"io/ioutil"
"net"
"os"
"time"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/cmd/kube-controller-manager/app"
kubecontrollerconfig "k8s.io/kubernetes/cmd/kube-controller-manager/app/config"
"k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
)
// TearDownFunc is to be called to tear down a test server.
type TearDownFunc func()
// TestServer return values supplied by kube-test-ApiServer
type TestServer struct {
LoopbackClientConfig *restclient.Config // Rest client config using the magic token
Options *options.KubeControllerManagerOptions
Config *kubecontrollerconfig.Config
TearDownFn TearDownFunc // TearDown function
TmpDir string // Temp Dir used, by the apiserver
}
// Logger allows t.Testing and b.Testing to be passed to StartTestServer and StartTestServerOrDie
type Logger interface {
Errorf(format string, args ...interface{})
Fatalf(format string, args ...interface{})
Logf(format string, args ...interface{})
}
// StartTestServer starts a kube-controller-manager. A rest client config and a tear-down func,
// and location of the tmpdir are returned.
//
// Note: we return a tear-down func instead of a stop channel because the later will leak temporary
// files that because Golang testing's call to os.Exit will not give a stop channel go routine
// enough time to remove temporary files.
func StartTestServer(t Logger, customFlags []string) (result TestServer, err error) {
stopCh := make(chan struct{})
tearDown := func() {
close(stopCh)
if len(result.TmpDir) != 0 {
os.RemoveAll(result.TmpDir)
}
}
defer func() {
if result.TearDownFn == nil {
tearDown()
}
}()
result.TmpDir, err = ioutil.TempDir("", "kube-controller-manager")
if err != nil {
return result, fmt.Errorf("failed to create temp dir: %v", err)
}
fs := pflag.NewFlagSet("test", pflag.PanicOnError)
s, err := options.NewKubeControllerManagerOptions()
if err != nil {
return TestServer{}, err
}
all, disabled := app.KnownControllers(), app.ControllersDisabledByDefault.List()
namedFlagSets := s.Flags(all, disabled)
for _, f := range namedFlagSets.FlagSets {
fs.AddFlagSet(f)
}
fs.Parse(customFlags)
if s.SecureServing.BindPort != 0 {
s.SecureServing.Listener, s.SecureServing.BindPort, err = createListenerOnFreePort()
if err != nil {
return result, fmt.Errorf("failed to create listener: %v", err)
}
s.SecureServing.ServerCert.CertDirectory = result.TmpDir
t.Logf("kube-controller-manager will listen securely on port %d...", s.SecureServing.BindPort)
}
if s.InsecureServing.BindPort != 0 {
s.InsecureServing.Listener, s.InsecureServing.BindPort, err = createListenerOnFreePort()
if err != nil {
return result, fmt.Errorf("failed to create listener: %v", err)
}
t.Logf("kube-controller-manager will listen insecurely on port %d...", s.InsecureServing.BindPort)
}
config, err := s.Config(all, disabled)
if err != nil {
return result, fmt.Errorf("failed to create config from options: %v", err)
}
errCh := make(chan error)
go func(stopCh <-chan struct{}) {
if err := app.Run(config.Complete(), stopCh); err != nil {
errCh <- err
}
}(stopCh)
t.Logf("Waiting for /healthz to be ok...")
client, err := kubernetes.NewForConfig(config.LoopbackClientConfig)
if err != nil {
return result, fmt.Errorf("failed to create a client: %v", err)
}
err = wait.Poll(100*time.Millisecond, 30*time.Second, func() (bool, error) {
select {
case err := <-errCh:
return false, err
default:
}
result := client.CoreV1().RESTClient().Get().AbsPath("/healthz").Do()
status := 0
result.StatusCode(&status)
if status == 200 {
return true, nil
}
return false, nil
})
if err != nil {
return result, fmt.Errorf("failed to wait for /healthz to return ok: %v", err)
}
// from here the caller must call tearDown
result.LoopbackClientConfig = config.LoopbackClientConfig
result.Options = s
result.Config = config
result.TearDownFn = tearDown
return result, nil
}
// StartTestServerOrDie calls StartTestServer t.Fatal if it does not succeed.
func StartTestServerOrDie(t Logger, flags []string) *TestServer {
result, err := StartTestServer(t, flags)
if err == nil {
return &result
}
t.Fatalf("failed to launch server: %v", err)
return nil
}
func createListenerOnFreePort() (net.Listener, int, error) {
ln, err := net.Listen("tcp", ":0")
if err != nil {
return nil, 0, err
}
// get port
tcpAddr, ok := ln.Addr().(*net.TCPAddr)
if !ok {
ln.Close()
return nil, 0, fmt.Errorf("invalid listen address: %q", ln.Addr().String())
}
return ln, tcpAddr.Port, nil
}
// +build !windows
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app
import (
"fmt"
"testing"
"k8s.io/kubernetes/pkg/proxy/ipvs"
"k8s.io/kubernetes/pkg/util/iptables"
)
func Test_getProxyMode(t *testing.T) {
var cases = []struct {
flag string
annotationKey string
annotationVal string
iptablesVersion string
ipsetVersion string
kmods []string
kernelCompat bool
iptablesError error
ipsetError error
expected string
}{
{ // flag says userspace
flag: "userspace",
expected: proxyModeUserspace,
},
{ // flag says iptables, error detecting version
flag: "iptables",
iptablesError: fmt.Errorf("oops!"),
expected: proxyModeUserspace,
},
{ // flag says iptables, version too low
flag: "iptables",
iptablesVersion: "0.0.0",
expected: proxyModeUserspace,
},
{ // flag says iptables, version ok, kernel not compatible
flag: "iptables",
iptablesVersion: iptables.MinCheckVersion,
kernelCompat: false,
expected: proxyModeUserspace,
},
{ // flag says iptables, version ok, kernel is compatible
flag: "iptables",
iptablesVersion: iptables.MinCheckVersion,
kernelCompat: true,
expected: proxyModeIPTables,
},
{ // detect, error
flag: "",
iptablesError: fmt.Errorf("oops!"),
expected: proxyModeUserspace,
},
{ // detect, version too low
flag: "",
iptablesVersion: "0.0.0",
expected: proxyModeUserspace,
},
{ // detect, version ok, kernel not compatible
flag: "",
iptablesVersion: iptables.MinCheckVersion,
kernelCompat: false,
expected: proxyModeUserspace,
},
{ // detect, version ok, kernel is compatible
flag: "",
iptablesVersion: iptables.MinCheckVersion,
kernelCompat: true,
expected: proxyModeIPTables,
},
{ // flag says ipvs, ipset version ok, kernel modules installed
flag: "ipvs",
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
ipsetVersion: ipvs.MinIPSetCheckVersion,
expected: proxyModeIPVS,
},
{ // flag says ipvs, ipset version too low, fallback on iptables mode
flag: "ipvs",
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
ipsetVersion: "0.0",
iptablesVersion: iptables.MinCheckVersion,
kernelCompat: true,
expected: proxyModeIPTables,
},
{ // flag says ipvs, bad ipset version, fallback on iptables mode
flag: "ipvs",
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
ipsetVersion: "a.b.c",
iptablesVersion: iptables.MinCheckVersion,
kernelCompat: true,
expected: proxyModeIPTables,
},
{ // flag says ipvs, required kernel modules are not installed, fallback on iptables mode
flag: "ipvs",
kmods: []string{"foo", "bar", "baz"},
ipsetVersion: ipvs.MinIPSetCheckVersion,
iptablesVersion: iptables.MinCheckVersion,
kernelCompat: true,
expected: proxyModeIPTables,
},
{ // flag says ipvs, required kernel modules are not installed, iptables version too old, fallback on userspace mode
flag: "ipvs",
kmods: []string{"foo", "bar", "baz"},
ipsetVersion: ipvs.MinIPSetCheckVersion,
iptablesVersion: "0.0.0",
kernelCompat: true,
expected: proxyModeUserspace,
},
{ // flag says ipvs, ipset version too low, iptables version too old, kernel not compatible, fallback on userspace mode
flag: "ipvs",
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
ipsetVersion: "0.0",
iptablesVersion: iptables.MinCheckVersion,
kernelCompat: false,
expected: proxyModeUserspace,
},
}
for i, c := range cases {
versioner := &fakeIPTablesVersioner{c.iptablesVersion, c.iptablesError}
kcompater := &fakeKernelCompatTester{c.kernelCompat}
ipsetver := &fakeIPSetVersioner{c.ipsetVersion, c.ipsetError}
khandler := &fakeKernelHandler{c.kmods}
r := getProxyMode(c.flag, versioner, khandler, ipsetver, kcompater)
if r != c.expected {
t.Errorf("Case[%d] Expected %q, got %q", i, c.expected, r)
}
}
}
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package options
import (
"testing"
)
func TestValidateDeprecatedKubeSchedulerConfiguration(t *testing.T) {
scenarios := map[string]struct {
expectedToFail bool
config *DeprecatedOptions
}{
"good": {
expectedToFail: false,
config: &DeprecatedOptions{
PolicyConfigFile: "/some/file",
UseLegacyPolicyConfig: true,
AlgorithmProvider: "",
},
},
"bad-policy-config-file-null": {
expectedToFail: true,
config: &DeprecatedOptions{
PolicyConfigFile: "",
UseLegacyPolicyConfig: true,
AlgorithmProvider: "",
},
},
}
for name, scenario := range scenarios {
errs := scenario.config.Validate()
if len(errs) == 0 && scenario.expectedToFail {
t.Errorf("Unexpected success for scenario: %s", name)
}
if len(errs) > 0 && !scenario.expectedToFail {
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
}
}
}
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["testserver.go"],
importpath = "k8s.io/kubernetes/cmd/kube-scheduler/app/testing",
visibility = ["//visibility:public"],
deps = [
"//cmd/kube-scheduler/app:go_default_library",
"//cmd/kube-scheduler/app/config:go_default_library",
"//cmd/kube-scheduler/app/options:go_default_library",
"//pkg/scheduler/algorithmprovider/defaults:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"fmt"
"io/ioutil"
"net"
"os"
"time"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/cmd/kube-scheduler/app"
kubeschedulerconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
"k8s.io/kubernetes/cmd/kube-scheduler/app/options"
// import DefaultProvider
_ "k8s.io/kubernetes/pkg/scheduler/algorithmprovider/defaults"
)
// TearDownFunc is to be called to tear down a test server.
type TearDownFunc func()
// TestServer return values supplied by kube-test-ApiServer
type TestServer struct {
LoopbackClientConfig *restclient.Config // Rest client config using the magic token
Options *options.Options
Config *kubeschedulerconfig.Config
TearDownFn TearDownFunc // TearDown function
TmpDir string // Temp Dir used, by the apiserver
}
// Logger allows t.Testing and b.Testing to be passed to StartTestServer and StartTestServerOrDie
type Logger interface {
Errorf(format string, args ...interface{})
Fatalf(format string, args ...interface{})
Logf(format string, args ...interface{})
}
// StartTestServer starts a kube-scheduler. A rest client config and a tear-down func,
// and location of the tmpdir are returned.
//
// Note: we return a tear-down func instead of a stop channel because the later will leak temporary
// files that because Golang testing's call to os.Exit will not give a stop channel go routine
// enough time to remove temporary files.
func StartTestServer(t Logger, customFlags []string) (result TestServer, err error) {
stopCh := make(chan struct{})
tearDown := func() {
close(stopCh)
if len(result.TmpDir) != 0 {
os.RemoveAll(result.TmpDir)
}
}
defer func() {
if result.TearDownFn == nil {
tearDown()
}
}()
result.TmpDir, err = ioutil.TempDir("", "kube-scheduler")
if err != nil {
return result, fmt.Errorf("failed to create temp dir: %v", err)
}
fs := pflag.NewFlagSet("test", pflag.PanicOnError)
s, err := options.NewOptions()
if err != nil {
return TestServer{}, err
}
namedFlagSets := s.Flags()
for _, f := range namedFlagSets.FlagSets {
fs.AddFlagSet(f)
}
fs.Parse(customFlags)
if s.SecureServing.BindPort != 0 {
s.SecureServing.Listener, s.SecureServing.BindPort, err = createListenerOnFreePort()
if err != nil {
return result, fmt.Errorf("failed to create listener: %v", err)
}
s.SecureServing.ServerCert.CertDirectory = result.TmpDir
t.Logf("kube-scheduler will listen securely on port %d...", s.SecureServing.BindPort)
}
if s.CombinedInsecureServing.BindPort != 0 {
listener, port, err := createListenerOnFreePort()
if err != nil {
return result, fmt.Errorf("failed to create listener: %v", err)
}
s.CombinedInsecureServing.BindPort = port
s.CombinedInsecureServing.Healthz.Listener = listener
s.CombinedInsecureServing.Metrics.Listener = listener
t.Logf("kube-scheduler will listen insecurely on port %d...", s.CombinedInsecureServing.BindPort)
}
config, err := s.Config()
if err != nil {
return result, fmt.Errorf("failed to create config from options: %v", err)
}
errCh := make(chan error)
go func(stopCh <-chan struct{}) {
if err := app.Run(config.Complete(), stopCh); err != nil {
errCh <- err
}
}(stopCh)
t.Logf("Waiting for /healthz to be ok...")
client, err := kubernetes.NewForConfig(config.LoopbackClientConfig)
if err != nil {
return result, fmt.Errorf("failed to create a client: %v", err)
}
err = wait.Poll(100*time.Millisecond, 30*time.Second, func() (bool, error) {
select {
case err := <-errCh:
return false, err
default:
}
result := client.CoreV1().RESTClient().Get().AbsPath("/healthz").Do()
status := 0
result.StatusCode(&status)
if status == 200 {
return true, nil
}
return false, nil
})
if err != nil {
return result, fmt.Errorf("failed to wait for /healthz to return ok: %v", err)
}
// from here the caller must call tearDown
result.LoopbackClientConfig = config.LoopbackClientConfig
result.Options = s
result.Config = config
result.TearDownFn = tearDown
return result, nil
}
// StartTestServerOrDie calls StartTestServer t.Fatal if it does not succeed.
func StartTestServerOrDie(t Logger, flags []string) *TestServer {
result, err := StartTestServer(t, flags)
if err == nil {
return &result
}
t.Fatalf("failed to launch server: %v", err)
return nil
}
func createListenerOnFreePort() (net.Listener, int, error) {
ln, err := net.Listen("tcp", ":0")
if err != nil {
return nil, 0, err
}
// get port
tcpAddr, ok := ln.Addr().(*net.TCPAddr)
if !ok {
ln.Close()
return nil, 0, fmt.Errorf("invalid listen address: %q", ln.Addr().String())
}
return ln, tcpAddr.Port, nil
}
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
)
const (
testInitConfig = `---
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: "1.2.3.4"
bootstrapTokens:
- token: "abcdef.0123456789abcdef"
nodeRegistration:
criSocket: /run/containerd/containerd.sock
name: someName
---
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
controlPlaneEndpoint: "3.4.5.6"
`
)
func TestNewInitData(t *testing.T) {
// create temp directory
tmpDir, err := ioutil.TempDir("", "kubeadm-init-test")
if err != nil {
t.Errorf("Unable to create temporary directory: %v", err)
}
defer os.RemoveAll(tmpDir)
// create config file
configFilePath := filepath.Join(tmpDir, "test-config-file")
cfgFile, err := os.Create(configFilePath)
if err != nil {
t.Errorf("Unable to create file %q: %v", configFilePath, err)
}
defer cfgFile.Close()
if _, err = cfgFile.WriteString(testInitConfig); err != nil {
t.Fatalf("Unable to write file %q: %v", configFilePath, err)
}
testCases := []struct {
name string
args []string
flags map[string]string
validate func(*testing.T, *initData)
expectError bool
}{
// Init data passed using flags
{
name: "pass without any flag (use defaults)",
},
{
name: "fail if unknown feature gates flag are passed",
flags: map[string]string{
options.FeatureGatesString: "unknown=true",
},
expectError: true,
},
{
name: "fail if deprecetes feature gates are set",
flags: map[string]string{
options.FeatureGatesString: fmt.Sprintf("%s=true", features.CoreDNS),
},
expectError: true,
},
{
name: "fails if invalid preflight checks are provided",
flags: map[string]string{
options.IgnorePreflightErrors: "all,something-else",
},
expectError: true,
},
// Init data passed using config file
{
name: "Pass with config from file",
flags: map[string]string{
options.CfgPath: configFilePath,
},
},
{
name: "--cri-socket and --node-name flags override config from file",
flags: map[string]string{
options.CfgPath: configFilePath,
options.NodeCRISocket: "/var/run/crio/crio.sock",
options.NodeName: "anotherName",
},
validate: func(t *testing.T, data *initData) {
// validate that cri-socket and node-name are overwritten
if data.cfg.NodeRegistration.CRISocket != "/var/run/crio/crio.sock" {
t.Errorf("Invalid NodeRegistration.CRISocket")
}
if data.cfg.NodeRegistration.Name != "anotherName" {
t.Errorf("Invalid NodeRegistration.Name")
}
},
},
{
name: "fail if mixedArguments are passed",
flags: map[string]string{
options.CfgPath: configFilePath,
options.APIServerAdvertiseAddress: "1.2.3.4",
},
expectError: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// initialize an external init option and inject it to the init cmd
initOptions := newInitOptions()
cmd := NewCmdInit(nil, initOptions)
// sets cmd flags (that will be reflected on the init options)
for f, v := range tc.flags {
cmd.Flags().Set(f, v)
}
// test newInitData method
data, err := newInitData(cmd, tc.args, initOptions, nil)
if err != nil && !tc.expectError {
t.Fatalf("newInitData returned unexpected error: %v", err)
}
if err == nil && tc.expectError {
t.Fatalf("newInitData didn't return error when expected")
}
// exec additional validation on the returned value
if tc.validate != nil {
tc.validate(t, data)
}
})
}
}
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package phases
import (
"io"
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
)
// a package local type for testing purposes.
type testInitData struct{}
// testInitData must satisfy InitData.
var _ InitData = &testInitData{}
func (t *testInitData) UploadCerts() bool { return false }
func (t *testInitData) CertificateKey() string { return "" }
func (t *testInitData) SetCertificateKey(key string) {}
func (t *testInitData) SkipCertificateKeyPrint() bool { return false }
func (t *testInitData) Cfg() *kubeadmapi.InitConfiguration { return nil }
func (t *testInitData) DryRun() bool { return false }
func (t *testInitData) SkipTokenPrint() bool { return false }
func (t *testInitData) IgnorePreflightErrors() sets.String { return nil }
func (t *testInitData) CertificateWriteDir() string { return "" }
func (t *testInitData) CertificateDir() string { return "" }
func (t *testInitData) KubeConfigDir() string { return "" }
func (t *testInitData) KubeConfigPath() string { return "" }
func (t *testInitData) ManifestDir() string { return "" }
func (t *testInitData) KubeletDir() string { return "" }
func (t *testInitData) ExternalCA() bool { return false }
func (t *testInitData) OutputWriter() io.Writer { return nil }
func (t *testInitData) Client() (clientset.Interface, error) { return nil, nil }
func (t *testInitData) Tokens() []string { return nil }
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package phases
import (
"io"
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
)
// a package local type for testing purposes.
type testJoinData struct{}
// testJoinData must satisfy JoinData.
var _ JoinData = &testJoinData{}
func (j *testJoinData) CertificateKey() string { return "" }
func (j *testJoinData) Cfg() *kubeadmapi.JoinConfiguration { return nil }
func (j *testJoinData) TLSBootstrapCfg() (*clientcmdapi.Config, error) { return nil, nil }
func (j *testJoinData) InitCfg() (*kubeadmapi.InitConfiguration, error) { return nil, nil }
func (j *testJoinData) ClientSet() (*clientset.Clientset, error) { return nil, nil }
func (j *testJoinData) IgnorePreflightErrors() sets.String { return nil }
func (j *testJoinData) OutputWriter() io.Writer { return nil }
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: 1.13.0
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package copycerts
import (
"encoding/hex"
"io/ioutil"
"os"
"path"
"regexp"
"testing"
"github.com/lithammer/dedent"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
cryptoutil "k8s.io/kubernetes/cmd/kubeadm/app/util/crypto"
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
)
func TestUploadCerts(t *testing.T) {
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
}
//teste cert name, teste cert can be decrypted
func TestGetDataFromInitConfig(t *testing.T) {
certData := []byte("cert-data")
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
cfg := &kubeadmapi.InitConfiguration{}
cfg.CertificatesDir = tmpdir
key, err := CreateCertificateKey()
if err != nil {
t.Fatalf(dedent.Dedent("failed to create key.\nfatal error: %v"), err)
}
decodedKey, err := hex.DecodeString(key)
if err != nil {
t.Fatalf(dedent.Dedent("failed to decode key.\nfatal error: %v"), err)
}
if err := os.Mkdir(path.Join(tmpdir, "etcd"), 0755); err != nil {
t.Fatalf(dedent.Dedent("failed to create etcd cert dir.\nfatal error: %v"), err)
}
certs := certsToTransfer(cfg)
for name, path := range certs {
if err := ioutil.WriteFile(path, certData, 0644); err != nil {
t.Fatalf(dedent.Dedent("failed to write cert: %s\nfatal error: %v"), name, err)
}
}
secretData, err := getDataFromDisk(cfg, decodedKey)
if err != nil {
t.Fatalf("failed to get secret data. fatal error: %v", err)
}
re := regexp.MustCompile(`[-._a-zA-Z0-9]+`)
for name, data := range secretData {
if !re.MatchString(name) {
t.Fatalf(dedent.Dedent("failed to validate secretData\n %s isn't a valid secret key"), name)
}
decryptedData, err := cryptoutil.DecryptBytes(data, decodedKey)
if string(certData) != string(decryptedData) {
t.Fatalf(dedent.Dedent("can't decript cert: %s\nfatal error: %v"), name, err)
}
}
}
func TestCertsToTransfer(t *testing.T) {
localEtcdCfg := &kubeadmapi.InitConfiguration{}
externalEtcdCfg := &kubeadmapi.InitConfiguration{}
externalEtcdCfg.Etcd = kubeadmapi.Etcd{}
externalEtcdCfg.Etcd.External = &kubeadmapi.ExternalEtcd{}
commonExpectedCerts := []string{
kubeadmconstants.CACertName,
kubeadmconstants.CAKeyName,
kubeadmconstants.FrontProxyCACertName,
kubeadmconstants.FrontProxyCAKeyName,
kubeadmconstants.ServiceAccountPublicKeyName,
kubeadmconstants.ServiceAccountPrivateKeyName,
}
tests := map[string]struct {
config *kubeadmapi.InitConfiguration
expectedCerts []string
}{
"local etcd": {
config: localEtcdCfg,
expectedCerts: append(
[]string{kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName},
commonExpectedCerts...,
),
},
"external etcd": {
config: externalEtcdCfg,
expectedCerts: append(
[]string{externalEtcdCA, externalEtcdCert, externalEtcdKey},
commonExpectedCerts...,
),
},
}
for name, test := range tests {
t.Run(name, func(t2 *testing.T) {
certList := certsToTransfer(test.config)
for _, cert := range test.expectedCerts {
if _, found := certList[cert]; !found {
t2.Fatalf(dedent.Dedent("failed to get list of certs to upload\ncert %s not found"), cert)
}
}
})
}
}
func TestCertOrKeyNameToSecretName(t *testing.T) {
tests := []struct {
keyName string
expectedSecretName string
}{
{
keyName: "apiserver-kubelet-client.crt",
expectedSecretName: "apiserver-kubelet-client.crt",
},
{
keyName: "etcd/ca.crt",
expectedSecretName: "etcd-ca.crt",
},
{
keyName: "etcd/healthcheck-client.crt",
expectedSecretName: "etcd-healthcheck-client.crt",
},
}
for _, tc := range tests {
secretName := certOrKeyNameToSecretName(tc.keyName)
if secretName != tc.expectedSecretName {
t.Fatalf("secret name %s didn't match expected name %s", secretName, tc.expectedSecretName)
}
}
}
APIServer:
CertSANs: null
ExtraArgs:
authorization-mode: Node,RBAC,Webhook
ExtraVolumes:
- HostPath: /host/read-only
MountPath: /mount/read-only
Name: ReadOnlyVolume
PathType: ""
ReadOnly: true
- HostPath: /host/writable
MountPath: /mount/writable
Name: WritableVolume
PathType: ""
ReadOnly: false
TimeoutForControlPlane: 4m0s
BootstrapTokens:
- Description: ""
Expires: null
Groups:
- system:bootstrappers:kubeadm:default-node-token
TTL: 24h0m0s
Token: s73ybu.6tw6wnqgp5z0wb77
Usages:
- signing
- authentication
CIImageRepository: ""
CertificatesDir: /etc/kubernetes/pki
ClusterName: kubernetes
ComponentConfigs:
KubeProxy:
BindAddress: 0.0.0.0
ClientConnection:
AcceptContentTypes: ""
Burst: 10
ContentType: application/vnd.kubernetes.protobuf
Kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
QPS: 5
ClusterCIDR: ""
ConfigSyncPeriod: 15m0s
Conntrack:
Max: null
MaxPerCore: 32768
Min: 131072
TCPCloseWaitTimeout: 1h0m0s
TCPEstablishedTimeout: 24h0m0s
EnableProfiling: false
FeatureGates:
ServiceNodeExclusion: true
SupportIPVSProxyMode: true
HealthzBindAddress: 0.0.0.0:10256
HostnameOverride: ""
IPTables:
MasqueradeAll: false
MasqueradeBit: 14
MinSyncPeriod: 0s
SyncPeriod: 30s
IPVS:
ExcludeCIDRs: null
MinSyncPeriod: 0s
Scheduler: ""
SyncPeriod: 30s
MetricsBindAddress: 127.0.0.1:10249
Mode: iptables
NodePortAddresses: null
OOMScoreAdj: -999
PortRange: ""
ResourceContainer: /kube-proxy
UDPIdleTimeout: 250ms
Winkernel:
EnableDSR: false
NetworkName: ""
SourceVip: ""
Kubelet:
Address: 1.2.3.4
Authentication:
Anonymous:
Enabled: false
Webhook:
CacheTTL: 2m0s
Enabled: true
X509:
ClientCAFile: /etc/kubernetes/pki/ca.crt
Authorization:
Mode: Webhook
Webhook:
CacheAuthorizedTTL: 5m0s
CacheUnauthorizedTTL: 30s
CPUCFSQuota: true
CPUCFSQuotaPeriod: 0s
CPUManagerPolicy: none
CPUManagerReconcilePeriod: 10s
CgroupDriver: cgroupfs
CgroupRoot: ""
CgroupsPerQOS: true
ClusterDNS:
- 10.96.0.10
ClusterDomain: cluster.local
ConfigMapAndSecretChangeDetectionStrategy: Watch
ContainerLogMaxFiles: 5
ContainerLogMaxSize: 10Mi
ContentType: application/vnd.kubernetes.protobuf
EnableContentionProfiling: false
EnableControllerAttachDetach: true
EnableDebuggingHandlers: true
EnforceNodeAllocatable:
- pods
EventBurst: 10
EventRecordQPS: 5
EvictionHard:
imagefs.available: 15%
memory.available: 100Mi
nodefs.available: 10%
EvictionMaxPodGracePeriod: 0
EvictionMinimumReclaim: null
EvictionPressureTransitionPeriod: 5m0s
EvictionSoft: null
EvictionSoftGracePeriod: null
FailSwapOn: true
FeatureGates: null
FileCheckFrequency: 20s
HTTPCheckFrequency: 20s
HairpinMode: promiscuous-bridge
HealthzBindAddress: 127.0.0.1
HealthzPort: 10248
IPTablesDropBit: 15
IPTablesMasqueradeBit: 14
ImageGCHighThresholdPercent: 85
ImageGCLowThresholdPercent: 80
ImageMinimumGCAge: 2m0s
KubeAPIBurst: 10
KubeAPIQPS: 5
KubeReserved: null
KubeReservedCgroup: ""
KubeletCgroups: ""
MakeIPTablesUtilChains: true
MaxOpenFiles: 1000000
MaxPods: 110
NodeLeaseDurationSeconds: 40
NodeStatusReportFrequency: 1m0s
NodeStatusUpdateFrequency: 10s
OOMScoreAdj: -999
PodCIDR: ""
PodPidsLimit: -1
PodsPerCore: 0
Port: 10250
ProtectKernelDefaults: false
QOSReserved: null
ReadOnlyPort: 0
RegistryBurst: 10
RegistryPullQPS: 5
ResolverConfig: /etc/resolv.conf
RotateCertificates: true
RuntimeRequestTimeout: 2m0s
SerializeImagePulls: true
ServerTLSBootstrap: false
StaticPodPath: /etc/kubernetes/manifests
StaticPodURL: ""
StaticPodURLHeader: null
StreamingConnectionIdleTimeout: 4h0m0s
SyncFrequency: 1m0s
SystemCgroups: ""
SystemReserved: null
SystemReservedCgroup: ""
TLSCertFile: ""
TLSCipherSuites: null
TLSMinVersion: ""
TLSPrivateKeyFile: ""
VolumeStatsAggPeriod: 1m0s
ControlPlaneEndpoint: ""
ControllerManager:
ExtraArgs: null
ExtraVolumes: null
DNS:
ImageRepository: ""
ImageTag: ""
Type: CoreDNS
Etcd:
External: null
Local:
DataDir: /var/lib/etcd
ExtraArgs: null
ImageRepository: ""
ImageTag: ""
PeerCertSANs: null
ServerCertSANs: null
FeatureGates: null
ImageRepository: k8s.gcr.io
KubernetesVersion: v1.12.2
LocalAPIEndpoint:
AdvertiseAddress: 192.168.2.2
BindPort: 6443
Networking:
DNSDomain: cluster.local
PodSubnet: ""
ServiceSubnet: 10.96.0.0/12
NodeRegistration:
CRISocket: /var/run/dockershim.sock
KubeletExtraArgs: null
Name: control-plane-1
Taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
Scheduler:
ExtraArgs: null
ExtraVolumes: null
UseHyperKubeImage: true
apiEndpoint:
advertiseAddress: 192.168.2.2
bindPort: 6443
apiVersion: kubeadm.k8s.io/v1alpha3
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: s73ybu.6tw6wnqgp5z0wb77
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: control-plane-1
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
---
apiServerExtraArgs:
authorization-mode: Node,RBAC,Webhook
apiServerExtraVolumes:
- hostPath: /host/read-only
mountPath: /mount/read-only
name: ReadOnlyVolume
- hostPath: /host/writable
mountPath: /mount/writable
name: WritableVolume
writable: true
apiVersion: kubeadm.k8s.io/v1alpha3
auditPolicy:
logDir: /var/log/kubernetes/audit
logMaxAge: 2
path: ""
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controlPlaneEndpoint: ""
etcd:
local:
dataDir: /var/lib/etcd
image: ""
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: v1.12.2
networking:
dnsDomain: cluster.local
podSubnet: ""
serviceSubnet: 10.96.0.0/12
unifiedControlPlaneImage: "k8s.gcr.io/hyperkube:v1.12.2"
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
clientConnection:
acceptContentTypes: ""
burst: 10
contentType: application/vnd.kubernetes.protobuf
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 5
clusterCIDR: ""
configSyncPeriod: 15m0s
conntrack:
max: null
maxPerCore: 32768
min: 131072
tcpCloseWaitTimeout: 1h0m0s
tcpEstablishedTimeout: 24h0m0s
enableProfiling: false
featureGates:
ServiceNodeExclusion: true
SupportIPVSProxyMode: true
healthzBindAddress: 0.0.0.0:10256
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: 14
minSyncPeriod: 0s
syncPeriod: 30s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
syncPeriod: 30s
kind: KubeProxyConfiguration
metricsBindAddress: 127.0.0.1:10249
mode: iptables
nodePortAddresses: null
oomScoreAdj: -999
portRange: ""
resourceContainer: /kube-proxy
udpIdleTimeout: 250ms
winkernel:
enableDSR: false
networkName: ""
sourceVip: ""
---
address: 1.2.3.4
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 2m0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
cgroupDriver: cgroupfs
cgroupsPerQOS: true
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
configMapAndSecretChangeDetectionStrategy: Watch
containerLogMaxFiles: 5
containerLogMaxSize: 10Mi
contentType: application/vnd.kubernetes.protobuf
cpuCFSQuota: true
cpuCFSQuotaPeriod: 0s
cpuManagerPolicy: none
cpuManagerReconcilePeriod: 10s
enableControllerAttachDetach: true
enableDebuggingHandlers: true
enforceNodeAllocatable:
- pods
eventBurst: 10
eventRecordQPS: 5
evictionHard:
imagefs.available: 15%
memory.available: 100Mi
nodefs.available: 10%
evictionPressureTransitionPeriod: 5m0s
failSwapOn: true
fileCheckFrequency: 20s
hairpinMode: promiscuous-bridge
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 20s
imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 80
imageMinimumGCAge: 2m0s
iptablesDropBit: 15
iptablesMasqueradeBit: 14
kind: KubeletConfiguration
kubeAPIBurst: 10
kubeAPIQPS: 5
makeIPTablesUtilChains: true
maxOpenFiles: 1000000
maxPods: 110
nodeLeaseDurationSeconds: 40
nodeStatusReportFrequency: 1m0s
nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999
podPidsLimit: -1
port: 10250
registryBurst: 10
registryPullQPS: 5
resolvConf: /etc/resolv.conf
rotateCertificates: true
runtimeRequestTimeout: 2m0s
serializeImagePulls: true
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 4h0m0s
syncFrequency: 1m0s
volumeStatsAggPeriod: 1m0s
apiVersion: kubeadm.k8s.io/v1beta1
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: s73ybu.6tw6wnqgp5z0wb77
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.2.2
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: control-plane-1
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
---
apiServer:
extraArgs:
authorization-mode: Node,RBAC,Webhook
extraVolumes:
- hostPath: /host/read-only
mountPath: /mount/read-only
name: ReadOnlyVolume
readOnly: true
- hostPath: /host/writable
mountPath: /mount/writable
name: WritableVolume
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta1
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controlPlaneEndpoint: ""
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: v1.12.2
networking:
dnsDomain: cluster.local
podSubnet: ""
serviceSubnet: 10.96.0.0/12
scheduler: {}
useHyperKubeImage: true
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
clientConnection:
acceptContentTypes: ""
burst: 10
contentType: application/vnd.kubernetes.protobuf
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 5
clusterCIDR: ""
configSyncPeriod: 15m0s
conntrack:
max: null
maxPerCore: 32768
min: 131072
tcpCloseWaitTimeout: 1h0m0s
tcpEstablishedTimeout: 24h0m0s
enableProfiling: false
featureGates:
ServiceNodeExclusion: true
SupportIPVSProxyMode: true
healthzBindAddress: 0.0.0.0:10256
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: 14
minSyncPeriod: 0s
syncPeriod: 30s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
syncPeriod: 30s
kind: KubeProxyConfiguration
metricsBindAddress: 127.0.0.1:10249
mode: iptables
nodePortAddresses: null
oomScoreAdj: -999
portRange: ""
resourceContainer: /kube-proxy
udpIdleTimeout: 250ms
winkernel:
enableDSR: false
networkName: ""
sourceVip: ""
---
address: 1.2.3.4
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 2m0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
cgroupDriver: cgroupfs
cgroupsPerQOS: true
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
configMapAndSecretChangeDetectionStrategy: Watch
containerLogMaxFiles: 5
containerLogMaxSize: 10Mi
contentType: application/vnd.kubernetes.protobuf
cpuCFSQuota: true
cpuCFSQuotaPeriod: 0s
cpuManagerPolicy: none
cpuManagerReconcilePeriod: 10s
enableControllerAttachDetach: true
enableDebuggingHandlers: true
enforceNodeAllocatable:
- pods
eventBurst: 10
eventRecordQPS: 5
evictionHard:
imagefs.available: 15%
memory.available: 100Mi
nodefs.available: 10%
evictionPressureTransitionPeriod: 5m0s
failSwapOn: true
fileCheckFrequency: 20s
hairpinMode: promiscuous-bridge
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 20s
imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 80
imageMinimumGCAge: 2m0s
iptablesDropBit: 15
iptablesMasqueradeBit: 14
kind: KubeletConfiguration
kubeAPIBurst: 10
kubeAPIQPS: 5
makeIPTablesUtilChains: true
maxOpenFiles: 1000000
maxPods: 110
nodeLeaseDurationSeconds: 40
nodeStatusReportFrequency: 1m0s
nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999
podPidsLimit: -1
port: 10250
registryBurst: 10
registryPullQPS: 5
resolvConf: /etc/resolv.conf
rotateCertificates: true
runtimeRequestTimeout: 2m0s
serializeImagePulls: true
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 4h0m0s
syncFrequency: 1m0s
volumeStatsAggPeriod: 1m0s
apiVersion: kubeadm.k8s.io/v1beta1
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: s73ybu.6tw6wnqgp5z0wb77
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.2.2
bindPort: 6443
nodeRegistration:
criSocket: /var/run/criruntime.sock
name: control-plane-1
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta1
certificatesDir: /var/lib/kubernetes/pki
clusterName: kubernetes
controlPlaneEndpoint: ""
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: my-company.com
kind: ClusterConfiguration
kubernetesVersion: v1.13.0
networking:
dnsDomain: cluster.global
podSubnet: 10.148.0.0/16
serviceSubnet: 10.196.0.0/12
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
clientConnection:
acceptContentTypes: ""
burst: 10
contentType: application/vnd.kubernetes.protobuf
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 5
clusterCIDR: 10.148.0.0/16
configSyncPeriod: 15m0s
conntrack:
max: null
maxPerCore: 32768
min: 131072
tcpCloseWaitTimeout: 1h0m0s
tcpEstablishedTimeout: 24h0m0s
enableProfiling: false
healthzBindAddress: 0.0.0.0:10256
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: 14
minSyncPeriod: 0s
syncPeriod: 30s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
syncPeriod: 30s
kind: KubeProxyConfiguration
metricsBindAddress: 127.0.0.1:10249
mode: ""
nodePortAddresses: null
oomScoreAdj: -999
portRange: ""
resourceContainer: /kube-proxy
udpIdleTimeout: 250ms
winkernel:
enableDSR: false
networkName: ""
sourceVip: ""
---
address: 0.0.0.0
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 2m0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
cgroupDriver: cgroupfs
cgroupsPerQOS: true
clusterDNS:
- 10.192.0.10
clusterDomain: cluster.global
configMapAndSecretChangeDetectionStrategy: Watch
containerLogMaxFiles: 5
containerLogMaxSize: 10Mi
contentType: application/vnd.kubernetes.protobuf
cpuCFSQuota: true
cpuCFSQuotaPeriod: 100ms
cpuManagerPolicy: none
cpuManagerReconcilePeriod: 10s
enableControllerAttachDetach: true
enableDebuggingHandlers: true
enforceNodeAllocatable:
- pods
eventBurst: 10
eventRecordQPS: 5
evictionHard:
imagefs.available: 15%
memory.available: 100Mi
nodefs.available: 10%
evictionPressureTransitionPeriod: 5m0s
failSwapOn: true
fileCheckFrequency: 20s
hairpinMode: promiscuous-bridge
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 20s
imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 80
imageMinimumGCAge: 2m0s
iptablesDropBit: 15
iptablesMasqueradeBit: 14
kind: KubeletConfiguration
kubeAPIBurst: 10
kubeAPIQPS: 5
makeIPTablesUtilChains: true
maxOpenFiles: 1000000
maxPods: 110
nodeLeaseDurationSeconds: 40
nodeStatusReportFrequency: 1m0s
nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999
podPidsLimit: -1
port: 10250
registryBurst: 10
registryPullQPS: 5
resolvConf: /etc/resolv.conf
rotateCertificates: true
runtimeRequestTimeout: 2m0s
serializeImagePulls: true
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 4h0m0s
syncFrequency: 1m0s
volumeStatsAggPeriod: 1m0s
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package crypto
import (
"testing"
"github.com/lithammer/dedent"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
)
func TestEncryptAndDecryptData(t *testing.T) {
key1, err := CreateRandBytes(kubeadmconstants.CertificateKeySize)
if err != nil {
t.Fatal(err)
}
key2, err := CreateRandBytes(kubeadmconstants.CertificateKeySize)
if err != nil {
t.Fatal(err)
}
testData := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
tests := map[string]struct {
encryptKey []byte
decryptKey []byte
data []byte
expectDecryptErr bool
}{
"can decrypt using the correct key": {
encryptKey: key1,
decryptKey: key1,
data: testData,
expectDecryptErr: false,
},
"can't decrypt using incorrect key": {
encryptKey: key1,
decryptKey: key2,
data: testData,
expectDecryptErr: true,
},
"can't decrypt without a key": {
encryptKey: key1,
decryptKey: []byte{},
data: testData,
expectDecryptErr: true,
},
}
for name, test := range tests {
t.Run(name, func(t2 *testing.T) {
encryptedData, err := EncryptBytes(test.data, test.encryptKey)
if err != nil {
t2.Fatalf(dedent.Dedent(
"EncryptBytes failed\nerror: %v"),
err,
)
}
decryptedData, err := DecryptBytes(encryptedData, test.decryptKey)
if (err != nil) != test.expectDecryptErr {
t2.Fatalf(dedent.Dedent(
"DecryptBytes failed\nexpected error: %t\n\tgot: %t\nerror: %v"),
test.expectDecryptErr,
(err != nil),
err,
)
}
if (string(decryptedData) != string(test.data)) && !test.expectDecryptErr {
t2.Fatalf(dedent.Dedent(
"EncryptDecryptBytes failed\nexpected decryptedData equal to data\n\tgot: data=%q decryptedData=%q"),
test.data,
string(decryptedData),
)
}
})
}
}
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package options
import (
"fmt"
"reflect"
"testing"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/diff"
cliflag "k8s.io/component-base/cli/flag"
)
func newKubeletServerOrDie() *KubeletServer {
s, err := NewKubeletServer()
if err != nil {
panic(err)
}
return s
}
func cleanFlags(s *KubeletServer) {
s.DynamicConfigDir = cliflag.NewStringFlag(s.DynamicConfigDir.Value())
}
// TestRoundTrip ensures that flag values from the Kubelet can be serialized
// to arguments and then read back and have the same value. Also catches cases
// where the default value reported by the flag is not actually allowed to be
// specified.
func TestRoundTrip(t *testing.T) {
testCases := []struct {
name string
inputFlags func() *KubeletServer
outputFlags func() *KubeletServer
flagDefaulter func(*pflag.FlagSet)
skipDefault bool
err bool
expectArgs bool
}{
{
name: "default flags are eliminated",
inputFlags: newKubeletServerOrDie,
outputFlags: newKubeletServerOrDie,
flagDefaulter: newKubeletServerOrDie().AddFlags,
err: false,
expectArgs: false,
},
{
name: "default flag values round trip",
inputFlags: newKubeletServerOrDie,
outputFlags: newKubeletServerOrDie,
flagDefaulter: func(*pflag.FlagSet) {},
err: false,
expectArgs: true,
},
{
name: "nil address does not fail for optional argument",
inputFlags: func() *KubeletServer {
s := newKubeletServerOrDie()
s.HealthzBindAddress = ""
return s
},
outputFlags: func() *KubeletServer {
s := newKubeletServerOrDie()
s.HealthzBindAddress = ""
return s
},
flagDefaulter: func(*pflag.FlagSet) {},
err: false,
expectArgs: true,
},
}
for _, testCase := range testCases {
modifiedFlags := testCase.inputFlags()
args := asArgs(modifiedFlags.AddFlags, testCase.flagDefaulter)
if testCase.expectArgs != (len(args) > 0) {
t.Errorf("%s: unexpected args: %v", testCase.name, args)
continue
}
t.Logf("%s: args: %v", testCase.name, args)
flagSet := pflag.NewFlagSet("output", pflag.ContinueOnError)
outputFlags := testCase.outputFlags()
outputFlags.AddFlags(flagSet)
if err := flagSet.Parse(args); err != nil {
if !testCase.err {
t.Errorf("%s: unexpected flag error: %v", testCase.name, err)
}
continue
}
cleanFlags(outputFlags)
if !reflect.DeepEqual(modifiedFlags, outputFlags) {
t.Errorf("%s: flags did not round trip: %s", testCase.name, diff.ObjectReflectDiff(modifiedFlags, outputFlags))
continue
}
}
}
func asArgs(fn, defaultFn func(*pflag.FlagSet)) []string {
fs := pflag.NewFlagSet("extended", pflag.ContinueOnError)
fn(fs)
defaults := pflag.NewFlagSet("defaults", pflag.ContinueOnError)
defaultFn(defaults)
var args []string
fs.VisitAll(func(flag *pflag.Flag) {
// if the flag implements cliflag.OmitEmpty and the value is Empty, then just omit it from the command line
if omit, ok := flag.Value.(cliflag.OmitEmpty); ok && omit.Empty() {
return
}
s := flag.Value.String()
// if the flag has the same value as the default, we can omit it without changing the meaning of the command line
var defaultValue string
if defaultFlag := defaults.Lookup(flag.Name); defaultFlag != nil {
defaultValue = defaultFlag.Value.String()
if s == defaultValue {
return
}
}
// if the flag is a string slice, each element is specified with an independent flag invocation
if values, err := fs.GetStringSlice(flag.Name); err == nil {
for _, s := range values {
args = append(args, fmt.Sprintf("--%s=%s", flag.Name, s))
}
} else {
if len(s) == 0 {
s = defaultValue
}
args = append(args, fmt.Sprintf("--%s=%s", flag.Name, s))
}
})
return args
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app
import (
"testing"
)
func TestValueOfAllocatableResources(t *testing.T) {
testCases := []struct {
kubeReserved map[string]string
systemReserved map[string]string
errorExpected bool
name string
}{
{
kubeReserved: map[string]string{"cpu": "200m", "memory": "-150G", "ephemeral-storage": "10Gi"},
systemReserved: map[string]string{"cpu": "200m", "memory": "15Ki"},
errorExpected: true,
name: "negative quantity value",
},
{
kubeReserved: map[string]string{"cpu": "200m", "memory": "150Gi", "ephemeral-storage": "10Gi"},
systemReserved: map[string]string{"cpu": "200m", "memory": "15Ky"},
errorExpected: true,
name: "invalid quantity unit",
},
{
kubeReserved: map[string]string{"cpu": "200m", "memory": "15G", "ephemeral-storage": "10Gi"},
systemReserved: map[string]string{"cpu": "200m", "memory": "15Ki"},
errorExpected: false,
name: "Valid resource quantity",
},
}
for _, test := range testCases {
_, err1 := parseResourceList(test.kubeReserved)
_, err2 := parseResourceList(test.systemReserved)
if test.errorExpected {
if err1 == nil && err2 == nil {
t.Errorf("%s: error expected", test.name)
}
} else {
if err1 != nil || err2 != nil {
t.Errorf("%s: unexpected error: %v, %v", test.name, err1, err2)
}
}
}
}
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package persistentvolume
import (
"reflect"
"testing"
"k8s.io/apimachinery/pkg/util/diff"
utilfeature "k8s.io/apiserver/pkg/util/feature"
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/features"
)
func TestDropDisabledFields(t *testing.T) {
specWithMode := func(mode *api.PersistentVolumeMode) *api.PersistentVolumeSpec {
return &api.PersistentVolumeSpec{VolumeMode: mode}
}
modeBlock := api.PersistentVolumeBlock
tests := map[string]struct {
oldSpec *api.PersistentVolumeSpec
newSpec *api.PersistentVolumeSpec
expectOldSpec *api.PersistentVolumeSpec
expectNewSpec *api.PersistentVolumeSpec
blockEnabled bool
}{
"disabled block clears new": {
blockEnabled: false,
newSpec: specWithMode(&modeBlock),
expectNewSpec: specWithMode(nil),
oldSpec: nil,
expectOldSpec: nil,
},
"disabled block clears update when old pv did not use block": {
blockEnabled: false,
newSpec: specWithMode(&modeBlock),
expectNewSpec: specWithMode(nil),
oldSpec: specWithMode(nil),
expectOldSpec: specWithMode(nil),
},
"disabled block does not clear new on update when old pv did use block": {
blockEnabled: false,
newSpec: specWithMode(&modeBlock),
expectNewSpec: specWithMode(&modeBlock),
oldSpec: specWithMode(&modeBlock),
expectOldSpec: specWithMode(&modeBlock),
},
"enabled block preserves new": {
blockEnabled: true,
newSpec: specWithMode(&modeBlock),
expectNewSpec: specWithMode(&modeBlock),
oldSpec: nil,
expectOldSpec: nil,
},
"enabled block preserves update when old pv did not use block": {
blockEnabled: true,
newSpec: specWithMode(&modeBlock),
expectNewSpec: specWithMode(&modeBlock),
oldSpec: specWithMode(nil),
expectOldSpec: specWithMode(nil),
},
"enabled block preserves update when old pv did use block": {
blockEnabled: true,
newSpec: specWithMode(&modeBlock),
expectNewSpec: specWithMode(&modeBlock),
oldSpec: specWithMode(&modeBlock),
expectOldSpec: specWithMode(&modeBlock),
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, tc.blockEnabled)()
DropDisabledFields(tc.newSpec, tc.oldSpec)
if !reflect.DeepEqual(tc.newSpec, tc.expectNewSpec) {
t.Error(diff.ObjectReflectDiff(tc.newSpec, tc.expectNewSpec))
}
if !reflect.DeepEqual(tc.oldSpec, tc.expectOldSpec) {
t.Error(diff.ObjectReflectDiff(tc.oldSpec, tc.expectOldSpec))
}
})
}
}
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package persistentvolumeclaim
import (
"fmt"
"reflect"
"testing"
"k8s.io/apimachinery/pkg/util/diff"
utilfeature "k8s.io/apiserver/pkg/util/feature"
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/features"
)
func TestDropAlphaPVCVolumeMode(t *testing.T) {
vmode := core.PersistentVolumeFilesystem
pvcWithoutVolumeMode := func() *core.PersistentVolumeClaim {
return &core.PersistentVolumeClaim{
Spec: core.PersistentVolumeClaimSpec{
VolumeMode: nil,
},
}
}
pvcWithVolumeMode := func() *core.PersistentVolumeClaim {
return &core.PersistentVolumeClaim{
Spec: core.PersistentVolumeClaimSpec{
VolumeMode: &vmode,
},
}
}
pvcInfo := []struct {
description string
hasVolumeMode bool
pvc func() *core.PersistentVolumeClaim
}{
{
description: "pvc without VolumeMode",
hasVolumeMode: false,
pvc: pvcWithoutVolumeMode,
},
{
description: "pvc with Filesystem VolumeMode",
hasVolumeMode: true,
pvc: pvcWithVolumeMode,
},
{
description: "is nil",
hasVolumeMode: false,
pvc: func() *core.PersistentVolumeClaim { return nil },
},
}
for _, enabled := range []bool{true, false} {
for _, oldpvcInfo := range pvcInfo {
for _, newpvcInfo := range pvcInfo {
oldpvcHasVolumeMode, oldpvc := oldpvcInfo.hasVolumeMode, oldpvcInfo.pvc()
newpvcHasVolumeMode, newpvc := newpvcInfo.hasVolumeMode, newpvcInfo.pvc()
if newpvc == nil {
continue
}
t.Run(fmt.Sprintf("feature enabled=%v, old pvc %v, new pvc %v", enabled, oldpvcInfo.description, newpvcInfo.description), func(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, enabled)()
var oldpvcSpec *core.PersistentVolumeClaimSpec
if oldpvc != nil {
oldpvcSpec = &oldpvc.Spec
}
DropDisabledFields(&newpvc.Spec, oldpvcSpec)
// old pvc should never be changed
if !reflect.DeepEqual(oldpvc, oldpvcInfo.pvc()) {
t.Errorf("old pvc changed: %v", diff.ObjectReflectDiff(oldpvc, oldpvcInfo.pvc()))
}
switch {
case enabled || oldpvcHasVolumeMode:
// new pvc should not be changed if the feature is enabled, or if the old pvc had BlockVolume
if !reflect.DeepEqual(newpvc, newpvcInfo.pvc()) {
t.Errorf("new pvc changed: %v", diff.ObjectReflectDiff(newpvc, newpvcInfo.pvc()))
}
case newpvcHasVolumeMode:
// new pvc should be changed
if reflect.DeepEqual(newpvc, newpvcInfo.pvc()) {
t.Errorf("new pvc was not changed")
}
// new pvc should not have BlockVolume
if !reflect.DeepEqual(newpvc, pvcWithoutVolumeMode()) {
t.Errorf("new pvc had pvcBlockVolume: %v", diff.ObjectReflectDiff(newpvc, pvcWithoutVolumeMode()))
}
default:
// new pvc should not need to be changed
if !reflect.DeepEqual(newpvc, newpvcInfo.pvc()) {
t.Errorf("new pvc changed: %v", diff.ObjectReflectDiff(newpvc, newpvcInfo.pvc()))
}
}
})
}
}
}
}
func TestDropDisabledDataSource(t *testing.T) {
pvcWithoutDataSource := func() *core.PersistentVolumeClaim {
return &core.PersistentVolumeClaim{
Spec: core.PersistentVolumeClaimSpec{
DataSource: nil,
},
}
}
apiGroup := "snapshot.storage.k8s.io"
pvcWithDataSource := func() *core.PersistentVolumeClaim {
return &core.PersistentVolumeClaim{
Spec: core.PersistentVolumeClaimSpec{
DataSource: &core.TypedLocalObjectReference{
APIGroup: &apiGroup,
Kind: "VolumeSnapshot",
Name: "test_snapshot",
},
},
}
}
pvcInfo := []struct {
description string
hasDataSource bool
pvc func() *core.PersistentVolumeClaim
}{
{
description: "pvc without DataSource",
hasDataSource: false,
pvc: pvcWithoutDataSource,
},
{
description: "pvc with DataSource",
hasDataSource: true,
pvc: pvcWithDataSource,
},
{
description: "is nil",
hasDataSource: false,
pvc: func() *core.PersistentVolumeClaim { return nil },
},
}
for _, enabled := range []bool{true, false} {
for _, oldpvcInfo := range pvcInfo {
for _, newpvcInfo := range pvcInfo {
oldPvcHasDataSource, oldpvc := oldpvcInfo.hasDataSource, oldpvcInfo.pvc()
newPvcHasDataSource, newpvc := newpvcInfo.hasDataSource, newpvcInfo.pvc()
if newpvc == nil {
continue
}
t.Run(fmt.Sprintf("feature enabled=%v, old pvc %v, new pvc %v", enabled, oldpvcInfo.description, newpvcInfo.description), func(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeSnapshotDataSource, enabled)()
var oldpvcSpec *core.PersistentVolumeClaimSpec
if oldpvc != nil {
oldpvcSpec = &oldpvc.Spec
}
DropDisabledFields(&newpvc.Spec, oldpvcSpec)
// old pvc should never be changed
if !reflect.DeepEqual(oldpvc, oldpvcInfo.pvc()) {
t.Errorf("old pvc changed: %v", diff.ObjectReflectDiff(oldpvc, oldpvcInfo.pvc()))
}
switch {
case enabled || oldPvcHasDataSource:
// new pvc should not be changed if the feature is enabled, or if the old pvc had DataSource
if !reflect.DeepEqual(newpvc, newpvcInfo.pvc()) {
t.Errorf("new pvc changed: %v", diff.ObjectReflectDiff(newpvc, newpvcInfo.pvc()))
}
case newPvcHasDataSource:
// new pvc should be changed
if reflect.DeepEqual(newpvc, newpvcInfo.pvc()) {
t.Errorf("new pvc was not changed")
}
// new pvc should not have DataSource
if !reflect.DeepEqual(newpvc, pvcWithoutDataSource()) {
t.Errorf("new pvc had DataSource: %v", diff.ObjectReflectDiff(newpvc, pvcWithoutDataSource()))
}
default:
// new pvc should not need to be changed
if !reflect.DeepEqual(newpvc, newpvcInfo.pvc()) {
t.Errorf("new pvc changed: %v", diff.ObjectReflectDiff(newpvc, newpvcInfo.pvc()))
}
}
})
}
}
}
}
/*
Copyright 2014 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ref
import (
"reflect"
"testing"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api/legacyscheme"
api "k8s.io/kubernetes/pkg/apis/core"
)
type FakeAPIObject struct{}
func (obj *FakeAPIObject) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
func (obj *FakeAPIObject) DeepCopyObject() runtime.Object {
if obj == nil {
return nil
}
clone := *obj
return &clone
}
type ExtensionAPIObject struct {
metav1.TypeMeta
metav1.ObjectMeta
}
func (obj *ExtensionAPIObject) DeepCopyObject() runtime.Object {
panic("ExtensionAPIObject does not support DeepCopy")
}
func TestGetReference(t *testing.T) {
// when vendoring kube, if you don't force the set of registered versions (like make test does)
// then you run into trouble because the types aren't registered in the scheme by anything. This does the
// register manually to allow unit test execution
if _, _, err := legacyscheme.Scheme.ObjectKinds(&api.Pod{}); err != nil {
require.NoError(t, api.AddToScheme(legacyscheme.Scheme))
}
table := map[string]struct {
obj runtime.Object
ref *api.ObjectReference
fieldPath string
shouldErr bool
}{
"pod": {
obj: &api.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
UID: "bar",
ResourceVersion: "42",
SelfLink: "/api/version1/pods/foo",
},
},
fieldPath: ".desiredState.containers[0]",
ref: &api.ObjectReference{
Kind: "Pod",
APIVersion: "version1",
Name: "foo",
UID: "bar",
ResourceVersion: "42",
FieldPath: ".desiredState.containers[0]",
},
},
"serviceList": {
obj: &api.ServiceList{
ListMeta: metav1.ListMeta{
ResourceVersion: "42",
SelfLink: "/api/version2/services",
},
},
ref: &api.ObjectReference{
Kind: "ServiceList",
APIVersion: "version2",
ResourceVersion: "42",
},
},
"extensionAPIObject": {
obj: &ExtensionAPIObject{
TypeMeta: metav1.TypeMeta{
Kind: "ExtensionAPIObject",
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
UID: "bar",
ResourceVersion: "42",
SelfLink: "/custom_prefix/version1/extensions/foo",
},
},
ref: &api.ObjectReference{
Kind: "ExtensionAPIObject",
APIVersion: "version1",
Name: "foo",
UID: "bar",
ResourceVersion: "42",
},
},
"badSelfLink": {
obj: &api.ServiceList{
ListMeta: metav1.ListMeta{
ResourceVersion: "42",
SelfLink: "version2/services",
},
},
shouldErr: true,
},
"error": {
obj: &FakeAPIObject{},
ref: nil,
shouldErr: true,
},
"errorNil": {
obj: nil,
ref: nil,
shouldErr: true,
},
}
for name, item := range table {
ref, err := GetPartialReference(legacyscheme.Scheme, item.obj, item.fieldPath)
if e, a := item.shouldErr, (err != nil); e != a {
t.Errorf("%v: expected %v, got %v, err %v", name, e, a, err)
continue
}
if e, a := item.ref, ref; !reflect.DeepEqual(e, a) {
t.Errorf("%v: expected %#v, got %#v", name, e, a)
}
}
}
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource
import (
"strings"
"testing"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/uuid"
api "k8s.io/kubernetes/pkg/apis/core"
)
func TestResourceHelpers(t *testing.T) {
cpuLimit := resource.MustParse("10")
memoryLimit := resource.MustParse("10G")
resourceSpec := api.ResourceRequirements{
Limits: api.ResourceList{
api.ResourceCPU: cpuLimit,
api.ResourceMemory: memoryLimit,
},
}
if res := resourceSpec.Limits.Cpu(); res.Cmp(cpuLimit) != 0 {
t.Errorf("expected cpulimit %v, got %v", cpuLimit, res)
}
if res := resourceSpec.Limits.Memory(); res.Cmp(memoryLimit) != 0 {
t.Errorf("expected memorylimit %v, got %v", memoryLimit, res)
}
resourceSpec = api.ResourceRequirements{
Limits: api.ResourceList{
api.ResourceMemory: memoryLimit,
},
}
if res := resourceSpec.Limits.Cpu(); res.Value() != 0 {
t.Errorf("expected cpulimit %v, got %v", 0, res)
}
if res := resourceSpec.Limits.Memory(); res.Cmp(memoryLimit) != 0 {
t.Errorf("expected memorylimit %v, got %v", memoryLimit, res)
}
}
func TestDefaultResourceHelpers(t *testing.T) {
resourceList := api.ResourceList{}
if resourceList.Cpu().Format != resource.DecimalSI {
t.Errorf("expected %v, actual %v", resource.DecimalSI, resourceList.Cpu().Format)
}
if resourceList.Memory().Format != resource.BinarySI {
t.Errorf("expected %v, actual %v", resource.BinarySI, resourceList.Memory().Format)
}
}
func TestPodRequestsAndLimits(t *testing.T) {
tests := []struct {
name string
pod *api.Pod
expectreqs map[api.ResourceName]resource.Quantity
expectlimits map[api.ResourceName]resource.Quantity
}{
{
name: "InitContainers resource < Containers resource",
pod: &api.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: uuid.NewUUID(),
},
Spec: api.PodSpec{
InitContainers: []api.Container{
makeContainer("100m", "200m", "100Mi", "200Mi"),
},
Containers: []api.Container{
makeContainer("100m", "400m", "100Mi", "400Mi"),
makeContainer("100m", "200m", "100Mi", "200Mi"),
},
},
},
expectreqs: map[api.ResourceName]resource.Quantity{
api.ResourceCPU: resource.MustParse("200m"),
api.ResourceMemory: resource.MustParse("200Mi"),
},
expectlimits: map[api.ResourceName]resource.Quantity{
api.ResourceCPU: resource.MustParse("600m"),
api.ResourceMemory: resource.MustParse("600Mi"),
},
},
{
name: "InitContainers resource > Containers resource",
pod: &api.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: uuid.NewUUID(),
},
Spec: api.PodSpec{
InitContainers: []api.Container{
makeContainer("500m", "500m", "500Mi", "500Mi"),
makeContainer("100m", "200m", "100Mi", "200Mi"),
},
Containers: []api.Container{
makeContainer("100m", "200m", "100Mi", "200Mi"),
makeContainer("100m", "200m", "100Mi", "200Mi"),
},
},
},
expectreqs: map[api.ResourceName]resource.Quantity{
api.ResourceCPU: resource.MustParse("500m"),
api.ResourceMemory: resource.MustParse("500Mi"),
},
expectlimits: map[api.ResourceName]resource.Quantity{
api.ResourceCPU: resource.MustParse("500m"),
api.ResourceMemory: resource.MustParse("500Mi"),
},
},
}
for i, test := range tests {
t.Run(test.name, func(t *testing.T) {
requests, limits := PodRequestsAndLimits(test.pod)
for name, quantity := range test.expectreqs {
if value, ok := requests[name]; !ok {
t.Errorf("case[%d]: Error to get value of key=%s from requests result", i, name)
} else if quantity.Cmp(value) != 0 {
t.Errorf("case[%d]: Expected value of key=%s from requests result:%v, Got:%v", i, name, quantity, value)
}
}
for name, quantity := range test.expectlimits {
if value, ok := limits[name]; !ok {
t.Errorf("case[%d]: Error to get value of key=%s from limits result", i, name)
} else if quantity.Cmp(value) != 0 {
t.Errorf("case[%d]: Expected value of key=%s from limits result:%v, Got:%v", i, name, quantity, value)
}
}
})
}
}
func TestExtractContainerResourceValue(t *testing.T) {
testcontainer := &api.Container{
Name: string(uuid.NewUUID()),
Resources: api.ResourceRequirements{
Limits: api.ResourceList{
api.ResourceCPU: resource.MustParse("200m"),
api.ResourceMemory: resource.MustParse("200Mi"),
api.ResourceStorage: resource.MustParse("2G"),
api.ResourceEphemeralStorage: resource.MustParse("2G"),
},
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("100Mi"),
api.ResourceStorage: resource.MustParse("1G"),
api.ResourceEphemeralStorage: resource.MustParse("300Mi"),
},
},
}
tests := []struct {
name string
filed *api.ResourceFieldSelector
expectresult string
expecterr string
}{
{
name: "get limits cpu",
filed: &api.ResourceFieldSelector{Resource: "limits.cpu", Divisor: resource.MustParse("1m")},
expectresult: "200",
expecterr: "",
},
{
name: "get limits memory",
filed: &api.ResourceFieldSelector{Resource: "limits.memory"},
expectresult: "209715200",
expecterr: "",
},
{
name: "get limits ephemeral-storage",
filed: &api.ResourceFieldSelector{Resource: "limits.ephemeral-storage", Divisor: resource.MustParse("1G")},
expectresult: "2",
expecterr: "",
},
{
name: "get requests cpu",
filed: &api.ResourceFieldSelector{Resource: "requests.cpu", Divisor: resource.MustParse("1m")},
expectresult: "100",
expecterr: "",
},
{
name: "get requests memory",
filed: &api.ResourceFieldSelector{Resource: "requests.memory", Divisor: resource.MustParse("1G")},
expectresult: "1",
expecterr: "",
},
{
name: "get requests ephemeral-storage",
filed: &api.ResourceFieldSelector{Resource: "requests.ephemeral-storage"},
expectresult: "314572800",
expecterr: "",
},
{
name: "get limits storage",
filed: &api.ResourceFieldSelector{Resource: "limits.storage", Divisor: resource.MustParse("1G")},
expectresult: "",
expecterr: "unsupported container resource",
},
}
for i, test := range tests {
t.Run(test.name, func(t *testing.T) {
result, err := ExtractContainerResourceValue(test.filed, testcontainer)
if test.expecterr != "" {
if !strings.Contains(err.Error(), test.expecterr) {
t.Errorf("case[%d]:%s Expected err:%s, Got err:%s", i, test.name, test.expecterr, err.Error())
}
} else if err != nil {
t.Errorf("case[%d]:%s Expected no err, Got err:%s", i, test.name, err.Error())
}
if result != test.expectresult {
t.Errorf("case[%d]:%s Expected result:%s, Got result:%s", i, test.name, test.expectresult, result)
}
})
}
}
func makeContainer(cpuReq, cpuLim, memReq, memLim string) api.Container {
return api.Container{
Name: string(uuid.NewUUID()),
Resources: api.ResourceRequirements{
Limits: api.ResourceList{
api.ResourceCPU: resource.MustParse(cpuLim),
api.ResourceMemory: resource.MustParse(memLim),
},
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse(cpuReq),
api.ResourceMemory: resource.MustParse(memReq),
},
},
}
}
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resourcequota
import (
"fmt"
"reflect"
"testing"
"k8s.io/apimachinery/pkg/util/diff"
utilfeature "k8s.io/apiserver/pkg/util/feature"
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/features"
)
func TestDropDisabledFields(t *testing.T) {
rqWithScopeSelector := func() *api.ResourceQuota {
return &api.ResourceQuota{Spec: api.ResourceQuotaSpec{Scopes: []api.ResourceQuotaScope{"scope-1"}, ScopeSelector: &api.ScopeSelector{
MatchExpressions: []api.ScopedResourceSelectorRequirement{
{
ScopeName: api.ResourceQuotaScopePriorityClass,
Operator: api.ScopeSelectorOpIn,
Values: []string{"scope-1"},
},
},
}}}
}
rqWithoutScopeSelector := func() *api.ResourceQuota {
return &api.ResourceQuota{Spec: api.ResourceQuotaSpec{Scopes: []api.ResourceQuotaScope{"scope-1"}, ScopeSelector: nil}}
}
rqInfo := []struct {
description string
hasScopeSelector bool
resourceQuota func() *api.ResourceQuota
}{
{
description: "ResourceQuota without Scopes Selector",
hasScopeSelector: false,
resourceQuota: rqWithoutScopeSelector,
},
{
description: "ResourceQuota with Scope Selector",
hasScopeSelector: true,
resourceQuota: rqWithScopeSelector,
},
{
description: "is nil",
hasScopeSelector: false,
resourceQuota: func() *api.ResourceQuota { return nil },
},
}
for _, enabled := range []bool{true, false} {
for _, oldRQInfo := range rqInfo {
for _, newRQInfo := range rqInfo {
oldRQHasSelector, oldrq := oldRQInfo.hasScopeSelector, oldRQInfo.resourceQuota()
newRQHasSelector, newrq := newRQInfo.hasScopeSelector, newRQInfo.resourceQuota()
if newrq == nil {
continue
}
t.Run(fmt.Sprintf("feature enabled=%v, old ResourceQuota %v, new ResourceQuota %v", enabled, oldRQInfo.description, newRQInfo.description), func(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ResourceQuotaScopeSelectors, enabled)()
var oldRQSpec *api.ResourceQuotaSpec
if oldrq != nil {
oldRQSpec = &oldrq.Spec
}
DropDisabledFields(&newrq.Spec, oldRQSpec)
// old ResourceQuota should never be changed
if !reflect.DeepEqual(oldrq, oldRQInfo.resourceQuota()) {
t.Errorf("old ResourceQuota changed: %v", diff.ObjectReflectDiff(oldrq, oldRQInfo.resourceQuota()))
}
switch {
case enabled || oldRQHasSelector:
// new ResourceQuota should not be changed if the feature is enabled, or if the old ResourceQuota had ScopeSelector
if !reflect.DeepEqual(newrq, newRQInfo.resourceQuota()) {
t.Errorf("new ResourceQuota changed: %v", diff.ObjectReflectDiff(newrq, newRQInfo.resourceQuota()))
}
case newRQHasSelector:
// new ResourceQuota should be changed
if reflect.DeepEqual(newrq, newRQInfo.resourceQuota()) {
t.Errorf("new ResourceQuota was not changed")
}
// new ResourceQuota should not have ScopeSelector
if !reflect.DeepEqual(newrq, rqWithoutScopeSelector()) {
t.Errorf("new ResourceQuota had ScopeSelector: %v", diff.ObjectReflectDiff(newrq, rqWithoutScopeSelector()))
}
default:
// new ResourceQuota should not need to be changed
if !reflect.DeepEqual(newrq, newRQInfo.resourceQuota()) {
t.Errorf("new ResourceQuota changed: %v", diff.ObjectReflectDiff(newrq, newRQInfo.resourceQuota()))
}
}
})
}
}
}
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package service
import (
"strings"
"testing"
api "k8s.io/kubernetes/pkg/apis/core"
utilnet "k8s.io/utils/net"
)
func TestGetLoadBalancerSourceRanges(t *testing.T) {
checkError := func(v string) {
annotations := make(map[string]string)
annotations[api.AnnotationLoadBalancerSourceRangesKey] = v
svc := api.Service{}
svc.Annotations = annotations
_, err := GetLoadBalancerSourceRanges(&svc)
if err == nil {
t.Errorf("Expected error parsing: %q", v)
}
svc = api.Service{}
svc.Spec.LoadBalancerSourceRanges = strings.Split(v, ",")
_, err = GetLoadBalancerSourceRanges(&svc)
if err == nil {
t.Errorf("Expected error parsing: %q", v)
}
}
checkError("10.0.0.1/33")
checkError("foo.bar")
checkError("10.0.0.1/32,*")
checkError("10.0.0.1/32,")
checkError("10.0.0.1/32, ")
checkError("10.0.0.1")
checkOK := func(v string) utilnet.IPNetSet {
annotations := make(map[string]string)
annotations[api.AnnotationLoadBalancerSourceRangesKey] = v
svc := api.Service{}
svc.Annotations = annotations
cidrs, err := GetLoadBalancerSourceRanges(&svc)
if err != nil {
t.Errorf("Unexpected error parsing: %q", v)
}
svc = api.Service{}
svc.Spec.LoadBalancerSourceRanges = strings.Split(v, ",")
cidrs, err = GetLoadBalancerSourceRanges(&svc)
if err != nil {
t.Errorf("Unexpected error parsing: %q", v)
}
return cidrs
}
cidrs := checkOK("192.168.0.1/32")
if len(cidrs) != 1 {
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
}
cidrs = checkOK("192.168.0.1/32,192.168.0.1/32")
if len(cidrs) != 1 {
t.Errorf("Expected exactly one CIDR (after de-dup): %v", cidrs.StringSlice())
}
cidrs = checkOK("192.168.0.1/32,192.168.0.2/32")
if len(cidrs) != 2 {
t.Errorf("Expected two CIDRs: %v", cidrs.StringSlice())
}
cidrs = checkOK(" 192.168.0.1/32 , 192.168.0.2/32 ")
if len(cidrs) != 2 {
t.Errorf("Expected two CIDRs: %v", cidrs.StringSlice())
}
// check LoadBalancerSourceRanges not specified
svc := api.Service{}
cidrs, err := GetLoadBalancerSourceRanges(&svc)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if len(cidrs) != 1 {
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
}
if !IsAllowAll(cidrs) {
t.Errorf("Expected default to be allow-all: %v", cidrs.StringSlice())
}
// check SourceRanges annotation is empty
annotations := make(map[string]string)
annotations[api.AnnotationLoadBalancerSourceRangesKey] = ""
svc = api.Service{}
svc.Annotations = annotations
cidrs, err = GetLoadBalancerSourceRanges(&svc)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if len(cidrs) != 1 {
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
}
if !IsAllowAll(cidrs) {
t.Errorf("Expected default to be allow-all: %v", cidrs.StringSlice())
}
}
func TestAllowAll(t *testing.T) {
checkAllowAll := func(allowAll bool, cidrs ...string) {
ipnets, err := utilnet.ParseIPNets(cidrs...)
if err != nil {
t.Errorf("Unexpected error parsing cidrs: %v", cidrs)
}
if allowAll != IsAllowAll(ipnets) {
t.Errorf("IsAllowAll did not return expected value for %v", cidrs)
}
}
checkAllowAll(false, "10.0.0.1/32")
checkAllowAll(false, "10.0.0.1/32", "10.0.0.2/32")
checkAllowAll(false, "10.0.0.1/32", "10.0.0.1/32")
checkAllowAll(true, "0.0.0.0/0")
checkAllowAll(true, "192.168.0.0/0")
checkAllowAll(true, "192.168.0.1/32", "0.0.0.0/0")
}
func TestRequestsOnlyLocalTraffic(t *testing.T) {
checkRequestsOnlyLocalTraffic := func(requestsOnlyLocalTraffic bool, service *api.Service) {
res := RequestsOnlyLocalTraffic(service)
if res != requestsOnlyLocalTraffic {
t.Errorf("Expected requests OnlyLocal traffic = %v, got %v",
requestsOnlyLocalTraffic, res)
}
}
checkRequestsOnlyLocalTraffic(false, &api.Service{})
checkRequestsOnlyLocalTraffic(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeClusterIP,
},
})
checkRequestsOnlyLocalTraffic(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeNodePort,
},
})
checkRequestsOnlyLocalTraffic(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeNodePort,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkRequestsOnlyLocalTraffic(true, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeNodePort,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
},
})
checkRequestsOnlyLocalTraffic(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkRequestsOnlyLocalTraffic(true, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
},
})
}
func TestNeedsHealthCheck(t *testing.T) {
checkNeedsHealthCheck := func(needsHealthCheck bool, service *api.Service) {
res := NeedsHealthCheck(service)
if res != needsHealthCheck {
t.Errorf("Expected needs health check = %v, got %v",
needsHealthCheck, res)
}
}
checkNeedsHealthCheck(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeClusterIP,
},
})
checkNeedsHealthCheck(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeNodePort,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkNeedsHealthCheck(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeNodePort,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
},
})
checkNeedsHealthCheck(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
},
})
checkNeedsHealthCheck(true, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeLoadBalancer,
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
},
})
}
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testapi
import (
"encoding/json"
"reflect"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
func TestResourcePathWithPrefix(t *testing.T) {
testCases := []struct {
prefix string
resource string
namespace string
name string
expected string
}{
{"prefix", "resource", "mynamespace", "myresource", "/api/" + Default.GroupVersion().Version + "/prefix/namespaces/mynamespace/resource/myresource"},
{"prefix", "resource", "", "myresource", "/api/" + Default.GroupVersion().Version + "/prefix/resource/myresource"},
{"prefix", "resource", "mynamespace", "", "/api/" + Default.GroupVersion().Version + "/prefix/namespaces/mynamespace/resource"},
{"prefix", "resource", "", "", "/api/" + Default.GroupVersion().Version + "/prefix/resource"},
{"", "resource", "mynamespace", "myresource", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource/myresource"},
}
for _, item := range testCases {
if actual := Default.ResourcePathWithPrefix(item.prefix, item.resource, item.namespace, item.name); actual != item.expected {
t.Errorf("Expected: %s, got: %s for prefix: %s, resource: %s, namespace: %s and name: %s", item.expected, actual, item.prefix, item.resource, item.namespace, item.name)
}
}
testGroupCases := []struct {
prefix string
resource string
namespace string
name string
expected string
}{
{"prefix", "resource", "mynamespace", "myresource", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/prefix/namespaces/mynamespace/resource/myresource"},
{"prefix", "resource", "", "myresource", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/prefix/resource/myresource"},
{"prefix", "resource", "mynamespace", "", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/prefix/namespaces/mynamespace/resource"},
{"prefix", "resource", "", "", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/prefix/resource"},
{"", "resource", "mynamespace", "myresource", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/namespaces/mynamespace/resource/myresource"},
}
for _, item := range testGroupCases {
if actual := Admission.ResourcePathWithPrefix(item.prefix, item.resource, item.namespace, item.name); actual != item.expected {
t.Errorf("Expected: %s, got: %s for prefix: %s, resource: %s, namespace: %s and name: %s", item.expected, actual, item.prefix, item.resource, item.namespace, item.name)
}
}
}
func TestResourcePath(t *testing.T) {
testCases := []struct {
resource string
namespace string
name string
expected string
}{
{"resource", "mynamespace", "myresource", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource/myresource"},
{"resource", "", "myresource", "/api/" + Default.GroupVersion().Version + "/resource/myresource"},
{"resource", "mynamespace", "", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource"},
{"resource", "", "", "/api/" + Default.GroupVersion().Version + "/resource"},
}
for _, item := range testCases {
if actual := Default.ResourcePath(item.resource, item.namespace, item.name); actual != item.expected {
t.Errorf("Expected: %s, got: %s for resource: %s, namespace: %s and name: %s", item.expected, actual, item.resource, item.namespace, item.name)
}
}
}
func TestSubResourcePath(t *testing.T) {
testCases := []struct {
resource string
namespace string
name string
sub string
expected string
}{
{"resource", "mynamespace", "myresource", "mysub", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource/myresource/mysub"},
{"resource", "", "myresource", "mysub", "/api/" + Default.GroupVersion().Version + "/resource/myresource/mysub"},
{"resource", "mynamespace", "", "mysub", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource/mysub"},
{"resource", "", "", "mysub", "/api/" + Default.GroupVersion().Version + "/resource/mysub"},
}
for _, item := range testCases {
if actual := Default.SubResourcePath(item.resource, item.namespace, item.name, item.sub); actual != item.expected {
t.Errorf("Expected: %s, got: %s for resource: %s, namespace: %s and name: %s", item.expected, actual, item.resource, item.namespace, item.name)
}
}
}
var status = &metav1.Status{
Status: metav1.StatusFailure,
Code: 200,
Reason: metav1.StatusReasonUnknown,
Message: "",
}
func TestSelfLink(t *testing.T) {
testCases := []struct {
resource string
name string
expected string
}{
{"resource", "name", "/api/" + Default.GroupVersion().Version + "/resource/name"},
{"resource", "", "/api/" + Default.GroupVersion().Version + "/resource"},
}
for _, item := range testCases {
if actual := Default.SelfLink(item.resource, item.name); actual != item.expected {
t.Errorf("Expected: %s, got: %s for resource: %s and name: %s", item.expected, actual, item.resource, item.name)
}
}
testGroupCases := []struct {
resource string
name string
expected string
}{
{"resource", "name", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/resource/name"},
{"resource", "", "/apis/" + Admission.GroupVersion().Group + "/" + Admission.GroupVersion().Version + "/resource"},
}
for _, item := range testGroupCases {
if actual := Admission.SelfLink(item.resource, item.name); actual != item.expected {
t.Errorf("Expected: %s, got: %s for resource: %s and name: %s", item.expected, actual, item.resource, item.name)
}
}
}
func TestV1EncodeDecodeStatus(t *testing.T) {
v1Codec := Default.Codec()
encoded, err := runtime.Encode(v1Codec, status)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
typeMeta := metav1.TypeMeta{}
if err := json.Unmarshal(encoded, &typeMeta); err != nil {
t.Errorf("unexpected error: %v", err)
}
if typeMeta.Kind != "Status" {
t.Errorf("Kind is not set to \"Status\". Got %v", string(encoded))
}
if typeMeta.APIVersion != "v1" {
t.Errorf("APIVersion is not set to \"v1\". Got %v", string(encoded))
}
decoded, err := runtime.Decode(v1Codec, encoded)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if !reflect.DeepEqual(status, decoded) {
t.Errorf("expected: %#v, got: %#v", status, decoded)
}
}
func testEncodeDecodeStatus(t *testing.T, codec runtime.Codec) {
encoded, err := runtime.Encode(codec, status)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
typeMeta := metav1.TypeMeta{}
if err := json.Unmarshal(encoded, &typeMeta); err != nil {
t.Errorf("unexpected error: %v", err)
}
if typeMeta.Kind != "Status" {
t.Errorf("Kind is not set to \"Status\". Got %s", encoded)
}
if typeMeta.APIVersion != "v1" {
t.Errorf("APIVersion is not set to \"\". Got %s", encoded)
}
decoded, err := runtime.Decode(codec, encoded)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if !reflect.DeepEqual(status, decoded) {
t.Errorf("expected: %v, got: %v", status, decoded)
}
}
func TestAutoscalingEncodeDecodeStatus(t *testing.T) {
testEncodeDecodeStatus(t, Autoscaling.Codec())
}
func TestBatchEncodeDecodeStatus(t *testing.T) {
testEncodeDecodeStatus(t, Batch.Codec())
}
func TestExperimentalEncodeDecodeStatus(t *testing.T) {
testEncodeDecodeStatus(t, Extensions.Codec())
}
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"conversion.go",
"doc.go",
"fuzzer.go",
"pod_specs.go",
],
importpath = "k8s.io/kubernetes/pkg/api/testing",
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/admissionregistration/fuzzer:go_default_library",
"//pkg/apis/apps:go_default_library",
"//pkg/apis/apps/fuzzer:go_default_library",
"//pkg/apis/auditregistration/fuzzer:go_default_library",
"//pkg/apis/autoscaling/fuzzer:go_default_library",
"//pkg/apis/batch/fuzzer:go_default_library",
"//pkg/apis/certificates/fuzzer:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/fuzzer:go_default_library",
"//pkg/apis/extensions/fuzzer:go_default_library",
"//pkg/apis/networking/fuzzer:go_default_library",
"//pkg/apis/policy/fuzzer:go_default_library",
"//pkg/apis/rbac/fuzzer:go_default_library",
"//pkg/apis/storage/fuzzer:go_default_library",
"//staging/src/k8s.io/api/apps/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting/fuzzer:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/fuzzer:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/github.com/google/gofuzz:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/api/testing/compat:all-srcs",
],
tags = ["automanaged"],
)
go_test(
name = "go_default_test",
srcs = [
"backward_compatibility_test.go",
"conversion_test.go",
"copy_test.go",
"deep_copy_test.go",
"defaulting_test.go",
"meta_test.go",
"serialization_proto_test.go",
"serialization_test.go",
"unstructured_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/api/testing/compat:go_default_library",
"//pkg/apis/apps:go_default_library",
"//pkg/apis/apps/v1:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/install:go_default_library",
"//pkg/apis/core/v1:go_default_library",
"//pkg/apis/core/validation:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library",
"//staging/src/k8s.io/api/apps/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/extensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting/fuzzer:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting/roundtrip:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/github.com/json-iterator/go:go_default_library",
],
)
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- thockin
- lavalamp
- smarterclayton
- wojtek-t
- deads2k
- yujuhong
- brendandburns
- derekwaynecarr
- caesarxuchao
- vishh
- mikedanese
- nikhiljindal
- erictune
- pmorie
- dchen1107
- saad-ali
- zmerlynn
- justinsb
- pwittrock
- roberthbailey
- tallclair
- yifan-gu
- eparis
- soltysh
- jsafrane
- madhusudancs
- hongchaodeng
- rootfs
- jszczepkowski
- markturansky
- fgrzadkowski
- aveshagarwal
- david-mcmahon
- pweil-
- rata
- feihujiang
- sdminonne
- ghodss
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"testing"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/api/testing/compat"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/validation"
_ "k8s.io/kubernetes/pkg/apis/core/install"
)
func TestCompatibility_v1_PodSecurityContext(t *testing.T) {
cases := []struct {
name string
input string
expectedKeys map[string]string
absentKeys []string
}{
{
name: "hostNetwork = true",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostNetwork": true,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
expectedKeys: map[string]string{
"spec.hostNetwork": "true",
},
},
{
name: "hostNetwork = false",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostNetwork": false,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
absentKeys: []string{
"spec.hostNetwork",
},
},
{
name: "hostIPC = true",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostIPC": true,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
expectedKeys: map[string]string{
"spec.hostIPC": "true",
},
},
{
name: "hostIPC = false",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostIPC": false,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
absentKeys: []string{
"spec.hostIPC",
},
},
{
name: "hostPID = true",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostPID": true,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
expectedKeys: map[string]string{
"spec.hostPID": "true",
},
},
{
name: "hostPID = false",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostPID": false,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
absentKeys: []string{
"spec.hostPID",
},
},
}
validator := func(obj runtime.Object) field.ErrorList {
return validation.ValidatePodSpec(&(obj.(*api.Pod).Spec), field.NewPath("spec"))
}
for _, tc := range cases {
t.Logf("Testing 1.0.0 backward compatibility for %v", tc.name)
compat.TestCompatibility(t, v1.SchemeGroupVersion, []byte(tc.input), validator, tc.expectedKeys, tc.absentKeys)
}
}
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["compatibility_tester.go"],
importpath = "k8s.io/kubernetes/pkg/api/testing/compat",
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package compat
import (
"encoding/json"
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
"testing"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/api/legacyscheme"
)
// TestCompatibility reencodes the input using the codec for the given
// version and checks for the presence of the expected keys and absent
// keys in the resulting JSON.
// Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go
func TestCompatibility(
t *testing.T,
version schema.GroupVersion,
input []byte,
validator func(obj runtime.Object) field.ErrorList,
expectedKeys map[string]string,
absentKeys []string,
) {
// Decode
codec := legacyscheme.Codecs.LegacyCodec(version)
obj, err := runtime.Decode(codec, input)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
// Validate
errs := validator(obj)
if len(errs) != 0 {
t.Fatalf("Unexpected validation errors: %v", errs)
}
// Encode
output, err := runtime.Encode(codec, obj)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
// Validate old and new fields are encoded
generic := map[string]interface{}{}
if err := json.Unmarshal(output, &generic); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
for k, expectedValue := range expectedKeys {
keys := strings.Split(k, ".")
if actualValue, ok, err := getJSONValue(generic, keys...); err != nil || !ok {
t.Errorf("Unexpected error for %s: %v", k, err)
} else if !reflect.DeepEqual(expectedValue, fmt.Sprintf("%v", actualValue)) {
t.Errorf("Unexpected value for %v: expected %v, got %v", k, expectedValue, actualValue)
}
}
for _, absentKey := range absentKeys {
keys := strings.Split(absentKey, ".")
actualValue, ok, err := getJSONValue(generic, keys...)
if err == nil || ok {
t.Errorf("Unexpected value found for key %s: %v", absentKey, actualValue)
}
}
if t.Failed() {
data, err := json.MarshalIndent(obj, "", " ")
if err != nil {
t.Log(err)
} else {
t.Log(string(data))
}
t.Logf("2: Encoded value: %v", string(output))
}
}
func getJSONValue(data map[string]interface{}, keys ...string) (interface{}, bool, error) {
// No keys, current value is it
if len(keys) == 0 {
return data, true, nil
}
// Get the key (and optional index)
key := keys[0]
index := -1
if matches := regexp.MustCompile(`^(.*)\[(\d+)\]$`).FindStringSubmatch(key); len(matches) > 0 {
key = matches[1]
index, _ = strconv.Atoi(matches[2])
}
// Look up the value
value, ok := data[key]
if !ok {
return nil, false, fmt.Errorf("No key %s found", key)
}
// Get the indexed value if an index is specified
if index >= 0 {
valueSlice, ok := value.([]interface{})
if !ok {
return nil, false, fmt.Errorf("Key %s did not hold a slice", key)
}
if index >= len(valueSlice) {
return nil, false, fmt.Errorf("Index %d out of bounds for slice at key: %v", index, key)
}
value = valueSlice[index]
}
if len(keys) == 1 {
return value, true, nil
}
childData, ok := value.(map[string]interface{})
if !ok {
return nil, false, fmt.Errorf("Key %s did not hold a map", keys[0])
}
return getJSONValue(childData, keys[1:]...)
}
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"testing"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api/legacyscheme"
)
// TestSelectableFieldLabelConversionsOfKind verifies that given resource have field
// label conversion defined for each its selectable field.
// fields contains selectable fields of the resource.
// labelMap maps deprecated labels to their canonical names.
func TestSelectableFieldLabelConversionsOfKind(t *testing.T, apiVersion string, kind string, fields fields.Set, labelMap map[string]string) {
badFieldLabels := []string{
"name",
".name",
"bad",
"metadata",
"foo.bar",
}
value := "value"
gv, err := schema.ParseGroupVersion(apiVersion)
if err != nil {
t.Errorf("kind=%s: got unexpected error: %v", kind, err)
return
}
gvk := gv.WithKind(kind)
if len(fields) == 0 {
t.Logf("no selectable fields for kind %q, skipping", kind)
}
for label := range fields {
if label == "name" {
t.Logf("FIXME: \"name\" is deprecated by \"metadata.name\", it should be removed from selectable fields of kind=%s", kind)
continue
}
newLabel, newValue, err := legacyscheme.Scheme.ConvertFieldLabel(gvk, label, value)
if err != nil {
t.Errorf("kind=%s label=%s: got unexpected error: %v", kind, label, err)
} else {
expectedLabel := label
if l, exists := labelMap[label]; exists {
expectedLabel = l
}
if newLabel != expectedLabel {
t.Errorf("kind=%s label=%s: got unexpected label name (%q != %q)", kind, label, newLabel, expectedLabel)
}
if newValue != value {
t.Errorf("kind=%s label=%s: got unexpected new value (%q != %q)", kind, label, newValue, value)
}
}
}
for _, label := range badFieldLabels {
_, _, err := legacyscheme.Scheme.ConvertFieldLabel(gvk, label, "value")
if err == nil {
t.Errorf("kind=%s label=%s: got unexpected non-error", kind, label)
}
}
}
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"io/ioutil"
"math/rand"
"testing"
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/api/testapi"
api "k8s.io/kubernetes/pkg/apis/core"
)
func BenchmarkPodConversion(b *testing.B) {
apiObjectFuzzer := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(benchmarkSeed), legacyscheme.Codecs)
items := make([]api.Pod, 4)
for i := range items {
apiObjectFuzzer.Fuzz(&items[i])
items[i].Spec.InitContainers = nil
items[i].Status.InitContainerStatuses = nil
}
// add a fixed item
items = append(items, benchmarkPod)
width := len(items)
scheme := legacyscheme.Scheme
for i := 0; i < b.N; i++ {
pod := &items[i%width]
versionedObj, err := scheme.UnsafeConvertToVersion(pod, schema.GroupVersion{Group: "", Version: "v1"})
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
if _, err = scheme.UnsafeConvertToVersion(versionedObj, schema.GroupVersion{Group: "", Version: runtime.APIVersionInternal}); err != nil {
b.Fatalf("Conversion error: %v", err)
}
}
}
func BenchmarkNodeConversion(b *testing.B) {
data, err := ioutil.ReadFile("node_example.json")
if err != nil {
b.Fatalf("Unexpected error while reading file: %v", err)
}
var node api.Node
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &node); err != nil {
b.Fatalf("Unexpected error decoding node: %v", err)
}
scheme := legacyscheme.Scheme
var result *api.Node
b.ResetTimer()
for i := 0; i < b.N; i++ {
versionedObj, err := scheme.UnsafeConvertToVersion(&node, schema.GroupVersion{Group: "", Version: "v1"})
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
obj, err := scheme.UnsafeConvertToVersion(versionedObj, schema.GroupVersion{Group: "", Version: runtime.APIVersionInternal})
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
result = obj.(*api.Node)
}
b.StopTimer()
if !apiequality.Semantic.DeepDerivative(node, *result) {
b.Fatalf("Incorrect conversion: %s", diff.ObjectDiff(node, *result))
}
}
func BenchmarkReplicationControllerConversion(b *testing.B) {
data, err := ioutil.ReadFile("replication_controller_example.json")
if err != nil {
b.Fatalf("Unexpected error while reading file: %v", err)
}
var replicationController api.ReplicationController
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &replicationController); err != nil {
b.Fatalf("Unexpected error decoding node: %v", err)
}
scheme := legacyscheme.Scheme
var result *api.ReplicationController
b.ResetTimer()
for i := 0; i < b.N; i++ {
versionedObj, err := scheme.UnsafeConvertToVersion(&replicationController, schema.GroupVersion{Group: "", Version: "v1"})
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
obj, err := scheme.UnsafeConvertToVersion(versionedObj, schema.GroupVersion{Group: "", Version: runtime.APIVersionInternal})
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
result = obj.(*api.ReplicationController)
}
b.StopTimer()
if !apiequality.Semantic.DeepDerivative(replicationController, *result) {
b.Fatalf("Incorrect conversion: expected %v, got %v", replicationController, *result)
}
}
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"bytes"
"math/rand"
"reflect"
"testing"
"github.com/google/gofuzz"
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/kubernetes/pkg/api/legacyscheme"
)
func TestDeepCopyApiObjects(t *testing.T) {
for i := 0; i < *roundtrip.FuzzIters; i++ {
for _, version := range []schema.GroupVersion{{Group: "", Version: runtime.APIVersionInternal}, {Group: "", Version: "v1"}} {
f := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(rand.Int63()), legacyscheme.Codecs)
for kind := range legacyscheme.Scheme.KnownTypes(version) {
doDeepCopyTest(t, version.WithKind(kind), f)
}
}
}
}
func doDeepCopyTest(t *testing.T, kind schema.GroupVersionKind, f *fuzz.Fuzzer) {
item, err := legacyscheme.Scheme.New(kind)
if err != nil {
t.Fatalf("Could not create a %v: %s", kind, err)
}
f.Fuzz(item)
itemCopy := item.DeepCopyObject()
if !reflect.DeepEqual(item, itemCopy) {
t.Errorf("\nexpected: %#v\n\ngot: %#v\n\ndiff: %v", item, itemCopy, diff.ObjectReflectDiff(item, itemCopy))
}
prefuzzData := &bytes.Buffer{}
if err := legacyscheme.Codecs.LegacyCodec(kind.GroupVersion()).Encode(item, prefuzzData); err != nil {
t.Errorf("Could not encode a %v: %s", kind, err)
return
}
// Refuzz the copy, which should have no effect on the original
f.Fuzz(itemCopy)
postfuzzData := &bytes.Buffer{}
if err := legacyscheme.Codecs.LegacyCodec(kind.GroupVersion()).Encode(item, postfuzzData); err != nil {
t.Errorf("Could not encode a %v: %s", kind, err)
return
}
if bytes.Compare(prefuzzData.Bytes(), postfuzzData.Bytes()) != 0 {
t.Log(diff.StringDiff(prefuzzData.String(), postfuzzData.String()))
t.Errorf("Fuzzing copy modified original of %#v", kind)
return
}
}
func TestDeepCopySingleType(t *testing.T) {
for i := 0; i < *roundtrip.FuzzIters; i++ {
for _, version := range []schema.GroupVersion{{Group: "", Version: runtime.APIVersionInternal}, {Group: "", Version: "v1"}} {
f := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(rand.Int63()), legacyscheme.Codecs)
doDeepCopyTest(t, version.WithKind("Pod"), f)
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment