Find matching existing DNS hosted zone

We choose the longest matching existing hosted zone as the default,
rather than the previous heuristic which was overly simplistic.

We also require the hosted zone to exist now; it doesn't seem to really
cost us anything given that the user has to set up DNS delegation
anyway.

Fix #125
This commit is contained in:
Justin Santa Barbara 2016-07-12 22:15:20 -04:00
parent b69ee2a0ee
commit cae256340b
5 changed files with 79 additions and 8 deletions

View File

@ -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)

View File

@ -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

View File

@ -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")
}

View File

@ -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,
}

View File

@ -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")
}