Skip to content

Commit

Permalink
Merge pull request kubernetes#49119 from kad/n-addons-repo
Browse files Browse the repository at this point in the history
Automatic merge from submit-queue (batch tested with PRs 50693, 50831, 47506, 49119, 50871)

kubeadm: Implement support for using images from CI builds

**What this PR does / why we need it**: Implements support for CI images in kubeadm

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes kubernetes/kubeadm#337

**Special notes for your reviewer**:

**Release note**:
```release-note
- kubeadm now supports "ci/latest-1.8" or "ci-cross/latest-1.8" and similar labels.
```
  • Loading branch information
Kubernetes Submit Queue authored Aug 21, 2017
2 parents 990395d + 9f3ac32 commit f40d074
Show file tree
Hide file tree
Showing 11 changed files with 439 additions and 19 deletions.
1 change: 1 addition & 0 deletions cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
obj.Etcd.Image = "foo"
obj.Etcd.DataDir = "foo"
obj.ImageRepository = "foo"
obj.CIImageRepository = ""
obj.UnifiedControlPlaneImage = "foo"
obj.FeatureFlags = map[string]bool{}
},
Expand Down
17 changes: 17 additions & 0 deletions cmd/kubeadm/app/apis/kubeadm/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ type MasterConfiguration struct {

// ImageRepository what container registry to pull control plane images from
ImageRepository string

// Container registry for core images generated by CI
// +k8s:conversion-gen=false
CIImageRepository string

// UnifiedControlPlaneImage specifies if a specific container image should be used for all control plane components
UnifiedControlPlaneImage string

Expand Down Expand Up @@ -115,3 +120,15 @@ type NodeConfiguration struct {
// the security of kubeadm since other nodes can impersonate the master.
DiscoveryTokenUnsafeSkipCAVerification bool
}

// GetControlPlaneImageRepository returns name of image repository
// for control plane images (API,Controller Manager,Scheduler and Proxy)
// It will override location with CI registry name in case user requests special
// Kubernetes version from CI build area.
// (See: kubeadmconstants.DefaultCIImageRepository)
func (cfg *MasterConfiguration) GetControlPlaneImageRepository() string {
if cfg.CIImageRepository != "" {
return cfg.CIImageRepository
}
return cfg.ImageRepository
}
2 changes: 2 additions & 0 deletions cmd/kubeadm/app/apis/kubeadm/v1alpha1/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ go_library(
"doc.go",
"register.go",
"types.go",
"zz_generated.conversion.go",
"zz_generated.deepcopy.go",
"zz_generated.defaults.go",
],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
Expand Down
1 change: 1 addition & 0 deletions cmd/kubeadm/app/apis/kubeadm/v1alpha1/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ limitations under the License.
// +k8s:defaulter-gen=TypeMeta
// +groupName=kubeadm.k8s.io
// +k8s:deepcopy-gen=package
// +k8s:conversion-gen=k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm
package v1alpha1 // import "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
279 changes: 279 additions & 0 deletions cmd/kubeadm/app/apis/kubeadm/v1alpha1/zz_generated.conversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
// +build !ignore_autogenerated

/*
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.
*/

// This file was autogenerated by conversion-gen. Do not edit it manually!

package v1alpha1

import (
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
time "time"
unsafe "unsafe"
)

func init() {
localSchemeBuilder.Register(RegisterConversions)
}

// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1alpha1_API_To_kubeadm_API,
Convert_kubeadm_API_To_v1alpha1_API,
Convert_v1alpha1_Etcd_To_kubeadm_Etcd,
Convert_kubeadm_Etcd_To_v1alpha1_Etcd,
Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration,
Convert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration,
Convert_v1alpha1_Networking_To_kubeadm_Networking,
Convert_kubeadm_Networking_To_v1alpha1_Networking,
Convert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration,
Convert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration,
Convert_v1alpha1_TokenDiscovery_To_kubeadm_TokenDiscovery,
Convert_kubeadm_TokenDiscovery_To_v1alpha1_TokenDiscovery,
)
}

func autoConvert_v1alpha1_API_To_kubeadm_API(in *API, out *kubeadm.API, s conversion.Scope) error {
out.AdvertiseAddress = in.AdvertiseAddress
out.BindPort = in.BindPort
return nil
}

// Convert_v1alpha1_API_To_kubeadm_API is an autogenerated conversion function.
func Convert_v1alpha1_API_To_kubeadm_API(in *API, out *kubeadm.API, s conversion.Scope) error {
return autoConvert_v1alpha1_API_To_kubeadm_API(in, out, s)
}

func autoConvert_kubeadm_API_To_v1alpha1_API(in *kubeadm.API, out *API, s conversion.Scope) error {
out.AdvertiseAddress = in.AdvertiseAddress
out.BindPort = in.BindPort
return nil
}

// Convert_kubeadm_API_To_v1alpha1_API is an autogenerated conversion function.
func Convert_kubeadm_API_To_v1alpha1_API(in *kubeadm.API, out *API, s conversion.Scope) error {
return autoConvert_kubeadm_API_To_v1alpha1_API(in, out, s)
}

func autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s conversion.Scope) error {
out.Endpoints = *(*[]string)(unsafe.Pointer(&in.Endpoints))
out.CAFile = in.CAFile
out.CertFile = in.CertFile
out.KeyFile = in.KeyFile
out.DataDir = in.DataDir
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs))
out.Image = in.Image
return nil
}

// Convert_v1alpha1_Etcd_To_kubeadm_Etcd is an autogenerated conversion function.
func Convert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s conversion.Scope) error {
return autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in, out, s)
}

func autoConvert_kubeadm_Etcd_To_v1alpha1_Etcd(in *kubeadm.Etcd, out *Etcd, s conversion.Scope) error {
if in.Endpoints == nil {
out.Endpoints = make([]string, 0)
} else {
out.Endpoints = *(*[]string)(unsafe.Pointer(&in.Endpoints))
}
out.CAFile = in.CAFile
out.CertFile = in.CertFile
out.KeyFile = in.KeyFile
out.DataDir = in.DataDir
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs))
out.Image = in.Image
return nil
}

// Convert_kubeadm_Etcd_To_v1alpha1_Etcd is an autogenerated conversion function.
func Convert_kubeadm_Etcd_To_v1alpha1_Etcd(in *kubeadm.Etcd, out *Etcd, s conversion.Scope) error {
return autoConvert_kubeadm_Etcd_To_v1alpha1_Etcd(in, out, s)
}

func autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in *MasterConfiguration, out *kubeadm.MasterConfiguration, s conversion.Scope) error {
if err := Convert_v1alpha1_API_To_kubeadm_API(&in.API, &out.API, s); err != nil {
return err
}
if err := Convert_v1alpha1_Etcd_To_kubeadm_Etcd(&in.Etcd, &out.Etcd, s); err != nil {
return err
}
if err := Convert_v1alpha1_Networking_To_kubeadm_Networking(&in.Networking, &out.Networking, s); err != nil {
return err
}
out.KubernetesVersion = in.KubernetesVersion
out.CloudProvider = in.CloudProvider
out.NodeName = in.NodeName
out.AuthorizationModes = *(*[]string)(unsafe.Pointer(&in.AuthorizationModes))
out.Token = in.Token
out.TokenTTL = time.Duration(in.TokenTTL)
out.APIServerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.APIServerExtraArgs))
out.ControllerManagerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ControllerManagerExtraArgs))
out.SchedulerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.SchedulerExtraArgs))
out.APIServerCertSANs = *(*[]string)(unsafe.Pointer(&in.APIServerCertSANs))
out.CertificatesDir = in.CertificatesDir
out.ImageRepository = in.ImageRepository
out.UnifiedControlPlaneImage = in.UnifiedControlPlaneImage
out.FeatureFlags = *(*map[string]bool)(unsafe.Pointer(&in.FeatureFlags))
return nil
}

// Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration is an autogenerated conversion function.
func Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in *MasterConfiguration, out *kubeadm.MasterConfiguration, s conversion.Scope) error {
return autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in, out, s)
}

func autoConvert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in *kubeadm.MasterConfiguration, out *MasterConfiguration, s conversion.Scope) error {
if err := Convert_kubeadm_API_To_v1alpha1_API(&in.API, &out.API, s); err != nil {
return err
}
if err := Convert_kubeadm_Etcd_To_v1alpha1_Etcd(&in.Etcd, &out.Etcd, s); err != nil {
return err
}
if err := Convert_kubeadm_Networking_To_v1alpha1_Networking(&in.Networking, &out.Networking, s); err != nil {
return err
}
out.KubernetesVersion = in.KubernetesVersion
out.CloudProvider = in.CloudProvider
out.NodeName = in.NodeName
if in.AuthorizationModes == nil {
out.AuthorizationModes = make([]string, 0)
} else {
out.AuthorizationModes = *(*[]string)(unsafe.Pointer(&in.AuthorizationModes))
}
out.Token = in.Token
out.TokenTTL = time.Duration(in.TokenTTL)
out.APIServerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.APIServerExtraArgs))
out.ControllerManagerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ControllerManagerExtraArgs))
out.SchedulerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.SchedulerExtraArgs))
if in.APIServerCertSANs == nil {
out.APIServerCertSANs = make([]string, 0)
} else {
out.APIServerCertSANs = *(*[]string)(unsafe.Pointer(&in.APIServerCertSANs))
}
out.CertificatesDir = in.CertificatesDir
out.ImageRepository = in.ImageRepository
// INFO: in.CIImageRepository opted out of conversion generation
out.UnifiedControlPlaneImage = in.UnifiedControlPlaneImage
out.FeatureFlags = *(*map[string]bool)(unsafe.Pointer(&in.FeatureFlags))
return nil
}

// Convert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration is an autogenerated conversion function.
func Convert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in *kubeadm.MasterConfiguration, out *MasterConfiguration, s conversion.Scope) error {
return autoConvert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in, out, s)
}

func autoConvert_v1alpha1_Networking_To_kubeadm_Networking(in *Networking, out *kubeadm.Networking, s conversion.Scope) error {
out.ServiceSubnet = in.ServiceSubnet
out.PodSubnet = in.PodSubnet
out.DNSDomain = in.DNSDomain
return nil
}

// Convert_v1alpha1_Networking_To_kubeadm_Networking is an autogenerated conversion function.
func Convert_v1alpha1_Networking_To_kubeadm_Networking(in *Networking, out *kubeadm.Networking, s conversion.Scope) error {
return autoConvert_v1alpha1_Networking_To_kubeadm_Networking(in, out, s)
}

func autoConvert_kubeadm_Networking_To_v1alpha1_Networking(in *kubeadm.Networking, out *Networking, s conversion.Scope) error {
out.ServiceSubnet = in.ServiceSubnet
out.PodSubnet = in.PodSubnet
out.DNSDomain = in.DNSDomain
return nil
}

// Convert_kubeadm_Networking_To_v1alpha1_Networking is an autogenerated conversion function.
func Convert_kubeadm_Networking_To_v1alpha1_Networking(in *kubeadm.Networking, out *Networking, s conversion.Scope) error {
return autoConvert_kubeadm_Networking_To_v1alpha1_Networking(in, out, s)
}

func autoConvert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration(in *NodeConfiguration, out *kubeadm.NodeConfiguration, s conversion.Scope) error {
out.CACertPath = in.CACertPath
out.DiscoveryFile = in.DiscoveryFile
out.DiscoveryToken = in.DiscoveryToken
out.DiscoveryTokenAPIServers = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenAPIServers))
out.NodeName = in.NodeName
out.TLSBootstrapToken = in.TLSBootstrapToken
out.Token = in.Token
out.DiscoveryTokenCACertHashes = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenCACertHashes))
out.DiscoveryTokenUnsafeSkipCAVerification = in.DiscoveryTokenUnsafeSkipCAVerification
return nil
}

// Convert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration is an autogenerated conversion function.
func Convert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration(in *NodeConfiguration, out *kubeadm.NodeConfiguration, s conversion.Scope) error {
return autoConvert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration(in, out, s)
}

func autoConvert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration(in *kubeadm.NodeConfiguration, out *NodeConfiguration, s conversion.Scope) error {
out.CACertPath = in.CACertPath
out.DiscoveryFile = in.DiscoveryFile
out.DiscoveryToken = in.DiscoveryToken
if in.DiscoveryTokenAPIServers == nil {
out.DiscoveryTokenAPIServers = make([]string, 0)
} else {
out.DiscoveryTokenAPIServers = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenAPIServers))
}
out.NodeName = in.NodeName
out.TLSBootstrapToken = in.TLSBootstrapToken
out.Token = in.Token
if in.DiscoveryTokenCACertHashes == nil {
out.DiscoveryTokenCACertHashes = make([]string, 0)
} else {
out.DiscoveryTokenCACertHashes = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenCACertHashes))
}
out.DiscoveryTokenUnsafeSkipCAVerification = in.DiscoveryTokenUnsafeSkipCAVerification
return nil
}

// Convert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration is an autogenerated conversion function.
func Convert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration(in *kubeadm.NodeConfiguration, out *NodeConfiguration, s conversion.Scope) error {
return autoConvert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration(in, out, s)
}

func autoConvert_v1alpha1_TokenDiscovery_To_kubeadm_TokenDiscovery(in *TokenDiscovery, out *kubeadm.TokenDiscovery, s conversion.Scope) error {
out.ID = in.ID
out.Secret = in.Secret
out.Addresses = *(*[]string)(unsafe.Pointer(&in.Addresses))
return nil
}

// Convert_v1alpha1_TokenDiscovery_To_kubeadm_TokenDiscovery is an autogenerated conversion function.
func Convert_v1alpha1_TokenDiscovery_To_kubeadm_TokenDiscovery(in *TokenDiscovery, out *kubeadm.TokenDiscovery, s conversion.Scope) error {
return autoConvert_v1alpha1_TokenDiscovery_To_kubeadm_TokenDiscovery(in, out, s)
}

func autoConvert_kubeadm_TokenDiscovery_To_v1alpha1_TokenDiscovery(in *kubeadm.TokenDiscovery, out *TokenDiscovery, s conversion.Scope) error {
out.ID = in.ID
out.Secret = in.Secret
if in.Addresses == nil {
out.Addresses = make([]string, 0)
} else {
out.Addresses = *(*[]string)(unsafe.Pointer(&in.Addresses))
}
return nil
}

// Convert_kubeadm_TokenDiscovery_To_v1alpha1_TokenDiscovery is an autogenerated conversion function.
func Convert_kubeadm_TokenDiscovery_To_v1alpha1_TokenDiscovery(in *kubeadm.TokenDiscovery, out *TokenDiscovery, s conversion.Scope) error {
return autoConvert_kubeadm_TokenDiscovery_To_v1alpha1_TokenDiscovery(in, out, s)
}
3 changes: 3 additions & 0 deletions cmd/kubeadm/app/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ const (
// NodeBootstrapTokenAuthGroup specifies which group a Node Bootstrap Token should be authenticated in
// TODO: This should be changed in the v1.8 dev cycle to a node-BT-specific group instead of the generic Bootstrap Token group that is used now
NodeBootstrapTokenAuthGroup = "system:bootstrappers"

// DefaultCIImageRepository points to image registry where CI uploads images from ci-cross build job
DefaultCIImageRepository = "gcr.io/kubernetes-ci-images"
)

var (
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/phases/addons/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func EnsureProxyAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Inte
}

proxyDaemonSetBytes, err := kubeadmutil.ParseTemplate(KubeProxyDaemonSet, struct{ ImageRepository, Arch, Version, ImageOverride, ClusterCIDR, MasterTaintKey, CloudTaintKey string }{
ImageRepository: cfg.ImageRepository,
ImageRepository: cfg.GetControlPlaneImageRepository(),
Arch: runtime.GOARCH,
Version: kubeadmutil.KubernetesVersionToImageTag(cfg.KubernetesVersion),
ImageOverride: cfg.UnifiedControlPlaneImage,
Expand Down
6 changes: 3 additions & 3 deletions cmd/kubeadm/app/phases/controlplane/manifests.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func GetStaticPodSpecs(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.
staticPodSpecs := map[string]v1.Pod{
kubeadmconstants.KubeAPIServer: staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.KubeAPIServer,
Image: images.GetCoreImage(kubeadmconstants.KubeAPIServer, cfg.ImageRepository, cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
Image: images.GetCoreImage(kubeadmconstants.KubeAPIServer, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
Command: getAPIServerCommand(cfg, k8sVersion),
VolumeMounts: mounts.GetVolumeMounts(kubeadmconstants.KubeAPIServer),
LivenessProbe: staticpodutil.ComponentProbe(int(cfg.API.BindPort), "/healthz", v1.URISchemeHTTPS),
Expand All @@ -80,7 +80,7 @@ func GetStaticPodSpecs(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.
}, mounts.GetVolumes(kubeadmconstants.KubeAPIServer)),
kubeadmconstants.KubeControllerManager: staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.KubeControllerManager,
Image: images.GetCoreImage(kubeadmconstants.KubeControllerManager, cfg.ImageRepository, cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
Image: images.GetCoreImage(kubeadmconstants.KubeControllerManager, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
Command: getControllerManagerCommand(cfg, k8sVersion),
VolumeMounts: mounts.GetVolumeMounts(kubeadmconstants.KubeControllerManager),
LivenessProbe: staticpodutil.ComponentProbe(10252, "/healthz", v1.URISchemeHTTP),
Expand All @@ -89,7 +89,7 @@ func GetStaticPodSpecs(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.
}, mounts.GetVolumes(kubeadmconstants.KubeControllerManager)),
kubeadmconstants.KubeScheduler: staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.KubeScheduler,
Image: images.GetCoreImage(kubeadmconstants.KubeScheduler, cfg.ImageRepository, cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
Image: images.GetCoreImage(kubeadmconstants.KubeScheduler, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
Command: getSchedulerCommand(cfg),
VolumeMounts: mounts.GetVolumeMounts(kubeadmconstants.KubeScheduler),
LivenessProbe: staticpodutil.ComponentProbe(10251, "/healthz", v1.URISchemeHTTP),
Expand Down
5 changes: 5 additions & 0 deletions cmd/kubeadm/app/util/config/masterconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ func SetInitDynamicDefaults(cfg *kubeadmapi.MasterConfiguration) error {
}
cfg.API.AdvertiseAddress = ip.String()

// Requested version is automatic CI build, thus use KubernetesCI Image Repository for core images
if kubeadmutil.KubernetesIsCIVersion(cfg.KubernetesVersion) {
cfg.CIImageRepository = kubeadmconstants.DefaultCIImageRepository
}

// Validate version argument
ver, err := kubeadmutil.KubernetesReleaseVersion(cfg.KubernetesVersion)
if err != nil {
Expand Down
Loading

0 comments on commit f40d074

Please sign in to comment.