kubeadm: Remove the .CloudProvider configuration option

This commit is contained in:
Lucas Käldström 2018-05-16 15:46:34 +01:00
parent 5686fcfcf8
commit adb60f4064
No known key found for this signature in database
GPG Key ID: 3FA3783D77751514
14 changed files with 80 additions and 225 deletions

View File

@ -42,8 +42,6 @@ type MasterConfiguration struct {
Networking Networking
// KubernetesVersion is the target version of the control plane.
KubernetesVersion string
// CloudProvider is the name of the cloud provider.
CloudProvider string
// NodeName is the name of the node that will host the k8s control plane.
// Defaults to the hostname if not provided.
NodeName string

View File

@ -0,0 +1,70 @@
/*
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 v1alpha1
import (
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
)
func addConversionFuncs(scheme *runtime.Scheme) error {
// Add non-generated conversion functions
err := scheme.AddConversionFuncs(
Convert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration,
Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration,
)
if err != nil {
return err
}
return nil
}
func Convert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in *kubeadm.MasterConfiguration, out *MasterConfiguration, s conversion.Scope) error {
if err := autoConvert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in, out, s); err != nil {
return err
}
// Setting .CloudProvider is not supported from internal API not supported
return nil
}
func Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in *MasterConfiguration, out *kubeadm.MasterConfiguration, s conversion.Scope) error {
if err := autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in, out, s); err != nil {
return err
}
UpgradeCloudProvider(in, out)
return nil
}
// UpgradeCloudProvider handles the removal of .CloudProvider as smoothly as possible
func UpgradeCloudProvider(in *MasterConfiguration, out *kubeadm.MasterConfiguration) {
if len(in.CloudProvider) != 0 {
if out.APIServerExtraArgs == nil {
out.APIServerExtraArgs = map[string]string{}
}
if out.ControllerManagerExtraArgs == nil {
out.ControllerManagerExtraArgs = map[string]string{}
}
out.APIServerExtraArgs["cloud-provider"] = in.CloudProvider
out.ControllerManagerExtraArgs["cloud-provider"] = in.CloudProvider
}
}

View File

@ -43,7 +43,7 @@ func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs)
localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs, addConversionFuncs)
}
// Kind takes an unqualified kind and returns a Group qualified GroupKind

View File

@ -42,8 +42,6 @@ type MasterConfiguration struct {
Networking Networking `json:"networking"`
// KubernetesVersion is the target version of the control plane.
KubernetesVersion string `json:"kubernetesVersion"`
// CloudProvider is the name of the cloud provider.
CloudProvider string `json:"cloudProvider"`
// NodeName is the name of the node that will host the k8s control plane.
// Defaults to the hostname if not provided.
NodeName string `json:"nodeName"`

View File

@ -49,20 +49,6 @@ import (
"k8s.io/kubernetes/pkg/util/node"
)
// TODO: Break out the cloudprovider functionality out of core and only support the new flow
// described in https://github.com/kubernetes/community/pull/128
var cloudproviders = []string{
"aws",
"azure",
"cloudstack",
"gce",
"external", // Support for out-of-tree cloud providers
"openstack",
"ovirt",
"photon",
"vsphere",
}
// Describes the authorization modes that are enforced by kubeadm
var requiredAuthzModes = []string{
authzmodes.ModeRBAC,
@ -72,7 +58,6 @@ var requiredAuthzModes = []string{
// ValidateMasterConfiguration validates master configuration and collects all encountered errors
func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateCloudProvider(c.CloudProvider, field.NewPath("cloudProvider"))...)
allErrs = append(allErrs, ValidateAuthorizationModes(c.AuthorizationModes, field.NewPath("authorizationModes"))...)
allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...)
allErrs = append(allErrs, ValidateCertSANs(c.APIServerCertSANs, field.NewPath("apiServerCertSANs"))...)
@ -332,21 +317,6 @@ func ValidateNodeName(nodename string, fldPath *field.Path) field.ErrorList {
return allErrs
}
// ValidateCloudProvider validates if cloud provider is supported
func ValidateCloudProvider(provider string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(provider) == 0 {
return allErrs
}
for _, supported := range cloudproviders {
if provider == supported {
return allErrs
}
}
allErrs = append(allErrs, field.Invalid(fldPath, provider, "cloudprovider not supported"))
return allErrs
}
// ValidateMixedArguments validates passed arguments
func ValidateMixedArguments(flag *pflag.FlagSet) error {
// If --config isn't set, we have nothing to validate

View File

@ -155,30 +155,6 @@ func TestValidateNodeName(t *testing.T) {
}
}
func TestValidateCloudProvider(t *testing.T) {
var tests = []struct {
s string
f *field.Path
expected bool
}{
{"", nil, true}, // if not provided, ok, it's optional
{"1234", nil, false}, // not supported
{"awws", nil, false}, // not supported
{"aws", nil, true}, // supported
{"gce", nil, true}, // supported
}
for _, rt := range tests {
actual := ValidateCloudProvider(rt.s, rt.f)
if (len(actual) == 0) != rt.expected {
t.Errorf(
"failed ValidateCloudProvider:\n\texpected: %t\n\t actual: %t",
rt.expected,
(len(actual) == 0),
)
}
}
}
func TestValidateCertSANs(t *testing.T) {
var tests = []struct {
sans []string

View File

@ -254,12 +254,6 @@ func NewInit(cfgPath string, externalcfg *kubeadmapiv1alpha2.MasterConfiguration
glog.Infof("[init] using Kubernetes version: %s\n", cfg.KubernetesVersion)
glog.Infof("[init] using Authorization modes: %v\n", cfg.AuthorizationModes)
// Warn about the limitations with the current cloudprovider solution.
if cfg.CloudProvider != "" {
glog.Warningln("[init] for cloudprovider integrations to work --cloud-provider must be set for all kubelets in the cluster")
glog.Infoln("\t(/etc/systemd/system/kubelet.service.d/10-kubeadm.conf should be edited for this purpose)")
}
glog.Infoln("[preflight] running pre-flight checks")
if err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, ignorePreflightErrors); err != nil {

View File

@ -127,7 +127,7 @@ func TestConfigDirCleaner(t *testing.T) {
"manifests",
},
},
"preserve cloud-config": {
"preserve unrelated file foo": {
setupDirs: []string{
"manifests",
"pki",
@ -138,12 +138,12 @@ func TestConfigDirCleaner(t *testing.T) {
"pki/ca.pem",
kubeadmconstants.AdminKubeConfigFileName,
kubeadmconstants.KubeletKubeConfigFileName,
"cloud-config",
"foo",
},
verifyExists: []string{
"manifests",
"pki",
"cloud-config",
"foo",
},
},
"preserve hidden files and directories": {
@ -158,13 +158,11 @@ func TestConfigDirCleaner(t *testing.T) {
"pki/ca.pem",
kubeadmconstants.AdminKubeConfigFileName,
kubeadmconstants.KubeletKubeConfigFileName,
".cloud-config",
".mydir/.myfile",
},
verifyExists: []string{
"manifests",
"pki",
".cloud-config",
".mydir",
".mydir/.myfile",
},

View File

@ -47,7 +47,6 @@ func TestPrintConfiguration(t *testing.T) {
logDir: ""
path: ""
certificatesDir: ""
cloudProvider: ""
etcd:
caFile: ""
certFile: ""
@ -87,7 +86,6 @@ func TestPrintConfiguration(t *testing.T) {
logDir: ""
path: ""
certificatesDir: ""
cloudProvider: ""
etcd:
caFile: ""
certFile: ""
@ -132,7 +130,6 @@ func TestPrintConfiguration(t *testing.T) {
logDir: ""
path: ""
certificatesDir: ""
cloudProvider: ""
etcd:
caFile: ""
certFile: ""

View File

@ -42,13 +42,7 @@ import (
"k8s.io/kubernetes/pkg/util/version"
)
// Static pod definitions in golang form are included below so that `kubeadm init` can get going.
const (
DefaultCloudConfigPath = "/etc/kubernetes/cloud-config"
deprecatedV19AdmissionControl = "NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota"
defaultV19AdmissionControl = "NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota"
)
const defaultAdmissionControl = "NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota"
// CreateInitStaticPodManifestFiles will write all static pod manifest files needed to bring up the control plane.
func CreateInitStaticPodManifestFiles(manifestDir string, cfg *kubeadmapi.MasterConfiguration) error {
@ -165,7 +159,7 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
defaultArguments := map[string]string{
"advertise-address": cfg.API.AdvertiseAddress,
"insecure-port": "0",
"admission-control": defaultV19AdmissionControl,
"admission-control": defaultAdmissionControl,
"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),
@ -190,10 +184,6 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
command := []string{"kube-apiserver"}
if cfg.CloudProvider == "aws" || cfg.CloudProvider == "gce" {
defaultArguments["admission-control"] = deprecatedV19AdmissionControl
}
// If the user set endpoints for an external etcd cluster
if len(cfg.Etcd.Endpoints) > 0 {
defaultArguments["etcd-servers"] = strings.Join(cfg.Etcd.Endpoints, ",")
@ -225,15 +215,6 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
}
}
if cfg.CloudProvider != "" {
defaultArguments["cloud-provider"] = cfg.CloudProvider
// Only append the --cloud-config option if there's a such file
if _, err := os.Stat(DefaultCloudConfigPath); err == nil {
defaultArguments["cloud-config"] = DefaultCloudConfigPath
}
}
if features.Enabled(cfg.FeatureGates, features.HighAvailability) {
defaultArguments["endpoint-reconciler-type"] = reconcilers.LeaseEndpointReconcilerType
}
@ -323,15 +304,6 @@ func getControllerManagerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion
defaultArguments["cluster-signing-cert-file"] = ""
}
if cfg.CloudProvider != "" {
defaultArguments["cloud-provider"] = cfg.CloudProvider
// Only append the --cloud-config option if there's a such file
if _, err := os.Stat(DefaultCloudConfigPath); err == nil {
defaultArguments["cloud-config"] = DefaultCloudConfigPath
}
}
// 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 != "" {

View File

@ -136,27 +136,20 @@ func TestCreateStaticPodFilesAndWrappers(t *testing.T) {
}
}
func TestCreatePrivilegedContainerForOpenStack(t *testing.T) {
// Creates a Master Configuration with OpenStack cloud provider
func TestPrivilegedPods(t *testing.T) {
var staticPodNames = []string{
kubeadmconstants.KubeAPIServer,
kubeadmconstants.KubeControllerManager,
}
var assertions = []struct {
cloudProvider string
privilegedPods bool
expectedPrivilege bool
}{
{
cloudProvider: "",
privilegedPods: false,
expectedPrivilege: false,
},
{
cloudProvider: "aws",
expectedPrivilege: false,
},
{
cloudProvider: "openstack",
privilegedPods: true,
expectedPrivilege: true,
},
@ -165,7 +158,6 @@ func TestCreatePrivilegedContainerForOpenStack(t *testing.T) {
for _, assertion := range assertions {
cfg := &kubeadmapi.MasterConfiguration{
KubernetesVersion: "v1.9.0",
CloudProvider: assertion.cloudProvider,
PrivilegedPods: assertion.privilegedPods,
}
@ -177,11 +169,11 @@ func TestCreatePrivilegedContainerForOpenStack(t *testing.T) {
sc := spec.Spec.Containers[0].SecurityContext
if assertion.expectedPrivilege == true {
if sc == nil || sc.Privileged == nil || *sc.Privileged == false {
t.Errorf("GetStaticPodSpecs did not enable privileged containers in %s pod for provider %s", podname, assertion.cloudProvider)
t.Errorf("GetStaticPodSpecs did not enable privileged containers in %s pod", podname)
}
} else {
if sc != nil && sc.Privileged != nil && *sc.Privileged == true {
t.Errorf("GetStaticPodSpecs enabled privileged containers in %s pod for provider %s", podname, assertion.cloudProvider)
t.Errorf("GetStaticPodSpecs enabled privileged containers in %s pod", podname)
}
}
}
@ -470,84 +462,6 @@ func TestGetAPIServerCommand(t *testing.T) {
"--audit-log-maxage=0",
},
},
{
name: "ensure gce cloud provider gets passed through",
cfg: &kubeadmapi.MasterConfiguration{
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
CertificatesDir: testCertsDir,
CloudProvider: "gce",
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
"--kubelet-client-certificate=" + testCertsDir + "/apiserver-kubelet-client.crt",
"--kubelet-client-key=" + testCertsDir + "/apiserver-kubelet-client.key",
"--enable-bootstrap-token-auth=true",
"--secure-port=123",
"--allow-privileged=true",
"--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname",
"--proxy-client-cert-file=/var/lib/certs/front-proxy-client.crt",
"--proxy-client-key-file=/var/lib/certs/front-proxy-client.key",
"--requestheader-username-headers=X-Remote-User",
"--requestheader-group-headers=X-Remote-Group",
"--requestheader-extra-headers-prefix=X-Remote-Extra-",
"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=1.2.3.4",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
"--cloud-provider=gce",
},
},
{
name: "ensure aws cloud provider gets passed through",
cfg: &kubeadmapi.MasterConfiguration{
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
CertificatesDir: testCertsDir,
CloudProvider: "aws",
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
"--kubelet-client-certificate=" + testCertsDir + "/apiserver-kubelet-client.crt",
"--kubelet-client-key=" + testCertsDir + "/apiserver-kubelet-client.key",
"--enable-bootstrap-token-auth=true",
"--secure-port=123",
"--allow-privileged=true",
"--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname",
"--proxy-client-cert-file=/var/lib/certs/front-proxy-client.crt",
"--proxy-client-key-file=/var/lib/certs/front-proxy-client.key",
"--requestheader-username-headers=X-Remote-User",
"--requestheader-group-headers=X-Remote-Group",
"--requestheader-extra-headers-prefix=X-Remote-Extra-",
"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=1.2.3.4",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
"--cloud-provider=aws",
},
},
{
name: "ensure the DynamicKubelet flag gets passed through",
cfg: &kubeadmapi.MasterConfiguration{
@ -672,26 +586,6 @@ func TestGetControllerManagerCommand(t *testing.T) {
"--controllers=*,bootstrapsigner,tokencleaner",
},
},
{
cfg: &kubeadmapi.MasterConfiguration{
CloudProvider: "foo",
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.7.0",
},
expected: []string{
"kube-controller-manager",
"--address=127.0.0.1",
"--leader-elect=true",
"--kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
"--root-ca-file=" + testCertsDir + "/ca.crt",
"--service-account-private-key-file=" + testCertsDir + "/sa.key",
"--cluster-signing-cert-file=" + testCertsDir + "/ca.crt",
"--cluster-signing-key-file=" + testCertsDir + "/ca.key",
"--use-service-account-credentials=true",
"--controllers=*,bootstrapsigner,tokencleaner",
"--cloud-provider=foo",
},
},
{
cfg: &kubeadmapi.MasterConfiguration{
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16"},

View File

@ -34,7 +34,6 @@ const (
caCertsVolumeName = "ca-certs"
caCertsVolumePath = "/etc/ssl/certs"
flexvolumeDirVolumeName = "flexvolume-dir"
cloudConfigVolumeName = "cloud-config"
flexvolumeDirVolumePath = "/usr/libexec/kubernetes/kubelet-plugins/volume/exec"
)
@ -77,13 +76,6 @@ func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) c
// 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)
// Read-only mount of the cloud config file if present
if cfg.CloudProvider != "" {
if _, err := os.Stat(DefaultCloudConfigPath); err == nil {
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, cloudConfigVolumeName, DefaultCloudConfigPath, DefaultCloudConfigPath, true, &hostPathFileOrCreate)
mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, cloudConfigVolumeName, DefaultCloudConfigPath, DefaultCloudConfigPath, 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() {

View File

@ -556,9 +556,6 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
if _, ok := mounts.volumeMounts[kubeadmconstants.KubeControllerManager][flexvolumeDirVolumeName]; ok {
delete(mounts.volumeMounts[kubeadmconstants.KubeControllerManager], flexvolumeDirVolumeName)
}
if _, ok := mounts.volumeMounts[kubeadmconstants.KubeControllerManager][cloudConfigVolumeName]; ok {
delete(mounts.volumeMounts[kubeadmconstants.KubeControllerManager], cloudConfigVolumeName)
}
if !reflect.DeepEqual(mounts.volumes, rt.vol) {
t.Errorf(
"failed getHostPathVolumesForTheControlPlane:\n\texpected: %v\n\t actual: %v",

View File

@ -55,7 +55,6 @@ authorizationModes:
- Node
- RBAC
certificatesDir: %s
cloudProvider: ""
controllerManagerExtraArgs: null
etcd:
caFile: ""