diff --git a/cmd/kubeadm/app/discovery/BUILD b/cmd/kubeadm/app/discovery/BUILD index e4e075a54e6..d31bf340f52 100644 --- a/cmd/kubeadm/app/discovery/BUILD +++ b/cmd/kubeadm/app/discovery/BUILD @@ -27,7 +27,10 @@ go_test( name = "go_default_test", srcs = ["discovery_test.go"], embed = [":go_default_library"], - deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"], + deps = [ + "//cmd/kubeadm/app/apis/kubeadm:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + ], ) filegroup( diff --git a/cmd/kubeadm/app/discovery/discovery.go b/cmd/kubeadm/app/discovery/discovery.go index 691f171bce9..dd11b1d5245 100644 --- a/cmd/kubeadm/app/discovery/discovery.go +++ b/cmd/kubeadm/app/discovery/discovery.go @@ -75,9 +75,9 @@ func DiscoverValidatedKubeConfig(cfg *kubeadmapi.JoinConfiguration) (*clientcmda case cfg.Discovery.File != nil: kubeConfigPath := cfg.Discovery.File.KubeConfigPath if isHTTPSURL(kubeConfigPath) { - return https.RetrieveValidatedConfigInfo(kubeConfigPath, kubeadmapiv1beta2.DefaultClusterName) + return https.RetrieveValidatedConfigInfo(kubeConfigPath, kubeadmapiv1beta2.DefaultClusterName, cfg.Discovery.Timeout.Duration) } - return file.RetrieveValidatedConfigInfo(kubeConfigPath, kubeadmapiv1beta2.DefaultClusterName) + return file.RetrieveValidatedConfigInfo(kubeConfigPath, kubeadmapiv1beta2.DefaultClusterName, cfg.Discovery.Timeout.Duration) case cfg.Discovery.BootstrapToken != nil: return token.RetrieveValidatedConfigInfo(cfg) default: diff --git a/cmd/kubeadm/app/discovery/discovery_test.go b/cmd/kubeadm/app/discovery/discovery_test.go index 66ccff97111..f6daeffddba 100644 --- a/cmd/kubeadm/app/discovery/discovery_test.go +++ b/cmd/kubeadm/app/discovery/discovery_test.go @@ -18,7 +18,9 @@ package discovery import ( "testing" + "time" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" ) @@ -69,7 +71,9 @@ func TestFor(t *testing.T) { } for _, rt := range tests { t.Run(rt.name, func(t *testing.T) { - _, actual := For(&rt.d) + config := rt.d + config.Discovery.Timeout = &metav1.Duration{Duration: 5 * time.Minute} + _, actual := For(&config) if (actual == nil) != rt.expect { t.Errorf( "failed For:\n\texpected: %t\n\t actual: %t", diff --git a/cmd/kubeadm/app/discovery/file/file.go b/cmd/kubeadm/app/discovery/file/file.go index a1c84a97b23..a7a932c86d4 100644 --- a/cmd/kubeadm/app/discovery/file/file.go +++ b/cmd/kubeadm/app/discovery/file/file.go @@ -17,6 +17,8 @@ limitations under the License. package file import ( + "time" + "github.com/pkg/errors" "k8s.io/api/core/v1" @@ -34,18 +36,18 @@ import ( // RetrieveValidatedConfigInfo connects to the API Server and makes sure it can talk // securely to the API Server using the provided CA cert and // optionally refreshes the cluster-info information from the cluster-info ConfigMap -func RetrieveValidatedConfigInfo(filepath, clustername string) (*clientcmdapi.Config, error) { +func RetrieveValidatedConfigInfo(filepath, clustername string, discoveryTimeout time.Duration) (*clientcmdapi.Config, error) { config, err := clientcmd.LoadFromFile(filepath) if err != nil { return nil, err } - return ValidateConfigInfo(config, clustername) + return ValidateConfigInfo(config, clustername, discoveryTimeout) } // ValidateConfigInfo connects to the API Server and makes sure it can talk // securely to the API Server using the provided CA cert/client certificates and // optionally refreshes the cluster-info information from the cluster-info ConfigMap -func ValidateConfigInfo(config *clientcmdapi.Config, clustername string) (*clientcmdapi.Config, error) { +func ValidateConfigInfo(config *clientcmdapi.Config, clustername string, discoveryTimeout time.Duration) (*clientcmdapi.Config, error) { err := validateKubeConfig(config) if err != nil { return nil, err @@ -91,7 +93,7 @@ func ValidateConfigInfo(config *clientcmdapi.Config, clustername string) (*clien klog.V(1).Infof("[discovery] Created cluster-info discovery client, requesting info from %q\n", currentCluster.Server) var clusterinfoCM *v1.ConfigMap - wait.PollInfinite(constants.DiscoveryRetryInterval, func() (bool, error) { + err = wait.Poll(constants.DiscoveryRetryInterval, discoveryTimeout, func() (bool, error) { var err error clusterinfoCM, err = client.CoreV1().ConfigMaps(metav1.NamespacePublic).Get(bootstrapapi.ConfigMapClusterInfo, metav1.GetOptions{}) if err != nil { @@ -106,6 +108,9 @@ func ValidateConfigInfo(config *clientcmdapi.Config, clustername string) (*clien } return true, nil }) + if err == wait.ErrWaitTimeout { + return nil, errors.Errorf("Abort reading the %s ConfigMap after timeout of %v", bootstrapapi.ConfigMapClusterInfo, discoveryTimeout) + } // If we couldn't fetch the cluster-info ConfigMap, just return the cluster-info object the user provided if clusterinfoCM == nil { diff --git a/cmd/kubeadm/app/discovery/https/https.go b/cmd/kubeadm/app/discovery/https/https.go index 82d342ec74c..2767eeddf1d 100644 --- a/cmd/kubeadm/app/discovery/https/https.go +++ b/cmd/kubeadm/app/discovery/https/https.go @@ -19,6 +19,7 @@ package https import ( "io/ioutil" "net/http" + "time" netutil "k8s.io/apimachinery/pkg/util/net" "k8s.io/client-go/tools/clientcmd" @@ -29,7 +30,7 @@ import ( // RetrieveValidatedConfigInfo connects to the API Server and makes sure it can talk // securely to the API Server using the provided CA cert and // optionally refreshes the cluster-info information from the cluster-info ConfigMap -func RetrieveValidatedConfigInfo(httpsURL, clustername string) (*clientcmdapi.Config, error) { +func RetrieveValidatedConfigInfo(httpsURL, clustername string, discoveryTimeout time.Duration) (*clientcmdapi.Config, error) { client := &http.Client{Transport: netutil.SetOldTransportDefaults(&http.Transport{})} response, err := client.Get(httpsURL) if err != nil { @@ -46,5 +47,5 @@ func RetrieveValidatedConfigInfo(httpsURL, clustername string) (*clientcmdapi.Co if err != nil { return nil, err } - return file.ValidateConfigInfo(config, clustername) + return file.ValidateConfigInfo(config, clustername, discoveryTimeout) }