Add generated file

This PR adds generated files under pkg/client and vendor folder.
This commit is contained in:
xing-yang
2018-07-12 10:55:15 -07:00
parent 36b1de0341
commit e213d1890d
17729 changed files with 5090889 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"manifests_test.go",
"volumes_test.go",
],
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/features:go_default_library",
"//cmd/kubeadm/app/phases/certs:go_default_library",
"//cmd/kubeadm/test:go_default_library",
"//pkg/kubeapiserver/authorizer/modes:go_default_library",
"//pkg/util/pointer:go_default_library",
"//pkg/util/version:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"manifests.go",
"volumes.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane",
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/apis/kubeadm/v1alpha2:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/features:go_default_library",
"//cmd/kubeadm/app/images:go_default_library",
"//cmd/kubeadm/app/phases/certs:go_default_library",
"//cmd/kubeadm/app/util:go_default_library",
"//cmd/kubeadm/app/util/staticpod:go_default_library",
"//pkg/kubeapiserver/authorizer/modes:go_default_library",
"//pkg/util/version:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@@ -0,0 +1,347 @@
/*
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 controlplane
import (
"fmt"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/golang/glog"
"k8s.io/api/core/v1"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
"k8s.io/kubernetes/cmd/kubeadm/app/images"
certphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
"k8s.io/kubernetes/pkg/util/version"
)
// CreateInitStaticPodManifestFiles will write all static pod manifest files needed to bring up the control plane.
func CreateInitStaticPodManifestFiles(manifestDir string, cfg *kubeadmapi.MasterConfiguration) error {
glog.V(1).Infoln("[controlplane] creating static pod files")
return createStaticPodFiles(manifestDir, cfg, kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeScheduler)
}
// CreateAPIServerStaticPodManifestFile will write APIserver static pod manifest file.
func CreateAPIServerStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.MasterConfiguration) error {
glog.V(1).Infoln("creating APIserver static pod files")
return createStaticPodFiles(manifestDir, cfg, kubeadmconstants.KubeAPIServer)
}
// CreateControllerManagerStaticPodManifestFile will write controller manager static pod manifest file.
func CreateControllerManagerStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.MasterConfiguration) error {
glog.V(1).Infoln("creating controller manager static pod files")
return createStaticPodFiles(manifestDir, cfg, kubeadmconstants.KubeControllerManager)
}
// CreateSchedulerStaticPodManifestFile will write scheduler static pod manifest file.
func CreateSchedulerStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.MasterConfiguration) error {
glog.V(1).Infoln("creating scheduler static pod files")
return createStaticPodFiles(manifestDir, cfg, kubeadmconstants.KubeScheduler)
}
// GetStaticPodSpecs returns all staticPodSpecs actualized to the context of the current MasterConfiguration
// NB. this methods holds the information about how kubeadm creates static pod manifests.
func GetStaticPodSpecs(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.Version) map[string]v1.Pod {
// Get the required hostpath mounts
mounts := getHostPathVolumesForTheControlPlane(cfg)
// Prepare static pod specs
staticPodSpecs := map[string]v1.Pod{
kubeadmconstants.KubeAPIServer: staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.KubeAPIServer,
Image: images.GetCoreImage(kubeadmconstants.KubeAPIServer, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
ImagePullPolicy: v1.PullIfNotPresent,
Command: getAPIServerCommand(cfg),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeAPIServer)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeAPIServer, int(cfg.API.BindPort), "/healthz", v1.URISchemeHTTPS),
Resources: staticpodutil.ComponentResources("250m"),
Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeadmconstants.KubeAPIServer)),
kubeadmconstants.KubeControllerManager: staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.KubeControllerManager,
Image: images.GetCoreImage(kubeadmconstants.KubeControllerManager, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
ImagePullPolicy: v1.PullIfNotPresent,
Command: getControllerManagerCommand(cfg, k8sVersion),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeControllerManager)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeControllerManager, 10252, "/healthz", v1.URISchemeHTTP),
Resources: staticpodutil.ComponentResources("200m"),
Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeadmconstants.KubeControllerManager)),
kubeadmconstants.KubeScheduler: staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.KubeScheduler,
Image: images.GetCoreImage(kubeadmconstants.KubeScheduler, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
ImagePullPolicy: v1.PullIfNotPresent,
Command: getSchedulerCommand(cfg),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeScheduler)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeScheduler, 10251, "/healthz", v1.URISchemeHTTP),
Resources: staticpodutil.ComponentResources("100m"),
Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeadmconstants.KubeScheduler)),
}
return staticPodSpecs
}
// createStaticPodFiles creates all the requested static pod files.
func createStaticPodFiles(manifestDir string, cfg *kubeadmapi.MasterConfiguration, componentNames ...string) error {
// TODO: Move the "pkg/util/version".Version object into the internal API instead of always parsing the string
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
if err != nil {
return err
}
// gets the StaticPodSpecs, actualized for the current MasterConfiguration
glog.V(1).Infoln("[controlplane] getting StaticPodSpecs")
specs := GetStaticPodSpecs(cfg, k8sVersion)
// creates required static pod specs
for _, componentName := range componentNames {
// retrives the StaticPodSpec for given component
spec, exists := specs[componentName]
if !exists {
return fmt.Errorf("couldn't retrive StaticPodSpec for %s", componentName)
}
// writes the StaticPodSpec to disk
if err := staticpodutil.WriteStaticPodToDisk(componentName, manifestDir, spec); err != nil {
return fmt.Errorf("failed to create static pod manifest file for %q: %v", componentName, err)
}
fmt.Printf("[controlplane] wrote Static Pod manifest for component %s to %q\n", componentName, kubeadmconstants.GetStaticPodFilepath(componentName, manifestDir))
}
return nil
}
// getAPIServerCommand builds the right API server command from the given config object and version
func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
defaultArguments := map[string]string{
"advertise-address": cfg.API.AdvertiseAddress,
"insecure-port": "0",
"enable-admission-plugins": "NodeRestriction",
// TODO: remove `PersistentVolumeLabel` in kubeadm v1.11, as it's automatically disabled in v1.11.
// ref: https://github.com/kubernetes/kubernetes/pull/64326
// we can't skip it now as we support v1.10 clusters still.
// remove it from the unit tests too.
"disable-admission-plugins": "PersistentVolumeLabel",
"service-cluster-ip-range": cfg.Networking.ServiceSubnet,
"service-account-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName),
"client-ca-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
"tls-cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerCertName),
"tls-private-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKeyName),
"kubelet-client-certificate": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientCertName),
"kubelet-client-key": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientKeyName),
"enable-bootstrap-token-auth": "true",
"secure-port": fmt.Sprintf("%d", cfg.API.BindPort),
"allow-privileged": "true",
"kubelet-preferred-address-types": "InternalIP,ExternalIP,Hostname",
// add options to configure the front proxy. Without the generated client cert, this will never be useable
// so add it unconditionally with recommended values
"requestheader-username-headers": "X-Remote-User",
"requestheader-group-headers": "X-Remote-Group",
"requestheader-extra-headers-prefix": "X-Remote-Extra-",
"requestheader-client-ca-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertName),
"requestheader-allowed-names": "front-proxy-client",
"proxy-client-cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyClientCertName),
"proxy-client-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyClientKeyName),
}
command := []string{"kube-apiserver"}
// If the user set endpoints for an external etcd cluster
if cfg.Etcd.External != nil {
defaultArguments["etcd-servers"] = strings.Join(cfg.Etcd.External.Endpoints, ",")
// Use any user supplied etcd certificates
if cfg.Etcd.External.CAFile != "" {
defaultArguments["etcd-cafile"] = cfg.Etcd.External.CAFile
}
if cfg.Etcd.External.CertFile != "" && cfg.Etcd.External.KeyFile != "" {
defaultArguments["etcd-certfile"] = cfg.Etcd.External.CertFile
defaultArguments["etcd-keyfile"] = cfg.Etcd.External.KeyFile
}
} else {
// Default to etcd static pod on localhost
defaultArguments["etcd-servers"] = "https://127.0.0.1:2379"
defaultArguments["etcd-cafile"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCACertName)
defaultArguments["etcd-certfile"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientCertName)
defaultArguments["etcd-keyfile"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientKeyName)
}
if features.Enabled(cfg.FeatureGates, features.HighAvailability) {
defaultArguments["endpoint-reconciler-type"] = kubeadmconstants.LeaseEndpointReconcilerType
}
if features.Enabled(cfg.FeatureGates, features.DynamicKubeletConfig) {
defaultArguments["feature-gates"] = "DynamicKubeletConfig=true"
}
if features.Enabled(cfg.FeatureGates, features.Auditing) {
defaultArguments["audit-policy-file"] = kubeadmconstants.GetStaticPodAuditPolicyFile()
defaultArguments["audit-log-path"] = filepath.Join(kubeadmconstants.StaticPodAuditPolicyLogDir, kubeadmconstants.AuditPolicyLogFile)
if cfg.AuditPolicyConfiguration.LogMaxAge == nil {
defaultArguments["audit-log-maxage"] = fmt.Sprintf("%d", kubeadmapiv1alpha2.DefaultAuditPolicyLogMaxAge)
} else {
defaultArguments["audit-log-maxage"] = fmt.Sprintf("%d", *cfg.AuditPolicyConfiguration.LogMaxAge)
}
}
if cfg.APIServerExtraArgs == nil {
cfg.APIServerExtraArgs = map[string]string{}
}
cfg.APIServerExtraArgs["authorization-mode"] = getAuthzModes(cfg.APIServerExtraArgs["authorization-mode"])
command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.APIServerExtraArgs)...)
return command
}
// getAuthzModes gets the authorization-related parameters to the api server
// Node,RBAC should be fixed in this order at the beginning
// AlwaysAllow and AlwaysDeny is ignored as they are only for testing
func getAuthzModes(authzModeExtraArgs string) string {
modes := []string{
authzmodes.ModeNode,
authzmodes.ModeRBAC,
}
if strings.Contains(authzModeExtraArgs, authzmodes.ModeABAC) {
modes = append(modes, authzmodes.ModeABAC)
}
if strings.Contains(authzModeExtraArgs, authzmodes.ModeWebhook) {
modes = append(modes, authzmodes.ModeWebhook)
}
return strings.Join(modes, ",")
}
// calcNodeCidrSize determines the size of the subnets used on each node, based
// on the pod subnet provided. For IPv4, we assume that the pod subnet will
// be /16 and use /24. If the pod subnet cannot be parsed, the IPv4 value will
// be used (/24).
//
// For IPv6, the algorithm will do two three. First, the node CIDR will be set
// to a multiple of 8, using the available bits for easier readability by user.
// Second, the number of nodes will be 512 to 64K to attempt to maximize the
// number of nodes (see NOTE below). Third, pod networks of /113 and larger will
// be rejected, as the amount of bits available is too small.
//
// A special case is when the pod network size is /112, where /120 will be used,
// only allowing 256 nodes and 256 pods.
//
// If the pod network size is /113 or larger, the node CIDR will be set to the same
// size and this will be rejected later in validation.
//
// NOTE: Currently, the design allows a maximum of 64K nodes. This algorithm splits
// the available bits to maximize the number used for nodes, but still have the node
// CIDR be a multiple of eight.
//
func calcNodeCidrSize(podSubnet string) string {
maskSize := "24"
if ip, podCidr, err := net.ParseCIDR(podSubnet); err == nil {
if ip.To4() == nil {
var nodeCidrSize int
podNetSize, totalBits := podCidr.Mask.Size()
switch {
case podNetSize == 112:
// Special case, allows 256 nodes, 256 pods/node
nodeCidrSize = 120
case podNetSize < 112:
// Use multiple of 8 for node CIDR, with 512 to 64K nodes
nodeCidrSize = totalBits - ((totalBits-podNetSize-1)/8-1)*8
default:
// Not enough bits, will fail later, when validate
nodeCidrSize = podNetSize
}
maskSize = strconv.Itoa(nodeCidrSize)
}
}
return maskSize
}
// getControllerManagerCommand builds the right controller manager command from the given config object and version
func getControllerManagerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.Version) []string {
defaultArguments := map[string]string{
"address": "127.0.0.1",
"leader-elect": "true",
"kubeconfig": filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName),
"root-ca-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
"service-account-private-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPrivateKeyName),
"cluster-signing-cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
"cluster-signing-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName),
"use-service-account-credentials": "true",
"controllers": "*,bootstrapsigner,tokencleaner",
}
// If using external CA, pass empty string to controller manager instead of ca.key/ca.crt path,
// so that the csrsigning controller fails to start
if res, _ := certphase.UsingExternalCA(cfg); res {
defaultArguments["cluster-signing-key-file"] = ""
defaultArguments["cluster-signing-cert-file"] = ""
}
// Let the controller-manager allocate Node CIDRs for the Pod network.
// Each node will get a subspace of the address CIDR provided with --pod-network-cidr.
if cfg.Networking.PodSubnet != "" {
maskSize := calcNodeCidrSize(cfg.Networking.PodSubnet)
defaultArguments["allocate-node-cidrs"] = "true"
defaultArguments["cluster-cidr"] = cfg.Networking.PodSubnet
defaultArguments["node-cidr-mask-size"] = maskSize
}
command := []string{"kube-controller-manager"}
command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.ControllerManagerExtraArgs)...)
return command
}
// getSchedulerCommand builds the right scheduler command from the given config object and version
func getSchedulerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
defaultArguments := map[string]string{
"address": "127.0.0.1",
"leader-elect": "true",
"kubeconfig": filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.SchedulerKubeConfigFileName),
}
command := []string{"kube-scheduler"}
command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.SchedulerExtraArgs)...)
return command
}
// getProxyEnvVars builds a list of environment variables to use in the control plane containers in order to use the right proxy
func getProxyEnvVars() []v1.EnvVar {
envs := []v1.EnvVar{}
for _, env := range os.Environ() {
pos := strings.Index(env, "=")
if pos == -1 {
// malformed environment variable, skip it.
continue
}
name := env[:pos]
value := env[pos+1:]
if strings.HasSuffix(strings.ToLower(name), "_proxy") && value != "" {
envVar := v1.EnvVar{Name: name, Value: value}
envs = append(envs, envVar)
}
}
return envs
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,235 @@
/*
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 controlplane
import (
"fmt"
"os"
"path/filepath"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/sets"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
)
const (
caCertsVolumeName = "ca-certs"
caCertsVolumePath = "/etc/ssl/certs"
flexvolumeDirVolumeName = "flexvolume-dir"
flexvolumeDirVolumePath = "/usr/libexec/kubernetes/kubelet-plugins/volume/exec"
)
// caCertsExtraVolumePaths specifies the paths that can be conditionally mounted into the apiserver and controller-manager containers
// as /etc/ssl/certs might be or contain a symlink to them. It's a variable since it may be changed in unit testing. This var MUST
// NOT be changed in normal codepaths during runtime.
var caCertsExtraVolumePaths = []string{"/etc/pki", "/usr/share/ca-certificates", "/usr/local/share/ca-certificates", "/etc/ca-certificates"}
// getHostPathVolumesForTheControlPlane gets the required hostPath volumes and mounts for the control plane
func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) controlPlaneHostPathMounts {
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
hostPathFileOrCreate := v1.HostPathFileOrCreate
hostPathFile := v1.HostPathFile
mounts := newControlPlaneHostPathMounts()
// HostPath volumes for the API Server
// Read-only mount for the certificates directory
// TODO: Always mount the K8s Certificates directory to a static path inside of the container
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeCertificatesVolumeName, cfg.CertificatesDir, cfg.CertificatesDir, true, &hostPathDirectoryOrCreate)
// Read-only mount for the ca certs (/etc/ssl/certs) directory
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, caCertsVolumeName, caCertsVolumePath, caCertsVolumePath, true, &hostPathDirectoryOrCreate)
if features.Enabled(cfg.FeatureGates, features.Auditing) {
// Read-only mount for the audit policy file.
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeAuditPolicyVolumeName, cfg.AuditPolicyConfiguration.Path, kubeadmconstants.GetStaticPodAuditPolicyFile(), true, &hostPathFile)
// Write mount for the audit logs.
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeAuditPolicyLogVolumeName, cfg.AuditPolicyConfiguration.LogDir, kubeadmconstants.StaticPodAuditPolicyLogDir, false, &hostPathDirectoryOrCreate)
}
// If external etcd is specified, mount the directories needed for accessing the CA/serving certs and the private key
if cfg.Etcd.External != nil {
etcdVols, etcdVolMounts := getEtcdCertVolumes(cfg.Etcd.External, cfg.CertificatesDir)
mounts.AddHostPathMounts(kubeadmconstants.KubeAPIServer, etcdVols, etcdVolMounts)
}
// HostPath volumes for the controller manager
// Read-only mount for the certificates directory
// TODO: Always mount the K8s Certificates directory to a static path inside of the container
mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeCertificatesVolumeName, cfg.CertificatesDir, cfg.CertificatesDir, true, &hostPathDirectoryOrCreate)
// Read-only mount for the ca certs (/etc/ssl/certs) directory
mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, caCertsVolumeName, caCertsVolumePath, caCertsVolumePath, true, &hostPathDirectoryOrCreate)
// Read-only mount for the controller manager kubeconfig file
controllerManagerKubeConfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName)
mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeConfigVolumeName, controllerManagerKubeConfigFile, controllerManagerKubeConfigFile, true, &hostPathFileOrCreate)
// Mount for the flexvolume directory (/usr/libexec/kubernetes/kubelet-plugins/volume/exec) directory
// Flexvolume dir must NOT be readonly as it is used for third-party plugins to integrate with their storage backends via unix domain socket.
if stat, err := os.Stat(flexvolumeDirVolumePath); err == nil && stat.IsDir() {
mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, flexvolumeDirVolumeName, flexvolumeDirVolumePath, flexvolumeDirVolumePath, false, &hostPathDirectoryOrCreate)
}
// HostPath volumes for the scheduler
// Read-only mount for the scheduler kubeconfig file
schedulerKubeConfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.SchedulerKubeConfigFileName)
mounts.NewHostPathMount(kubeadmconstants.KubeScheduler, kubeadmconstants.KubeConfigVolumeName, schedulerKubeConfigFile, schedulerKubeConfigFile, true, &hostPathFileOrCreate)
// On some systems were we host-mount /etc/ssl/certs, it is also required to mount additional directories.
// This is needed due to symlinks pointing from files in /etc/ssl/certs to these directories.
for _, caCertsExtraVolumePath := range caCertsExtraVolumePaths {
if isExtraVolumeMountNeeded(caCertsExtraVolumePath) {
caCertsExtraVolumeName := strings.Replace(caCertsExtraVolumePath, "/", "-", -1)[1:]
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, caCertsExtraVolumeName, caCertsExtraVolumePath, caCertsExtraVolumePath, true, &hostPathDirectoryOrCreate)
mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, caCertsExtraVolumeName, caCertsExtraVolumePath, caCertsExtraVolumePath, true, &hostPathDirectoryOrCreate)
}
}
// Merge user defined mounts and ensure unique volume and volume mount
// names
mounts.AddExtraHostPathMounts(kubeadmconstants.KubeAPIServer, cfg.APIServerExtraVolumes)
mounts.AddExtraHostPathMounts(kubeadmconstants.KubeControllerManager, cfg.ControllerManagerExtraVolumes)
mounts.AddExtraHostPathMounts(kubeadmconstants.KubeScheduler, cfg.SchedulerExtraVolumes)
return mounts
}
// controlPlaneHostPathMounts is a helper struct for handling all the control plane's hostPath mounts in an easy way
type controlPlaneHostPathMounts struct {
// volumes is a nested map that forces a unique volumes. The outer map's
// keys are a string that should specify the target component to add the
// volume to. The values (inner map) of the outer map are maps with string
// keys and v1.Volume values. The inner map's key should specify the volume
// name.
volumes map[string]map[string]v1.Volume
// volumeMounts is a nested map that forces a unique volume mounts. The
// outer map's keys are a string that should specify the target component
// to add the volume mount to. The values (inner map) of the outer map are
// maps with string keys and v1.VolumeMount values. The inner map's key
// should specify the volume mount name.
volumeMounts map[string]map[string]v1.VolumeMount
}
func newControlPlaneHostPathMounts() controlPlaneHostPathMounts {
return controlPlaneHostPathMounts{
volumes: map[string]map[string]v1.Volume{},
volumeMounts: map[string]map[string]v1.VolumeMount{},
}
}
func (c *controlPlaneHostPathMounts) NewHostPathMount(component, mountName, hostPath, containerPath string, readOnly bool, hostPathType *v1.HostPathType) {
vol := staticpodutil.NewVolume(mountName, hostPath, hostPathType)
c.addComponentVolume(component, vol)
volMount := staticpodutil.NewVolumeMount(mountName, containerPath, readOnly)
c.addComponentVolumeMount(component, volMount)
}
func (c *controlPlaneHostPathMounts) AddHostPathMounts(component string, vols []v1.Volume, volMounts []v1.VolumeMount) {
for _, v := range vols {
c.addComponentVolume(component, v)
}
for _, v := range volMounts {
c.addComponentVolumeMount(component, v)
}
}
// AddExtraHostPathMounts adds host path mounts and overwrites the default
// paths in the case that a user specifies the same volume/volume mount name.
func (c *controlPlaneHostPathMounts) AddExtraHostPathMounts(component string, extraVols []kubeadmapi.HostPathMount) {
for _, extraVol := range extraVols {
fmt.Printf("[controlplane] Adding extra host path mount %q to %q\n", extraVol.Name, component)
hostPathType := extraVol.PathType
c.NewHostPathMount(component, extraVol.Name, extraVol.HostPath, extraVol.MountPath, !extraVol.Writable, &hostPathType)
}
}
func (c *controlPlaneHostPathMounts) GetVolumes(component string) map[string]v1.Volume {
return c.volumes[component]
}
func (c *controlPlaneHostPathMounts) GetVolumeMounts(component string) map[string]v1.VolumeMount {
return c.volumeMounts[component]
}
func (c *controlPlaneHostPathMounts) addComponentVolume(component string, vol v1.Volume) {
if _, ok := c.volumes[component]; !ok {
c.volumes[component] = map[string]v1.Volume{}
}
c.volumes[component][vol.Name] = vol
}
func (c *controlPlaneHostPathMounts) addComponentVolumeMount(component string, volMount v1.VolumeMount) {
if _, ok := c.volumeMounts[component]; !ok {
c.volumeMounts[component] = map[string]v1.VolumeMount{}
}
c.volumeMounts[component][volMount.Name] = volMount
}
// getEtcdCertVolumes returns the volumes/volumemounts needed for talking to an external etcd cluster
func getEtcdCertVolumes(etcdCfg *kubeadmapi.ExternalEtcd, k8sCertificatesDir string) ([]v1.Volume, []v1.VolumeMount) {
certPaths := []string{etcdCfg.CAFile, etcdCfg.CertFile, etcdCfg.KeyFile}
certDirs := sets.NewString()
for _, certPath := range certPaths {
certDir := filepath.Dir(certPath)
// Ignore ".", which is the result of passing an empty path.
// Also ignore the cert directories that already may be mounted; /etc/ssl/certs, /etc/pki or Kubernetes CertificatesDir
// If the etcd certs are in there, it's okay, we don't have to do anything
extraVolumePath := false
for _, caCertsExtraVolumePath := range caCertsExtraVolumePaths {
if strings.HasPrefix(certDir, caCertsExtraVolumePath) {
extraVolumePath = true
break
}
}
if certDir == "." || extraVolumePath || strings.HasPrefix(certDir, caCertsVolumePath) || strings.HasPrefix(certDir, k8sCertificatesDir) {
continue
}
// Filter out any existing hostpath mounts in the list that contains a subset of the path
alreadyExists := false
for _, existingCertDir := range certDirs.List() {
// If the current directory is a parent of an existing one, remove the already existing one
if strings.HasPrefix(existingCertDir, certDir) {
certDirs.Delete(existingCertDir)
} else if strings.HasPrefix(certDir, existingCertDir) {
// If an existing directory is a parent of the current one, don't add the current one
alreadyExists = true
}
}
if alreadyExists {
continue
}
certDirs.Insert(certDir)
}
volumes := []v1.Volume{}
volumeMounts := []v1.VolumeMount{}
pathType := v1.HostPathDirectoryOrCreate
for i, certDir := range certDirs.List() {
name := fmt.Sprintf("etcd-certs-%d", i)
volumes = append(volumes, staticpodutil.NewVolume(name, certDir, &pathType))
volumeMounts = append(volumeMounts, staticpodutil.NewVolumeMount(name, certDir, true))
}
return volumes, volumeMounts
}
// isExtraVolumeMountNeeded specifies whether /etc/pki should be host-mounted into the containers
// On some systems were we host-mount /etc/ssl/certs, it is also required to mount /etc/pki. This is needed
// due to symlinks pointing from files in /etc/ssl/certs into /etc/pki/
func isExtraVolumeMountNeeded(caCertsExtraVolumePath string) bool {
if _, err := os.Stat(caCertsExtraVolumePath); err == nil {
return true
}
return false
}

View File

@@ -0,0 +1,675 @@
/*
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 controlplane
import (
"fmt"
"io/ioutil"
"os"
"reflect"
"testing"
"k8s.io/api/core/v1"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
)
func TestGetEtcdCertVolumes(t *testing.T) {
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
k8sCertifcatesDir := "/etc/kubernetes/pki"
var tests = []struct {
ca, cert, key string
vol []v1.Volume
volMount []v1.VolumeMount
}{
{
// Should ignore files in /etc/ssl/certs
ca: "/etc/ssl/certs/my-etcd-ca.crt",
cert: "/etc/ssl/certs/my-etcd.crt",
key: "/etc/ssl/certs/my-etcd.key",
vol: []v1.Volume{},
volMount: []v1.VolumeMount{},
},
{
// Should ignore files in subdirs of /etc/ssl/certs
ca: "/etc/ssl/certs/etcd/my-etcd-ca.crt",
cert: "/etc/ssl/certs/etcd/my-etcd.crt",
key: "/etc/ssl/certs/etcd/my-etcd.key",
vol: []v1.Volume{},
volMount: []v1.VolumeMount{},
},
{
// Should ignore files in /etc/pki
ca: "/etc/pki/my-etcd-ca.crt",
cert: "/etc/pki/my-etcd.crt",
key: "/etc/pki/my-etcd.key",
vol: []v1.Volume{},
volMount: []v1.VolumeMount{},
},
{
// Should ignore files in Kubernetes PKI directory (and subdirs)
ca: k8sCertifcatesDir + "/ca/my-etcd-ca.crt",
cert: k8sCertifcatesDir + "/my-etcd.crt",
key: k8sCertifcatesDir + "/my-etcd.key",
vol: []v1.Volume{},
volMount: []v1.VolumeMount{},
},
{
// All in the same dir
ca: "/var/lib/certs/etcd/my-etcd-ca.crt",
cert: "/var/lib/certs/etcd/my-etcd.crt",
key: "/var/lib/certs/etcd/my-etcd.key",
vol: []v1.Volume{
{
Name: "etcd-certs-0",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/var/lib/certs/etcd",
Type: &hostPathDirectoryOrCreate,
},
},
},
},
volMount: []v1.VolumeMount{
{
Name: "etcd-certs-0",
MountPath: "/var/lib/certs/etcd",
ReadOnly: true,
},
},
},
{
// One file + two files in separate dirs
ca: "/etc/certs/etcd/my-etcd-ca.crt",
cert: "/var/lib/certs/etcd/my-etcd.crt",
key: "/var/lib/certs/etcd/my-etcd.key",
vol: []v1.Volume{
{
Name: "etcd-certs-0",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/certs/etcd",
Type: &hostPathDirectoryOrCreate,
},
},
},
{
Name: "etcd-certs-1",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/var/lib/certs/etcd",
Type: &hostPathDirectoryOrCreate,
},
},
},
},
volMount: []v1.VolumeMount{
{
Name: "etcd-certs-0",
MountPath: "/etc/certs/etcd",
ReadOnly: true,
},
{
Name: "etcd-certs-1",
MountPath: "/var/lib/certs/etcd",
ReadOnly: true,
},
},
},
{
// All three files in different directories
ca: "/etc/certs/etcd/my-etcd-ca.crt",
cert: "/var/lib/certs/etcd/my-etcd.crt",
key: "/var/lib/certs/private/my-etcd.key",
vol: []v1.Volume{
{
Name: "etcd-certs-0",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/certs/etcd",
Type: &hostPathDirectoryOrCreate,
},
},
},
{
Name: "etcd-certs-1",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/var/lib/certs/etcd",
Type: &hostPathDirectoryOrCreate,
},
},
},
{
Name: "etcd-certs-2",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/var/lib/certs/private",
Type: &hostPathDirectoryOrCreate,
},
},
},
},
volMount: []v1.VolumeMount{
{
Name: "etcd-certs-0",
MountPath: "/etc/certs/etcd",
ReadOnly: true,
},
{
Name: "etcd-certs-1",
MountPath: "/var/lib/certs/etcd",
ReadOnly: true,
},
{
Name: "etcd-certs-2",
MountPath: "/var/lib/certs/private",
ReadOnly: true,
},
},
},
{
// The most top-level dir should be used
ca: "/etc/certs/etcd/my-etcd-ca.crt",
cert: "/etc/certs/etcd/serving/my-etcd.crt",
key: "/etc/certs/etcd/serving/my-etcd.key",
vol: []v1.Volume{
{
Name: "etcd-certs-0",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/certs/etcd",
Type: &hostPathDirectoryOrCreate,
},
},
},
},
volMount: []v1.VolumeMount{
{
Name: "etcd-certs-0",
MountPath: "/etc/certs/etcd",
ReadOnly: true,
},
},
},
{
// The most top-level dir should be used, regardless of order
ca: "/etc/certs/etcd/ca/my-etcd-ca.crt",
cert: "/etc/certs/etcd/my-etcd.crt",
key: "/etc/certs/etcd/my-etcd.key",
vol: []v1.Volume{
{
Name: "etcd-certs-0",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/certs/etcd",
Type: &hostPathDirectoryOrCreate,
},
},
},
},
volMount: []v1.VolumeMount{
{
Name: "etcd-certs-0",
MountPath: "/etc/certs/etcd",
ReadOnly: true,
},
},
},
}
for _, rt := range tests {
actualVol, actualVolMount := getEtcdCertVolumes(&kubeadmapi.ExternalEtcd{
CAFile: rt.ca,
CertFile: rt.cert,
KeyFile: rt.key,
}, k8sCertifcatesDir)
if !reflect.DeepEqual(actualVol, rt.vol) {
t.Errorf(
"failed getEtcdCertVolumes:\n\texpected: %v\n\t actual: %v",
rt.vol,
actualVol,
)
}
if !reflect.DeepEqual(actualVolMount, rt.volMount) {
t.Errorf(
"failed getEtcdCertVolumes:\n\texpected: %v\n\t actual: %v",
rt.volMount,
actualVolMount,
)
}
}
}
func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
hostPathFileOrCreate := v1.HostPathFileOrCreate
hostPathFile := v1.HostPathFile
volMap := make(map[string]map[string]v1.Volume)
volMap[kubeadmconstants.KubeAPIServer] = map[string]v1.Volume{}
volMap[kubeadmconstants.KubeAPIServer]["k8s-certs"] = v1.Volume{
Name: "k8s-certs",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: testCertsDir,
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap[kubeadmconstants.KubeAPIServer]["ca-certs"] = v1.Volume{
Name: "ca-certs",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/ssl/certs",
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap[kubeadmconstants.KubeAPIServer]["audit"] = v1.Volume{
Name: "audit",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/foo/bar/baz.yaml",
Type: &hostPathFile,
},
},
}
volMap[kubeadmconstants.KubeAPIServer]["audit-log"] = v1.Volume{
Name: "audit-log",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/bar/foo",
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap[kubeadmconstants.KubeControllerManager] = map[string]v1.Volume{}
volMap[kubeadmconstants.KubeControllerManager]["k8s-certs"] = v1.Volume{
Name: "k8s-certs",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: testCertsDir,
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap[kubeadmconstants.KubeControllerManager]["ca-certs"] = v1.Volume{
Name: "ca-certs",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/ssl/certs",
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap[kubeadmconstants.KubeControllerManager]["kubeconfig"] = v1.Volume{
Name: "kubeconfig",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/kubernetes/controller-manager.conf",
Type: &hostPathFileOrCreate,
},
},
}
volMap[kubeadmconstants.KubeScheduler] = map[string]v1.Volume{}
volMap[kubeadmconstants.KubeScheduler]["kubeconfig"] = v1.Volume{
Name: "kubeconfig",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/kubernetes/scheduler.conf",
Type: &hostPathFileOrCreate,
},
},
}
volMountMap := make(map[string]map[string]v1.VolumeMount)
volMountMap[kubeadmconstants.KubeAPIServer] = map[string]v1.VolumeMount{}
volMountMap[kubeadmconstants.KubeAPIServer]["k8s-certs"] = v1.VolumeMount{
Name: "k8s-certs",
MountPath: testCertsDir,
ReadOnly: true,
}
volMountMap[kubeadmconstants.KubeAPIServer]["ca-certs"] = v1.VolumeMount{
Name: "ca-certs",
MountPath: "/etc/ssl/certs",
ReadOnly: true,
}
volMountMap[kubeadmconstants.KubeAPIServer]["audit"] = v1.VolumeMount{
Name: "audit",
MountPath: "/etc/kubernetes/audit/audit.yaml",
ReadOnly: true,
}
volMountMap[kubeadmconstants.KubeAPIServer]["audit-log"] = v1.VolumeMount{
Name: "audit-log",
MountPath: "/var/log/kubernetes/audit",
ReadOnly: false,
}
volMountMap[kubeadmconstants.KubeControllerManager] = map[string]v1.VolumeMount{}
volMountMap[kubeadmconstants.KubeControllerManager]["k8s-certs"] = v1.VolumeMount{
Name: "k8s-certs",
MountPath: testCertsDir,
ReadOnly: true,
}
volMountMap[kubeadmconstants.KubeControllerManager]["ca-certs"] = v1.VolumeMount{
Name: "ca-certs",
MountPath: "/etc/ssl/certs",
ReadOnly: true,
}
volMountMap[kubeadmconstants.KubeControllerManager]["kubeconfig"] = v1.VolumeMount{
Name: "kubeconfig",
MountPath: "/etc/kubernetes/controller-manager.conf",
ReadOnly: true,
}
volMountMap[kubeadmconstants.KubeScheduler] = map[string]v1.VolumeMount{}
volMountMap[kubeadmconstants.KubeScheduler]["kubeconfig"] = v1.VolumeMount{
Name: "kubeconfig",
MountPath: "/etc/kubernetes/scheduler.conf",
ReadOnly: true,
}
volMap2 := make(map[string]map[string]v1.Volume)
volMap2[kubeadmconstants.KubeAPIServer] = map[string]v1.Volume{}
volMap2[kubeadmconstants.KubeAPIServer]["k8s-certs"] = v1.Volume{
Name: "k8s-certs",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: testCertsDir,
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap2[kubeadmconstants.KubeAPIServer]["ca-certs"] = v1.Volume{
Name: "ca-certs",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/ssl/certs",
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap2[kubeadmconstants.KubeAPIServer]["etcd-certs-0"] = v1.Volume{
Name: "etcd-certs-0",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/certs/etcd",
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap2[kubeadmconstants.KubeAPIServer]["etcd-certs-1"] = v1.Volume{
Name: "etcd-certs-1",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/var/lib/etcd/certs",
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap2[kubeadmconstants.KubeControllerManager] = map[string]v1.Volume{}
volMap2[kubeadmconstants.KubeControllerManager]["k8s-certs"] = v1.Volume{
Name: "k8s-certs",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: testCertsDir,
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap2[kubeadmconstants.KubeControllerManager]["ca-certs"] = v1.Volume{
Name: "ca-certs",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/ssl/certs",
Type: &hostPathDirectoryOrCreate,
},
},
}
volMap2[kubeadmconstants.KubeControllerManager]["kubeconfig"] = v1.Volume{
Name: "kubeconfig",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/kubernetes/controller-manager.conf",
Type: &hostPathFileOrCreate,
},
},
}
volMap2[kubeadmconstants.KubeScheduler] = map[string]v1.Volume{}
volMap2[kubeadmconstants.KubeScheduler]["kubeconfig"] = v1.Volume{
Name: "kubeconfig",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/etc/kubernetes/scheduler.conf",
Type: &hostPathFileOrCreate,
},
},
}
volMountMap2 := make(map[string]map[string]v1.VolumeMount)
volMountMap2[kubeadmconstants.KubeAPIServer] = map[string]v1.VolumeMount{}
volMountMap2[kubeadmconstants.KubeAPIServer]["k8s-certs"] = v1.VolumeMount{
Name: "k8s-certs",
MountPath: testCertsDir,
ReadOnly: true,
}
volMountMap2[kubeadmconstants.KubeAPIServer]["ca-certs"] = v1.VolumeMount{
Name: "ca-certs",
MountPath: "/etc/ssl/certs",
ReadOnly: true,
}
volMountMap2[kubeadmconstants.KubeAPIServer]["etcd-certs-0"] = v1.VolumeMount{
Name: "etcd-certs-0",
MountPath: "/etc/certs/etcd",
ReadOnly: true,
}
volMountMap2[kubeadmconstants.KubeAPIServer]["etcd-certs-1"] = v1.VolumeMount{
Name: "etcd-certs-1",
MountPath: "/var/lib/etcd/certs",
ReadOnly: true,
}
volMountMap2[kubeadmconstants.KubeControllerManager] = map[string]v1.VolumeMount{}
volMountMap2[kubeadmconstants.KubeControllerManager]["k8s-certs"] = v1.VolumeMount{
Name: "k8s-certs",
MountPath: testCertsDir,
ReadOnly: true,
}
volMountMap2[kubeadmconstants.KubeControllerManager]["ca-certs"] = v1.VolumeMount{
Name: "ca-certs",
MountPath: "/etc/ssl/certs",
ReadOnly: true,
}
volMountMap2[kubeadmconstants.KubeControllerManager]["kubeconfig"] = v1.VolumeMount{
Name: "kubeconfig",
MountPath: "/etc/kubernetes/controller-manager.conf",
ReadOnly: true,
}
volMountMap2[kubeadmconstants.KubeScheduler] = map[string]v1.VolumeMount{}
volMountMap2[kubeadmconstants.KubeScheduler]["kubeconfig"] = v1.VolumeMount{
Name: "kubeconfig",
MountPath: "/etc/kubernetes/scheduler.conf",
ReadOnly: true,
}
var tests = []struct {
cfg *kubeadmapi.MasterConfiguration
vol map[string]map[string]v1.Volume
volMount map[string]map[string]v1.VolumeMount
}{
{
// Should ignore files in /etc/ssl/certs
cfg: &kubeadmapi.MasterConfiguration{
CertificatesDir: testCertsDir,
Etcd: kubeadmapi.Etcd{},
FeatureGates: map[string]bool{features.Auditing: true},
AuditPolicyConfiguration: kubeadmapi.AuditPolicyConfiguration{
Path: "/foo/bar/baz.yaml",
LogDir: "/bar/foo",
},
},
vol: volMap,
volMount: volMountMap,
},
{
// Should ignore files in /etc/ssl/certs and in CertificatesDir
cfg: &kubeadmapi.MasterConfiguration{
CertificatesDir: testCertsDir,
Etcd: kubeadmapi.Etcd{
External: &kubeadmapi.ExternalEtcd{
Endpoints: []string{"foo"},
CAFile: "/etc/certs/etcd/my-etcd-ca.crt",
CertFile: testCertsDir + "/etcd/my-etcd.crt",
KeyFile: "/var/lib/etcd/certs/my-etcd.key",
},
},
},
vol: volMap2,
volMount: volMountMap2,
},
}
tmpdir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("Couldn't create tmpdir")
}
defer os.RemoveAll(tmpdir)
// set up tmp caCertsExtraVolumePaths for testing
caCertsExtraVolumePaths = []string{fmt.Sprintf("%s/etc/pki", tmpdir), fmt.Sprintf("%s/usr/share/ca-certificates", tmpdir)}
defer func() { caCertsExtraVolumePaths = []string{"/etc/pki", "/usr/share/ca-certificates"} }()
for _, rt := range tests {
mounts := getHostPathVolumesForTheControlPlane(rt.cfg)
// Avoid unit test errors when the flexvolume is mounted
if _, ok := mounts.volumes[kubeadmconstants.KubeControllerManager][flexvolumeDirVolumeName]; ok {
delete(mounts.volumes[kubeadmconstants.KubeControllerManager], flexvolumeDirVolumeName)
}
if _, ok := mounts.volumeMounts[kubeadmconstants.KubeControllerManager][flexvolumeDirVolumeName]; ok {
delete(mounts.volumeMounts[kubeadmconstants.KubeControllerManager], flexvolumeDirVolumeName)
}
if !reflect.DeepEqual(mounts.volumes, rt.vol) {
t.Errorf(
"failed getHostPathVolumesForTheControlPlane:\n\texpected: %v\n\t actual: %v",
rt.vol,
mounts.volumes,
)
}
if !reflect.DeepEqual(mounts.volumeMounts, rt.volMount) {
t.Errorf(
"failed getHostPathVolumesForTheControlPlane:\n\texpected: %v\n\t actual: %v",
rt.volMount,
mounts.volumeMounts,
)
}
}
}
func TestAddExtraHostPathMounts(t *testing.T) {
mounts := newControlPlaneHostPathMounts()
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
hostPathFileOrCreate := v1.HostPathFileOrCreate
vols := []v1.Volume{
{
Name: "foo",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/tmp/foo",
Type: &hostPathDirectoryOrCreate,
},
},
},
{
Name: "bar",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/tmp/bar",
Type: &hostPathFileOrCreate,
},
},
},
}
volMounts := []v1.VolumeMount{
{
Name: "foo",
MountPath: "/tmp/foo",
ReadOnly: true,
},
{
Name: "bar",
MountPath: "/tmp/bar",
ReadOnly: true,
},
}
mounts.AddHostPathMounts("component", vols, volMounts)
hostPathMounts := []kubeadmapi.HostPathMount{
{
Name: "foo-0",
HostPath: "/tmp/qux-0",
MountPath: "/tmp/qux-0",
Writable: false,
PathType: v1.HostPathFile,
},
{
Name: "bar-0",
HostPath: "/tmp/asd-0",
MountPath: "/tmp/asd-0",
Writable: true,
PathType: v1.HostPathDirectory,
},
{
Name: "foo-1",
HostPath: "/tmp/qux-1",
MountPath: "/tmp/qux-1",
Writable: false,
PathType: v1.HostPathFileOrCreate,
},
{
Name: "bar-1",
HostPath: "/tmp/asd-1",
MountPath: "/tmp/asd-1",
Writable: true,
PathType: v1.HostPathDirectoryOrCreate,
},
}
mounts.AddExtraHostPathMounts("component", hostPathMounts)
for _, hostMount := range hostPathMounts {
volumeName := hostMount.Name
if _, ok := mounts.volumes["component"][volumeName]; !ok {
t.Errorf("Expected to find volume %q", volumeName)
}
vol := mounts.volumes["component"][volumeName]
if vol.Name != volumeName {
t.Errorf("Expected volume name %q", volumeName)
}
if vol.HostPath.Path != hostMount.HostPath {
t.Errorf("Expected host path %q", hostMount.HostPath)
}
if _, ok := mounts.volumeMounts["component"][volumeName]; !ok {
t.Errorf("Expected to find volume mount %q", volumeName)
}
if *vol.HostPath.Type != v1.HostPathType(hostMount.PathType) {
t.Errorf("Expected to host path type %q", hostMount.PathType)
}
volMount, _ := mounts.volumeMounts["component"][volumeName]
if volMount.Name != volumeName {
t.Errorf("Expected volume mount name %q", volumeName)
}
if volMount.MountPath != hostMount.MountPath {
t.Errorf("Expected container path %q", hostMount.MountPath)
}
if volMount.ReadOnly != !hostMount.Writable {
t.Errorf("Expected volume writable setting %t", hostMount.Writable)
}
}
}