package kubernetes
import (
"io"
"reflect"
"testing"
"time"
proxyoptions "k8s.io/kubernetes/cmd/kube-proxy/app/options"
kubeletoptions "k8s.io/kubernetes/cmd/kubelet/app/options"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/componentconfig"
"k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/cloudprovider/providers/fake"
"k8s.io/kubernetes/pkg/kubelet/rkt"
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/kubernetes/pkg/util"
utilconfig "k8s.io/kubernetes/pkg/util/config"
"k8s.io/kubernetes/pkg/util/diff"
)
func TestKubeletDefaults(t *testing.T) {
defaults := kubeletoptions.NewKubeletServer()
// This is a snapshot of the default config
// If the default changes (new fields are added, or default values change), we want to know
// Once we've reacted to the changes appropriately in BuildKubernetesNodeConfig(), update this expected default to match the new upstream defaults
expectedDefaults := &kubeletoptions.KubeletServer{
AuthPath: util.NewStringFlag(""),
KubeConfig: util.NewStringFlag("/var/lib/kubelet/kubeconfig"),
KubeletConfiguration: componentconfig.KubeletConfiguration{
Address: "0.0.0.0", // overridden
AllowPrivileged: false, // overridden
CAdvisorPort: 4194, // disabled
VolumeStatsAggPeriod: unversioned.Duration{Duration: time.Minute},
CertDirectory: "/var/run/kubernetes",
CgroupRoot: "",
ClusterDNS: "", // overridden
ClusterDomain: "", // overridden
ConfigureCBR0: false,
ContainerRuntime: "docker",
Containerized: false, // overridden based on OPENSHIFT_CONTAINERIZED
CPUCFSQuota: true, // forced to true
DockerExecHandlerName: "native",
DockerEndpoint: "unix:///var/run/docker.sock",
EventBurst: 10,
EventRecordQPS: 5.0,
EnableCustomMetrics: false,
EnableDebuggingHandlers: true,
EnableServer: true,
EvictionHard: "memory.available<100Mi",
FileCheckFrequency: unversioned.Duration{Duration: 20 * time.Second}, // overridden
HealthzBindAddress: "127.0.0.1", // disabled
HealthzPort: 10248, // disabled
HostNetworkSources: []string{"*"}, // overridden
HostPIDSources: []string{"*"}, // overridden
HostIPCSources: []string{"*"}, // overridden
HTTPCheckFrequency: unversioned.Duration{Duration: 20 * time.Second}, // disabled
ImageMinimumGCAge: unversioned.Duration{Duration: 120 * time.Second},
ImageGCHighThresholdPercent: 90,
ImageGCLowThresholdPercent: 80,
IPTablesMasqueradeBit: 14,
IPTablesDropBit: 15,
LowDiskSpaceThresholdMB: 256,
MakeIPTablesUtilChains: true,
MasterServiceNamespace: "default",
MaxContainerCount: -1,
MaxPerPodContainerCount: 1,
MaxOpenFiles: 1000000,
MaxPods: 110, // overridden
MinimumGCAge: unversioned.Duration{},
NetworkPluginDir: "",
NetworkPluginName: "", // overridden
NonMasqueradeCIDR: "10.0.0.0/8",
VolumePluginDir: "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/",
NodeStatusUpdateFrequency: unversioned.Duration{Duration: 10 * time.Second},
NodeLabels: nil,
OOMScoreAdj: -999,
LockFilePath: "",
PodInfraContainerImage: "gcr.io/google_containers/pause-amd64:3.0", // overridden
Port: 10250, // overridden
ReadOnlyPort: 10255, // disabled
RegisterNode: true,
RegisterSchedulable: true,
RegistryBurst: 10,
RegistryPullQPS: 5.0,
ResolverConfig: kubetypes.ResolvConfDefault,
KubeletCgroups: "",
RktAPIEndpoint: rkt.DefaultRktAPIServiceEndpoint,
RktPath: "",
RktStage1Image: "",
RootDirectory: "/var/lib/kubelet", // overridden
RuntimeCgroups: "",
SerializeImagePulls: true,
StreamingConnectionIdleTimeout: unversioned.Duration{Duration: 4 * time.Hour},
SyncFrequency: unversioned.Duration{Duration: 1 * time.Minute},
SystemCgroups: "",
TLSCertFile: "", // overridden to prevent cert generation
TLSPrivateKeyFile: "", // overridden to prevent cert generation
ReconcileCIDR: true,
KubeAPIQPS: 5.0,
KubeAPIBurst: 10,
ExperimentalFlannelOverlay: false,
OutOfDiskTransitionFrequency: unversioned.Duration{Duration: 5 * time.Minute},
HairpinMode: "promiscuous-bridge",
BabysitDaemons: false,
SeccompProfileRoot: "/var/lib/kubelet/seccomp",
CloudProvider: "auto-detect",
RuntimeRequestTimeout: unversioned.Duration{Duration: 2 * time.Minute},
ContentType: "application/vnd.kubernetes.protobuf",
EnableControllerAttachDetach: true,
EvictionPressureTransitionPeriod: unversioned.Duration{Duration: 5 * time.Minute},
SystemReserved: utilconfig.ConfigurationMap{},
KubeReserved: utilconfig.ConfigurationMap{},
},
}
if !reflect.DeepEqual(defaults, expectedDefaults) {
t.Logf("expected defaults, actual defaults: \n%s", diff.ObjectReflectDiff(expectedDefaults, defaults))
t.Errorf("Got different defaults than expected, adjust in BuildKubernetesNodeConfig and update expectedDefaults")
}
}
func TestProxyConfig(t *testing.T) {
// This is a snapshot of the default config
// If the default changes (new fields are added, or default values change), we want to know
// Once we've reacted to the changes appropriately in buildKubeProxyConfig(), update this expected default to match the new upstream defaults
oomScoreAdj := int32(-999)
ipTablesMasqueratebit := int32(14)
expectedDefaultConfig := &proxyoptions.ProxyServerConfig{
KubeProxyConfiguration: componentconfig.KubeProxyConfiguration{
BindAddress: "0.0.0.0",
ClusterCIDR: "",
HealthzPort: 10249, // disabled
HealthzBindAddress: "127.0.0.1", // disabled
OOMScoreAdj: &oomScoreAdj, // disabled
ResourceContainer: "/kube-proxy", // disabled
IPTablesSyncPeriod: unversioned.Duration{Duration: 30 * time.Second},
// from k8s.io/kubernetes/cmd/kube-proxy/app/options/options.go
// defaults to 14.
IPTablesMasqueradeBit: &ipTablesMasqueratebit,
UDPIdleTimeout: unversioned.Duration{Duration: 250 * time.Millisecond},
ConntrackMaxPerCore: 32 * 1024,
ConntrackTCPEstablishedTimeout: unversioned.Duration{Duration: 86400 * time.Second}, // 1 day (1/5 default)
},
ConfigSyncPeriod: 15 * time.Minute,
KubeAPIQPS: 5.0,
KubeAPIBurst: 10,
ContentType: "application/vnd.kubernetes.protobuf",
}
actualDefaultConfig := proxyoptions.NewProxyConfig()
if !reflect.DeepEqual(expectedDefaultConfig, actualDefaultConfig) {
t.Errorf("Default kube proxy config has changed. Adjust buildKubeProxyConfig() as needed to disable or make use of additions.")
t.Logf("Difference %s", diff.ObjectReflectDiff(expectedDefaultConfig, actualDefaultConfig))
}
}
func TestBuildCloudProviderFake(t *testing.T) {
providerName := "fake"
cloudprovider.RegisterCloudProvider(providerName, func(config io.Reader) (cloudprovider.Interface, error) {
return &fake.FakeCloud{}, nil
})
server := kubeletoptions.NewKubeletServer()
server.CloudProvider = providerName
cloud, err := buildCloudProvider(server)
if err != nil {
t.Errorf("buildCloudProvider failed: %v", err)
}
if cloud == nil {
t.Errorf("buildCloudProvider returned nil cloud provider")
} else {
if cloud.ProviderName() != providerName {
t.Errorf("Invalid cloud provider returned, expected %q, got %q", providerName, cloud.ProviderName())
}
}
}
func TestBuildCloudProviderNone(t *testing.T) {
server := kubeletoptions.NewKubeletServer()
server.CloudProvider = ""
cloud, err := buildCloudProvider(server)
if err != nil {
t.Errorf("buildCloudProvider failed: %v", err)
}
if cloud != nil {
t.Errorf("buildCloudProvider returned cloud provider %q where nil was expected", cloud.ProviderName())
}
}
func TestBuildCloudProviderError(t *testing.T) {
server := kubeletoptions.NewKubeletServer()
server.CloudProvider = "unknown-provider-name"
cloud, err := buildCloudProvider(server)
if err == nil {
t.Errorf("buildCloudProvider returned no error when one was expected")
}
if cloud != nil {
t.Errorf("buildCloudProvider returned cloud provider %q where nil was expected", cloud.ProviderName())
}
}