mirror of https://github.com/kubernetes/kops.git
Create placeholder DNS records of correct type for IPv6 clusters
This commit is contained in:
parent
3a056c288b
commit
d4cf1a80f0
|
@ -13,6 +13,7 @@ go_library(
|
|||
"//pkg/cloudinstances:go_default_library",
|
||||
"//pkg/dns:go_default_library",
|
||||
"//upup/pkg/fi:go_default_library",
|
||||
"//upup/pkg/fi/cloudup:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"k8s.io/client-go/tools/pager"
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -90,7 +91,7 @@ func hasPlaceHolderIP(host string) (bool, error) {
|
|||
}
|
||||
|
||||
for _, h := range hostAddrs {
|
||||
if h == "203.0.113.123" {
|
||||
if h == cloudup.PlaceholderIP || h == cloudup.PlaceholderIPv6 {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@ go_test(
|
|||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//:go_default_library",
|
||||
"//dnsprovider/pkg/dnsprovider/rrstype:go_default_library",
|
||||
"//pkg/apis/kops:go_default_library",
|
||||
"//pkg/apis/kops/validation:go_default_library",
|
||||
"//pkg/assets:go_default_library",
|
||||
|
|
|
@ -40,11 +40,17 @@ const (
|
|||
// PlaceholderIP is from TEST-NET-3
|
||||
// https://en.wikipedia.org/wiki/Reserved_IP_addresses
|
||||
PlaceholderIP = "203.0.113.123"
|
||||
PlaceholderIPv6 = "fd00:dead:add::"
|
||||
PlaceholderTTL = 10
|
||||
// DigitalOcean's DNS servers require a certain minimum TTL (it's 30), keeping 60 here.
|
||||
PlaceholderTTLDigitialOcean = 60
|
||||
)
|
||||
|
||||
type recordKey struct {
|
||||
hostname string
|
||||
rrsType rrstype.RrsType
|
||||
}
|
||||
|
||||
func findZone(cluster *kops.Cluster, cloud fi.Cloud) (dnsprovider.Zone, error) {
|
||||
dns, err := cloud.DNS()
|
||||
if err != nil {
|
||||
|
@ -137,19 +143,19 @@ func precreateDNS(ctx context.Context, cluster *kops.Cluster, cloud fi.Cloud) er
|
|||
// This avoids hitting negative TTL on DNS lookups, which tend to be very long
|
||||
// If we get the names wrong here, it doesn't really matter (extra DNS name, slower boot)
|
||||
|
||||
dnsHostnames := buildPrecreateDNSHostnames(cluster)
|
||||
recordKeys := buildPrecreateDNSHostnames(cluster)
|
||||
|
||||
{
|
||||
var filtered []string
|
||||
for _, name := range dnsHostnames {
|
||||
if !kopsdns.IsGossipHostname(name) {
|
||||
filtered = append(filtered, name)
|
||||
var filtered []recordKey
|
||||
for _, recordKey := range recordKeys {
|
||||
if !kopsdns.IsGossipHostname(recordKey.hostname) {
|
||||
filtered = append(filtered, recordKey)
|
||||
}
|
||||
}
|
||||
dnsHostnames = filtered
|
||||
recordKeys = filtered
|
||||
}
|
||||
|
||||
if len(dnsHostnames) == 0 {
|
||||
if len(recordKeys) == 0 {
|
||||
klog.V(2).Infof("No DNS records to pre-create")
|
||||
return nil
|
||||
}
|
||||
|
@ -182,52 +188,56 @@ func precreateDNS(ctx context.Context, cluster *kops.Cluster, cloud fi.Cloud) er
|
|||
|
||||
changeset := rrs.StartChangeset()
|
||||
// TODO: Add ChangeSet.IsEmpty() method
|
||||
var created []string
|
||||
var created []recordKey
|
||||
|
||||
for _, dnsHostname := range dnsHostnames {
|
||||
dnsHostname = dns.EnsureDotSuffix(dnsHostname)
|
||||
foundA := false
|
||||
for _, recordKey := range recordKeys {
|
||||
recordKey.hostname = dns.EnsureDotSuffix(recordKey.hostname)
|
||||
foundAddress := false
|
||||
{
|
||||
dnsRecord := recordsMap["A::"+dnsHostname]
|
||||
dnsRecord := recordsMap[string(recordKey.rrsType)+"::"+recordKey.hostname]
|
||||
if dnsRecord != nil {
|
||||
rrdatas := dnsRecord.Rrdatas()
|
||||
if len(rrdatas) > 0 {
|
||||
klog.V(4).Infof("Found DNS record %s => %s; won't create", dnsHostname, rrdatas)
|
||||
klog.V(4).Infof("Found DNS record %s => %s; won't create", recordKey, rrdatas)
|
||||
} else {
|
||||
// This is probably an alias target; leave it alone...
|
||||
klog.V(4).Infof("Found DNS record %s, but no records", dnsHostname)
|
||||
klog.V(4).Infof("Found DNS record %s, but no records", recordKey)
|
||||
}
|
||||
foundA = true
|
||||
foundAddress = true
|
||||
}
|
||||
}
|
||||
|
||||
foundTXT := false
|
||||
{
|
||||
dnsRecord := recordsMap["TXT::"+dnsHostname]
|
||||
dnsRecord := recordsMap["TXT::"+recordKey.hostname]
|
||||
if dnsRecord != nil {
|
||||
foundTXT = true
|
||||
}
|
||||
}
|
||||
if foundA && foundTXT {
|
||||
if foundAddress && foundTXT {
|
||||
continue
|
||||
}
|
||||
|
||||
klog.V(2).Infof("Pre-creating DNS record %s => %s", dnsHostname, PlaceholderIP)
|
||||
ip := PlaceholderIP
|
||||
if recordKey.rrsType != rrstype.A {
|
||||
ip = PlaceholderIPv6
|
||||
}
|
||||
klog.V(2).Infof("Pre-creating DNS record %s => %s", recordKey, ip)
|
||||
|
||||
if !foundA {
|
||||
if !foundAddress {
|
||||
if cloud.ProviderID() == kops.CloudProviderDO {
|
||||
changeset.Add(rrs.New(dnsHostname, []string{PlaceholderIP}, PlaceholderTTLDigitialOcean, rrstype.A))
|
||||
changeset.Add(rrs.New(recordKey.hostname, []string{ip}, PlaceholderTTLDigitialOcean, recordKey.rrsType))
|
||||
} else {
|
||||
changeset.Add(rrs.New(dnsHostname, []string{PlaceholderIP}, PlaceholderTTL, rrstype.A))
|
||||
changeset.Add(rrs.New(recordKey.hostname, []string{ip}, PlaceholderTTL, recordKey.rrsType))
|
||||
|
||||
}
|
||||
}
|
||||
if !foundTXT {
|
||||
if cluster.Spec.ExternalDNS.Provider == kops.ExternalDNSProviderExternalDNS {
|
||||
changeset.Add(rrs.New(dnsHostname, []string{fmt.Sprintf("\"heritage=external-dns,external-dns/owner=kops-%s\"", cluster.ObjectMeta.Name)}, PlaceholderTTL, rrstype.TXT))
|
||||
changeset.Add(rrs.New(recordKey.hostname, []string{fmt.Sprintf("\"heritage=external-dns,external-dns/owner=kops-%s\"", cluster.ObjectMeta.Name)}, PlaceholderTTL, rrstype.TXT))
|
||||
}
|
||||
}
|
||||
created = append(created, dnsHostname)
|
||||
created = append(created, recordKey)
|
||||
}
|
||||
|
||||
if len(created) != 0 {
|
||||
|
@ -244,24 +254,43 @@ func precreateDNS(ctx context.Context, cluster *kops.Cluster, cloud fi.Cloud) er
|
|||
}
|
||||
|
||||
// buildPrecreateDNSHostnames returns the hostnames we should precreate
|
||||
func buildPrecreateDNSHostnames(cluster *kops.Cluster) []string {
|
||||
dnsHostnames := []string{}
|
||||
func buildPrecreateDNSHostnames(cluster *kops.Cluster) []recordKey {
|
||||
var recordKeys []recordKey
|
||||
internalType := rrstype.A
|
||||
if cluster.Spec.IsIPv6Only() {
|
||||
internalType = rrstype.AAAA
|
||||
}
|
||||
|
||||
hasAPILoadbalancer := cluster.Spec.API != nil && cluster.Spec.API.LoadBalancer != nil
|
||||
useLBForInternalAPI := hasAPILoadbalancer && cluster.Spec.API.LoadBalancer.UseForInternalApi
|
||||
|
||||
if cluster.Spec.MasterPublicName != "" && !hasAPILoadbalancer {
|
||||
dnsHostnames = append(dnsHostnames, cluster.Spec.MasterPublicName)
|
||||
recordKeys = append(recordKeys, recordKey{
|
||||
hostname: cluster.Spec.MasterPublicName,
|
||||
rrsType: rrstype.A,
|
||||
})
|
||||
if internalType != rrstype.A {
|
||||
recordKeys = append(recordKeys, recordKey{
|
||||
hostname: cluster.Spec.MasterPublicName,
|
||||
rrsType: internalType,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if cluster.Spec.MasterInternalName != "" && !useLBForInternalAPI {
|
||||
dnsHostnames = append(dnsHostnames, cluster.Spec.MasterInternalName)
|
||||
recordKeys = append(recordKeys, recordKey{
|
||||
hostname: cluster.Spec.MasterInternalName,
|
||||
rrsType: internalType,
|
||||
})
|
||||
}
|
||||
|
||||
if apimodel.UseKopsControllerForNodeBootstrap(cluster) {
|
||||
name := "kops-controller.internal." + cluster.ObjectMeta.Name
|
||||
dnsHostnames = append(dnsHostnames, name)
|
||||
recordKeys = append(recordKeys, recordKey{
|
||||
hostname: name,
|
||||
rrsType: internalType,
|
||||
})
|
||||
}
|
||||
|
||||
return dnsHostnames
|
||||
return recordKeys
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"sort"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kops/dnsprovider/pkg/dnsprovider/rrstype"
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
)
|
||||
|
||||
|
@ -28,13 +29,25 @@ func TestPrecreateDNSNames(t *testing.T) {
|
|||
|
||||
grid := []struct {
|
||||
cluster *kops.Cluster
|
||||
expected []string
|
||||
expected []recordKey
|
||||
}{
|
||||
{
|
||||
cluster: &kops.Cluster{},
|
||||
expected: []string{
|
||||
"api.cluster1.example.com",
|
||||
"api.internal.cluster1.example.com",
|
||||
expected: []recordKey{
|
||||
{"api.cluster1.example.com", rrstype.A},
|
||||
{"api.internal.cluster1.example.com", rrstype.A},
|
||||
},
|
||||
},
|
||||
{
|
||||
cluster: &kops.Cluster{
|
||||
Spec: kops.ClusterSpec{
|
||||
NonMasqueradeCIDR: "::/0",
|
||||
},
|
||||
},
|
||||
expected: []recordKey{
|
||||
{"api.cluster1.example.com", rrstype.A},
|
||||
{"api.cluster1.example.com", rrstype.AAAA},
|
||||
{"api.internal.cluster1.example.com", rrstype.AAAA},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -45,8 +58,21 @@ func TestPrecreateDNSNames(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
"api.internal.cluster1.example.com",
|
||||
expected: []recordKey{
|
||||
{"api.internal.cluster1.example.com", rrstype.A},
|
||||
},
|
||||
},
|
||||
{
|
||||
cluster: &kops.Cluster{
|
||||
Spec: kops.ClusterSpec{
|
||||
API: &kops.AccessSpec{
|
||||
LoadBalancer: &kops.LoadBalancerAccessSpec{},
|
||||
},
|
||||
NonMasqueradeCIDR: "::/0",
|
||||
},
|
||||
},
|
||||
expected: []recordKey{
|
||||
{"api.internal.cluster1.example.com", rrstype.AAAA},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -59,7 +85,35 @@ func TestPrecreateDNSNames(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
cluster: &kops.Cluster{
|
||||
Spec: kops.ClusterSpec{
|
||||
CloudProvider: "aws",
|
||||
KubernetesVersion: "1.22.0",
|
||||
},
|
||||
},
|
||||
expected: []recordKey{
|
||||
{"api.cluster1.example.com", rrstype.A},
|
||||
{"api.internal.cluster1.example.com", rrstype.A},
|
||||
{"kops-controller.internal.cluster1.example.com", rrstype.A},
|
||||
},
|
||||
},
|
||||
{
|
||||
cluster: &kops.Cluster{
|
||||
Spec: kops.ClusterSpec{
|
||||
CloudProvider: "aws",
|
||||
KubernetesVersion: "1.22.0",
|
||||
NonMasqueradeCIDR: "::/0",
|
||||
},
|
||||
},
|
||||
expected: []recordKey{
|
||||
{"api.cluster1.example.com", rrstype.A},
|
||||
{"api.cluster1.example.com", rrstype.AAAA},
|
||||
{"api.internal.cluster1.example.com", rrstype.AAAA},
|
||||
{"kops-controller.internal.cluster1.example.com", rrstype.AAAA},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -91,8 +145,15 @@ func TestPrecreateDNSNames(t *testing.T) {
|
|||
actual := buildPrecreateDNSHostnames(cluster)
|
||||
|
||||
expected := g.expected
|
||||
sort.Strings(actual)
|
||||
sort.Strings(expected)
|
||||
sort.Slice(actual, func(i, j int) bool {
|
||||
if actual[i].hostname < actual[j].hostname {
|
||||
return true
|
||||
}
|
||||
if actual[i].hostname == actual[j].hostname && actual[i].rrsType < actual[j].rrsType {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected records. expected=%v actual=%v", expected, actual)
|
||||
|
|
|
@ -167,7 +167,7 @@ func (b *KopsBootstrapClient) QueryBootstrap(ctx context.Context, req *nodeup.Bo
|
|||
return nil, fi.NewTryAgainLaterError(fmt.Sprintf("kops-controller DNS not setup yet (not found: %v)", dnsErr))
|
||||
}
|
||||
return nil, err
|
||||
} else if len(ips) == 1 && ips[0].String() == cloudup.PlaceholderIP {
|
||||
} else if len(ips) == 1 && (ips[0].String() == cloudup.PlaceholderIP || ips[0].String() == cloudup.PlaceholderIPv6) {
|
||||
return nil, fi.NewTryAgainLaterError(fmt.Sprintf("kops-controller DNS not setup yet (placeholder IP found: %v)", ips))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue