Merge pull request #3709 from chrislovecnm/placehold-dns-ux-updates

Automatic merge from submit-queue.

Improving UX for placeholder IP Address

Before the `kops validate cluster` attempts to connect to the K8s API
endpoint, the code now checks to see if the API DNS Entry is the kops
placeholder IP Address 203.0.113.123.  It prints a message to the user
and err's.  There is a new init func in validate cluster that disables
CGO based DNS for Darwin OS.  Darwin does two things with kops
validates; it caches the IP address, and it does not return the
placeholder IP address.  We cannot use CGO base DNS with kops validate with OSX.
This commit is contained in:
Kubernetes Submit Queue 2017-11-17 02:24:23 -08:00 committed by GitHub
commit d8e2ce211a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 0 deletions

View File

@ -20,6 +20,7 @@ import (
"fmt"
"io"
"os"
"runtime"
"strings"
"github.com/golang/glog"
@ -31,10 +32,18 @@ import (
"k8s.io/kops/cmd/kops/util"
api "k8s.io/kops/pkg/apis/kops"
apiutil "k8s.io/kops/pkg/apis/kops/util"
"k8s.io/kops/pkg/dns"
"k8s.io/kops/pkg/validation"
"k8s.io/kops/util/pkg/tables"
)
func init() {
if runtime.GOOS == "darwin" {
// In order for net.LookupHost(apiAddr.Host) to lookup our placeholder address on darwin, we have to
os.Setenv("GODEBUG", "netdns=go")
}
}
type ValidateClusterOptions struct {
// No options yet
}
@ -105,6 +114,25 @@ func RunValidateCluster(f *util.Factory, cmd *cobra.Command, args []string, out
return fmt.Errorf("Cannot build kube api client for %q: %v\n", contextName, err)
}
// Do not use if we are running gossip
if !dns.IsGossipHostname(cluster.ObjectMeta.Name) {
hasPlaceHolderIPAddress, err := validation.HasPlaceHolderIP(contextName)
if err != nil {
return err
}
if hasPlaceHolderIPAddress {
fmt.Println(
"Validation Failed\n\n" +
"The dns-controller Kubernetes deployment has not updated the Kubernetes cluster's API DNS entry to the correct IP address." +
" The API DNS IP address is the placeholder address that kops creates: 203.0.113.123." +
" Please wait about 5-10 minutes for a master to start, dns-controller to launch, and DNS to propagate." +
" The protokube container and dns-controller deployment logs may contain more diagnostic information." +
" Etcd and the API DNS entries must be updated for a kops Kubernetes cluster to start.")
return fmt.Errorf("\nCannot reach cluster's API server: unable to Validate Cluster: %s", cluster.ObjectMeta.Name)
}
}
validationCluster, validationFailed := validation.ValidateCluster(cluster.ObjectMeta.Name, list, k8sClient)
if validationCluster == nil || validationCluster.NodeList == nil || validationCluster.NodeList.Items == nil {

View File

@ -17,6 +17,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
],
)

View File

@ -18,11 +18,15 @@ package validation
import (
"fmt"
"net/url"
"time"
"net"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/util"
"k8s.io/kops/upup/pkg/fi"
@ -54,6 +58,32 @@ type ValidationNode struct {
Status v1.ConditionStatus `json:"status,omitempty"`
}
// HasPlaceHolderIP checks if the API DNS has been updated
func HasPlaceHolderIP(clusterName string) (bool, error) {
config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
clientcmd.NewDefaultClientConfigLoadingRules(),
&clientcmd.ConfigOverrides{CurrentContext: clusterName}).ClientConfig()
apiAddr, err := url.Parse(config.Host)
if err != nil {
return true, fmt.Errorf("unable to parse Kubernetes cluster API URL: %v", err)
}
hostAddrs, err := net.LookupHost(apiAddr.Host)
if err != nil {
return true, fmt.Errorf("unable to resolve Kubernetes cluster API URL dns: %v", err)
}
for _, h := range hostAddrs {
if h == "203.0.113.123" {
return true, nil
}
}
return false, nil
}
// ValidateCluster validate a k8s cluster with a provided instance group list
func ValidateCluster(clusterName string, instanceGroupList *kops.InstanceGroupList, clusterKubernetesClient kubernetes.Interface) (*ValidationCluster, error) {
var instanceGroups []*kops.InstanceGroup