add dualstack support for AWS provider with ALB ingress controllers

This commit is contained in:
twilfong 2019-06-26 18:05:22 -07:00
parent 58c9b2e321
commit d68d06f17c
3 changed files with 49 additions and 16 deletions

View File

@ -38,6 +38,9 @@ const (
// AWSSDDescriptionLabel label responsible for storing raw owner/resource combination information in the Labels
// supposed to be inserted by AWS SD Provider, and parsed into OwnerLabelKey and ResourceLabelKey key by AWS SD Registry
AWSSDDescriptionLabel = "aws-sd-description"
// DualstackLabelKey is the name of the label that identifies dualstack endpoints
DualstackLabelKey = "dualstack"
)
// Labels store metadata related to the endpoint

View File

@ -407,60 +407,74 @@ func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint,
changes := make([]*route53.Change, 0, len(endpoints))
for _, endpoint := range endpoints {
changes = append(changes, p.newChange(action, endpoint, recordsCache, zones))
change, dualstack := p.newChange(action, endpoint, recordsCache, zones)
changes = append(changes, change)
if dualstack {
// make a copy of change, modify RRS type to AAAA, then add new change
rrs := *change.ResourceRecordSet
change2 := &route53.Change{Action: change.Action, ResourceRecordSet: &rrs}
change2.ResourceRecordSet.Type = aws.String(route53.RRTypeAaaa)
changes = append(changes, change2)
}
}
return changes
}
// newChange returns a Change of the given record by the given action, e.g.
// newChange returns a route53 Change and a boolean indicating if there should also be a change to a AAAA record
// returned Change is based on the given record by the given action, e.g.
// action=ChangeActionCreate returns a change for creation of the record and
// action=ChangeActionDelete returns a change for deletion of the record.
func (p *AWSProvider) newChange(action string, endpoint *endpoint.Endpoint, recordsCache []*endpoint.Endpoint, zones map[string]*route53.HostedZone) *route53.Change {
func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint, recordsCache []*endpoint.Endpoint, zones map[string]*route53.HostedZone) (*route53.Change, bool) {
change := &route53.Change{
Action: aws.String(action),
ResourceRecordSet: &route53.ResourceRecordSet{
Name: aws.String(endpoint.DNSName),
Name: aws.String(ep.DNSName),
},
}
dualstack := false
if isAWSLoadBalancer(endpoint) {
if isAWSLoadBalancer(ep) {
evalTargetHealth := p.evaluateTargetHealth
if prop, ok := endpoint.GetProviderSpecificProperty(providerSpecificEvaluateTargetHealth); ok {
if prop, ok := ep.GetProviderSpecificProperty(providerSpecificEvaluateTargetHealth); ok {
evalTargetHealth = prop.Value == "true"
}
// If the endpoint has a Dualstack label, append a change for AAAA record as well.
if val, ok := ep.Labels[endpoint.DualstackLabelKey]; ok {
dualstack = val == "true"
}
change.ResourceRecordSet.Type = aws.String(route53.RRTypeA)
change.ResourceRecordSet.AliasTarget = &route53.AliasTarget{
DNSName: aws.String(endpoint.Targets[0]),
HostedZoneId: aws.String(canonicalHostedZone(endpoint.Targets[0])),
DNSName: aws.String(ep.Targets[0]),
HostedZoneId: aws.String(canonicalHostedZone(ep.Targets[0])),
EvaluateTargetHealth: aws.Bool(evalTargetHealth),
}
} else if hostedZone := isAWSAlias(endpoint, recordsCache); hostedZone != "" {
} else if hostedZone := isAWSAlias(ep, recordsCache); hostedZone != "" {
for _, zone := range zones {
change.ResourceRecordSet.Type = aws.String(route53.RRTypeA)
change.ResourceRecordSet.AliasTarget = &route53.AliasTarget{
DNSName: aws.String(endpoint.Targets[0]),
DNSName: aws.String(ep.Targets[0]),
HostedZoneId: aws.String(cleanZoneID(*zone.Id)),
EvaluateTargetHealth: aws.Bool(p.evaluateTargetHealth),
}
}
} else {
change.ResourceRecordSet.Type = aws.String(endpoint.RecordType)
if !endpoint.RecordTTL.IsConfigured() {
change.ResourceRecordSet.Type = aws.String(ep.RecordType)
if !ep.RecordTTL.IsConfigured() {
change.ResourceRecordSet.TTL = aws.Int64(recordTTL)
} else {
change.ResourceRecordSet.TTL = aws.Int64(int64(endpoint.RecordTTL))
change.ResourceRecordSet.TTL = aws.Int64(int64(ep.RecordTTL))
}
change.ResourceRecordSet.ResourceRecords = make([]*route53.ResourceRecord, len(endpoint.Targets))
for idx, val := range endpoint.Targets {
change.ResourceRecordSet.ResourceRecords = make([]*route53.ResourceRecord, len(ep.Targets))
for idx, val := range ep.Targets {
change.ResourceRecordSet.ResourceRecords[idx] = &route53.ResourceRecord{
Value: aws.String(val),
}
}
}
return change
return change, dualstack
}
func (p *AWSProvider) tagsForZone(zoneID string) (map[string]string, error) {

View File

@ -37,6 +37,13 @@ import (
"k8s.io/client-go/tools/cache"
)
const (
// The annotation used for determining if an ALB ingress is dualstack
ALBDualstackAnnotationKey = "alb.ingress.kubernetes.io/ip-address-type"
// The value of the ALB dualstack annotation that indicates it is dualstack
ALBDualstackAnnotationValue = "dualstack"
)
// ingressSource is an implementation of Source for Kubernetes ingress objects.
// Ingress implementation will use the spec.rules.host value for the hostname
// Use targetAnnotationKey to explicitly set Endpoint. (useful if the ingress
@ -148,6 +155,7 @@ func (sc *ingressSource) Endpoints() ([]*endpoint.Endpoint, error) {
log.Debugf("Endpoints generated from ingress: %s/%s: %v", ing.Namespace, ing.Name, ingEndpoints)
sc.setResourceLabel(ing, ingEndpoints)
sc.setDualstackLabel(ing, ingEndpoints)
endpoints = append(endpoints, ingEndpoints...)
}
@ -228,6 +236,14 @@ func (sc *ingressSource) setResourceLabel(ingress *v1beta1.Ingress, endpoints []
}
}
func (sc *ingressSource) setDualstackLabel(ingress *v1beta1.Ingress, endpoints []*endpoint.Endpoint) {
val, ok := ingress.Annotations[ALBDualstackAnnotationKey]
if ok && val == ALBDualstackAnnotationValue {
log.Debugf("Adding dualstack label to ingress %s/%s.", ingress.Namespace, ingress.Name)
for _, ep := range endpoints { ep.Labels[endpoint.DualstackLabelKey] = "true" }
}
}
// endpointsFromIngress extracts the endpoints from ingress object
func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool) []*endpoint.Endpoint {
var endpoints []*endpoint.Endpoint