diff --git a/README.md b/README.md index 99eae8d4e3..fa69909dac 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,15 @@ you should use Go 1.6 or later) ## Bringing up a cluster on AWS -* Ensure you have a DNS hosted zone set up in Route 53, e.g. `mydomain.com` +* Set up a DNS hosted zone in Route 53, e.g. `mydomain.com`, and set up the DNS nameservers as normal + so that domains will resolve. You can reuse an existing domain name (e.g. `mydomain.com`), or you can create + a "child" hosted zone (e.g. `myclusters.mydomain.com`) if you want to isolate them. Note that with AWS Route53, + you can have subdomains in a single hosted zone, so you can have `cluster1.testclusters.mydomain.com` under + `mydomain.com`. * Pick a DNS name under this zone to be the name of your cluster. kops will set up DNS so your cluster -can be reached on this name. For example, if your zone was `mydomain.com`, a good name would be -`kubernetes.mydomain.com`, or `dev.k8s.mydomain.com`, or even `dev.k8s.myproject.mydomain.com`. We'll call this `NAME`. + can be reached on this name. For example, if your zone was `mydomain.com`, a good name would be + `kubernetes.mydomain.com`, or `dev.k8s.mydomain.com`, or even `dev.k8s.myproject.mydomain.com`. We'll call this `NAME`. * Set `AWS_PROFILE` (if you need to select a profile for the AWS CLI to work) diff --git a/upup/pkg/fi/cloud.go b/upup/pkg/fi/cloud.go index 006cc6f7e0..2207a0edbb 100644 --- a/upup/pkg/fi/cloud.go +++ b/upup/pkg/fi/cloud.go @@ -7,6 +7,8 @@ const CloudProviderGCE CloudProviderID = "gce" type Cloud interface { ProviderID() CloudProviderID + + FindDNSHostedZone(dnsName string) (string, error) } // zonesToCloud allows us to infer from certain well-known zones to a cloud diff --git a/upup/pkg/fi/cloudup/awsup/aws_cloud.go b/upup/pkg/fi/cloudup/awsup/aws_cloud.go index 026ee67366..96faead24b 100644 --- a/upup/pkg/fi/cloudup/awsup/aws_cloud.go +++ b/upup/pkg/fi/cloudup/awsup/aws_cloud.go @@ -464,3 +464,60 @@ func (c *AWSCloud) ValidateZones(zones []string) error { return nil } + +func (c *AWSCloud) FindDNSHostedZone(clusterDNSName string) (string, error) { + glog.V(2).Infof("Querying for all route53 zones to find match for %q", clusterDNSName) + + clusterDNSName = "." + strings.TrimSuffix(clusterDNSName, ".") + + var zones []*route53.HostedZone + request := &route53.ListHostedZonesInput{} + err := c.Route53.ListHostedZonesPages(request, func(p *route53.ListHostedZonesOutput, lastPage bool) bool { + for _, zone := range p.HostedZones { + zoneName := aws.StringValue(zone.Name) + zoneName = "." + strings.TrimSuffix(zoneName, ".") + + if strings.HasSuffix(clusterDNSName, zoneName) { + zones = append(zones, zone) + } + } + return true + }) + if err != nil { + return "", fmt.Errorf("error querying for route53 zones: %v", err) + } + + // Find the longest zones + maxLength := -1 + maxLengthZones := []*route53.HostedZone{} + for _, z := range zones { + n := len(aws.StringValue(z.Name)) + if n < maxLength { + continue + } + + if n > maxLength { + maxLength = n + maxLengthZones = []*route53.HostedZone{} + } + + maxLengthZones = append(maxLengthZones, z) + } + + if len(maxLengthZones) == 0 { + // We make this an error because you have to set up DNS delegation anyway + tokens := strings.Split(clusterDNSName, ".") + suffix := strings.Join(tokens[len(tokens)-2:], ".") + //glog.Warningf("No matching hosted zones found; will created %q", suffix) + //return suffix, nil + return "", fmt.Errorf("No matching hosted zones found for %q; please create one (e.g. %q) first", clusterDNSName, suffix) + } + + if len(maxLengthZones) == 1 { + id := aws.StringValue(maxLengthZones[0].Id) + id = strings.TrimPrefix(id, "/hostedzone/") + return id, nil + } + + return "", fmt.Errorf("Found multiple hosted zones matching cluster %q; please specify the ID of the zone to use") +} diff --git a/upup/pkg/fi/cloudup/create_cluster.go b/upup/pkg/fi/cloudup/create_cluster.go index 02ae292b92..cba96abea5 100644 --- a/upup/pkg/fi/cloudup/create_cluster.go +++ b/upup/pkg/fi/cloudup/create_cluster.go @@ -93,11 +93,6 @@ func (c *CreateClusterCmd) Run() error { if c.Cluster.Spec.MasterPublicName == "" { c.Cluster.Spec.MasterPublicName = "api." + c.Cluster.Name } - if c.Cluster.Spec.DNSZone == "" { - tokens := strings.Split(c.Cluster.Spec.MasterPublicName, ".") - c.Cluster.Spec.DNSZone = strings.Join(tokens[len(tokens)-2:], ".") - glog.Infof("Defaulting DNS zone to: %s", c.Cluster.Spec.DNSZone) - } if len(c.Cluster.Spec.Zones) == 0 { // TODO: Auto choose zones from region? @@ -437,6 +432,15 @@ func (c *CreateClusterCmd) Run() error { return fmt.Errorf("unknown CloudProvider %q", c.Cluster.Spec.CloudProvider) } + if c.Cluster.Spec.DNSZone == "" { + dnsZone, err := cloud.FindDNSHostedZone(c.Cluster.Name) + if err != nil { + return fmt.Errorf("Error determining default DNS zone; please specify --zone-name: %v", err) + } + glog.Infof("Defaulting DNS zone to: %s", dnsZone) + c.Cluster.Spec.DNSZone = dnsZone + } + tf := &TemplateFunctions{ cluster: c.Cluster, } diff --git a/upup/pkg/fi/cloudup/gce/gce_cloud.go b/upup/pkg/fi/cloudup/gce/gce_cloud.go index c419b37205..af5824a321 100644 --- a/upup/pkg/fi/cloudup/gce/gce_cloud.go +++ b/upup/pkg/fi/cloudup/gce/gce_cloud.go @@ -49,3 +49,7 @@ func NewGCECloud(region string, project string) (*GCECloud, error) { return c, nil } + +func (c *GCECloud) FindDNSHostedZone(clusterDNSName string) (string, error) { + return "", fmt.Errorf("FindDNSHostedZone not yet implemented on GCE") +}