Skip to content

Commit

Permalink
used API to generate EPs and remove OCM
Browse files Browse the repository at this point in the history
Signed-off-by: Maskym Vavilov <mvavilov@redhat.com>
  • Loading branch information
maksymvavilov committed Aug 26, 2024
1 parent 1c8ddab commit c87d0b7
Show file tree
Hide file tree
Showing 13 changed files with 281 additions and 1,791 deletions.
16 changes: 8 additions & 8 deletions api/v1alpha1/dnspolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ var (
}
)

type RoutingStrategy string
//type RoutingStrategy string

const (
SimpleRoutingStrategy RoutingStrategy = "simple"
LoadBalancedRoutingStrategy RoutingStrategy = "loadbalanced"
//SimpleRoutingStrategy RoutingStrategy = "simple"
//LoadBalancedRoutingStrategy RoutingStrategy = "loadbalanced"

DefaultWeight Weight = 120
DefaultGeo GeoCode = "default"
Expand All @@ -70,10 +70,10 @@ type DNSPolicySpec struct {
// +optional
LoadBalancing *LoadBalancingSpec `json:"loadBalancing,omitempty"`

// +kubebuilder:validation:Enum=simple;loadbalanced
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="RoutingStrategy is immutable"
// +kubebuilder:default=loadbalanced
RoutingStrategy RoutingStrategy `json:"routingStrategy"`
//// +kubebuilder:validation:Enum=simple;loadbalanced
//// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="RoutingStrategy is immutable"
//// +kubebuilder:default=loadbalanced
RoutingStrategy dnsv1alpha1.RoutingStrategy `json:"routingStrategy"`

// providerRefs is a list of references to provider secrets. Max is one but intention is to allow this to be more in the future
// +kubebuilder:validation:MaxItems=1
Expand Down Expand Up @@ -265,7 +265,7 @@ func (p *DNSPolicy) WithLoadBalancing(loadBalancing LoadBalancingSpec) *DNSPolic
return p
}

func (p *DNSPolicy) WithRoutingStrategy(strategy RoutingStrategy) *DNSPolicy {
func (p *DNSPolicy) WithRoutingStrategy(strategy dnsv1alpha1.RoutingStrategy) *DNSPolicy {

Check warning on line 268 in api/v1alpha1/dnspolicy_types.go

View check run for this annotation

Codecov / codecov/patch

api/v1alpha1/dnspolicy_types.go#L268

Added line #L268 was not covered by tests
p.Spec.RoutingStrategy = strategy
return p
}
Expand Down
5 changes: 4 additions & 1 deletion bundle/manifests/kuadrant.io_dnspolicies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,10 @@ spec:
minItems: 1
type: array
routingStrategy:
default: loadbalanced
description: |-
// +kubebuilder:validation:Enum=simple;loadbalanced
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="RoutingStrategy is immutable"
// +kubebuilder:default=loadbalanced
enum:
- simple
- loadbalanced
Expand Down
5 changes: 4 additions & 1 deletion config/crd/bases/kuadrant.io_dnspolicies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,10 @@ spec:
minItems: 1
type: array
routingStrategy:
default: loadbalanced
description: |-
// +kubebuilder:validation:Enum=simple;loadbalanced
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="RoutingStrategy is immutable"
// +kubebuilder:default=loadbalanced
enum:
- simple
- loadbalanced
Expand Down
199 changes: 1 addition & 198 deletions controllers/dns_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,24 @@ package controllers
import (
"context"
"fmt"
"sort"
"strconv"
"strings"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
externaldns "sigs.k8s.io/external-dns/endpoint"
gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"

kuadrantdnsv1alpha1 "github.com/kuadrant/dns-operator/api/v1alpha1"

"github.com/kuadrant/kuadrant-operator/api/v1alpha1"
"github.com/kuadrant/kuadrant-operator/pkg/multicluster"
)

const (
LabelGatewayReference = "kuadrant.io/gateway"
LabelGatewayNSRef = "kuadrant.io/gateway-namespace"
LabelListenerReference = "kuadrant.io/listener-name"

DefaultTTL = 60
DefaultCnameTTL = 300
)

var (
ErrUnknownRoutingStrategy = fmt.Errorf("unknown routing strategy")
// ErrUnknownRoutingStrategy = fmt.Errorf("unknown routing strategy")
)

type dnsHelper struct {
Expand Down Expand Up @@ -60,187 +52,6 @@ func gatewayDNSRecordLabels(gwKey client.ObjectKey) map[string]string {
}
}

func (dh *dnsHelper) setEndpoints(mcgTarget *multicluster.GatewayTarget, dnsRecord *kuadrantdnsv1alpha1.DNSRecord, listener gatewayapiv1.Listener, strategy v1alpha1.RoutingStrategy) error {
gwListenerHost := string(*listener.Hostname)
var endpoints []*externaldns.Endpoint

//Health Checks currently modify endpoints, so we have to keep existing ones in order to not lose health check ids
currentEndpoints := make(map[string]*externaldns.Endpoint, len(dnsRecord.Spec.Endpoints))
for _, endpoint := range dnsRecord.Spec.Endpoints {
currentEndpoints[getSetID(endpoint)] = endpoint
}

switch strategy {
case v1alpha1.SimpleRoutingStrategy:
endpoints = dh.getSimpleEndpoints(mcgTarget, gwListenerHost, currentEndpoints)
case v1alpha1.LoadBalancedRoutingStrategy:
endpoints = dh.getLoadBalancedEndpoints(mcgTarget, gwListenerHost, currentEndpoints)
default:
return fmt.Errorf("%w : %s", ErrUnknownRoutingStrategy, strategy)
}

sort.Slice(endpoints, func(i, j int) bool {
return getSetID(endpoints[i]) < getSetID(endpoints[j])
})

dnsRecord.Spec.Endpoints = endpoints

return nil
}

// getSimpleEndpoints returns the endpoints for the given GatewayTarget using the simple routing strategy

func (dh *dnsHelper) getSimpleEndpoints(mcgTarget *multicluster.GatewayTarget, hostname string, currentEndpoints map[string]*externaldns.Endpoint) []*externaldns.Endpoint {
var (
endpoints []*externaldns.Endpoint
ipValues []string
hostValues []string
)

for _, cgwTarget := range mcgTarget.ClusterGatewayTargets {
for _, gwa := range cgwTarget.Status.Addresses {
if *gwa.Type == gatewayapiv1.IPAddressType {
ipValues = append(ipValues, gwa.Value)
} else {
hostValues = append(hostValues, gwa.Value)
}
}
}

if len(ipValues) > 0 {
endpoint := createOrUpdateEndpoint(hostname, ipValues, kuadrantdnsv1alpha1.ARecordType, "", DefaultTTL, currentEndpoints)
endpoints = append(endpoints, endpoint)
}

//ToDO This could possibly result in an invalid record since you can't have multiple CNAME target values https://github.com/kuadrant/kuadrant-operator/issues/663
if len(hostValues) > 0 {
endpoint := createOrUpdateEndpoint(hostname, hostValues, kuadrantdnsv1alpha1.CNAMERecordType, "", DefaultTTL, currentEndpoints)
endpoints = append(endpoints, endpoint)
}

return endpoints
}

// getLoadBalancedEndpoints returns the endpoints for the given GatewayTarget using the loadbalanced routing strategy
//
// Builds an array of externaldns.Endpoint resources and sets them on the given DNSRecord. The endpoints expected are calculated
// from the GatewayTarget using the target Gateway (GatewayTarget.Gateway), the LoadBalancing Spec
// from the DNSPolicy attached to the target gateway (GatewayTarget.LoadBalancing) and the list of clusters the
// target gateway is currently placed on (GatewayTarget.ClusterGatewayTargets).
//
// GatewayTarget.ClusterGatewayTarget are grouped by Geo, in the case of Geo not being defined in the
// LoadBalancing Spec (Weighted only) an internal only Geo Code of "default" is used and all clusters added to it.
//
// A CNAME record is created for the target host (DNSRecord.name), pointing to a generated gateway lb host.
// A CNAME record for the gateway lb host is created for every Geo, with appropriate Geo information, pointing to a geo
// specific host.
// A CNAME record for the geo specific host is created for every Geo, with weight information for that target added,
// pointing to a target cluster hostname.
// An A record for the target cluster hostname is created for any IP targets retrieved for that cluster.
//
// Example(Weighted only)
//
// www.example.com CNAME lb-1ab1.www.example.com
// lb-1ab1.www.example.com CNAME geolocation * default.lb-1ab1.www.example.com
// default.lb-1ab1.www.example.com CNAME weighted 100 1bc1.lb-1ab1.www.example.com
// default.lb-1ab1.www.example.com CNAME weighted 100 aws.lb.com
// 1bc1.lb-1ab1.www.example.com A 192.22.2.1
//
// Example(Geo, default IE)
//
// shop.example.com CNAME lb-a1b2.shop.example.com
// lb-a1b2.shop.example.com CNAME geolocation ireland ie.lb-a1b2.shop.example.com
// lb-a1b2.shop.example.com geolocation australia aus.lb-a1b2.shop.example.com
// lb-a1b2.shop.example.com geolocation default ie.lb-a1b2.shop.example.com (set by the default geo option)
// ie.lb-a1b2.shop.example.com CNAME weighted 100 ab1.lb-a1b2.shop.example.com
// ie.lb-a1b2.shop.example.com CNAME weighted 100 aws.lb.com
// aus.lb-a1b2.shop.example.com CNAME weighted 100 ab2.lb-a1b2.shop.example.com
// aus.lb-a1b2.shop.example.com CNAME weighted 100 ab3.lb-a1b2.shop.example.com
// ab1.lb-a1b2.shop.example.com A 192.22.2.1 192.22.2.5
// ab2.lb-a1b2.shop.example.com A 192.22.2.3
// ab3.lb-a1b2.shop.example.com A 192.22.2.4

func (dh *dnsHelper) getLoadBalancedEndpoints(mcgTarget *multicluster.GatewayTarget, hostname string, currentEndpoints map[string]*externaldns.Endpoint) []*externaldns.Endpoint {
cnameHost := hostname
if isWildCardHost(hostname) {
cnameHost = strings.Replace(hostname, "*.", "", -1)
}

var endpoint *externaldns.Endpoint
endpoints := make([]*externaldns.Endpoint, 0)
lbName := strings.ToLower(fmt.Sprintf("klb.%s", cnameHost))

for geoCode, cgwTargets := range mcgTarget.GroupTargetsByGeo() {
geoLbName := strings.ToLower(fmt.Sprintf("%s.%s", geoCode, lbName))
var clusterEndpoints []*externaldns.Endpoint
for _, cgwTarget := range cgwTargets {
var ipValues []string
var hostValues []string
for _, gwa := range cgwTarget.Status.Addresses {
if *gwa.Type == gatewayapiv1.IPAddressType {
ipValues = append(ipValues, gwa.Value)
} else {
hostValues = append(hostValues, gwa.Value)
}
}

if len(ipValues) > 0 {
clusterLbName := strings.ToLower(fmt.Sprintf("%s-%s.%s", cgwTarget.GetShortCode(), mcgTarget.GetShortCode(), lbName))
endpoint = createOrUpdateEndpoint(clusterLbName, ipValues, kuadrantdnsv1alpha1.ARecordType, "", DefaultTTL, currentEndpoints)
clusterEndpoints = append(clusterEndpoints, endpoint)
hostValues = append(hostValues, clusterLbName)
}

for _, hostValue := range hostValues {
endpoint = createOrUpdateEndpoint(geoLbName, []string{hostValue}, kuadrantdnsv1alpha1.CNAMERecordType, hostValue, DefaultTTL, currentEndpoints)
endpoint.SetProviderSpecificProperty(kuadrantdnsv1alpha1.ProviderSpecificWeight, strconv.Itoa(cgwTarget.GetWeight()))
clusterEndpoints = append(clusterEndpoints, endpoint)
}
}
if len(clusterEndpoints) == 0 {
continue
}
endpoints = append(endpoints, clusterEndpoints...)

//Create lbName CNAME (lb-a1b2.shop.example.com -> <geoCode>.lb-a1b2.shop.example.com)
endpoint = createOrUpdateEndpoint(lbName, []string{geoLbName}, kuadrantdnsv1alpha1.CNAMERecordType, string(geoCode), DefaultCnameTTL, currentEndpoints)
endpoint.SetProviderSpecificProperty(kuadrantdnsv1alpha1.ProviderSpecificGeoCode, string(geoCode))
endpoints = append(endpoints, endpoint)

//Add a default geo (*) endpoint if the current geoCode is equal to the defaultGeo set in the policy spec
if geoCode == mcgTarget.GetDefaultGeo() {
endpoint = createOrUpdateEndpoint(lbName, []string{geoLbName}, kuadrantdnsv1alpha1.CNAMERecordType, "default", DefaultCnameTTL, currentEndpoints)
endpoint.SetProviderSpecificProperty(kuadrantdnsv1alpha1.ProviderSpecificGeoCode, string(v1alpha1.WildcardGeo))
endpoints = append(endpoints, endpoint)
}
}

if len(endpoints) > 0 {
//Create gwListenerHost CNAME (shop.example.com -> lb-a1b2.shop.example.com)
endpoint = createOrUpdateEndpoint(hostname, []string{lbName}, kuadrantdnsv1alpha1.CNAMERecordType, "", DefaultCnameTTL, currentEndpoints)
endpoints = append(endpoints, endpoint)
}

return endpoints
}

func createOrUpdateEndpoint(dnsName string, targets externaldns.Targets, recordType kuadrantdnsv1alpha1.DNSRecordType, setIdentifier string,
recordTTL externaldns.TTL, currentEndpoints map[string]*externaldns.Endpoint) (endpoint *externaldns.Endpoint) {
ok := false
endpointID := dnsName + setIdentifier
if endpoint, ok = currentEndpoints[endpointID]; !ok {
endpoint = &externaldns.Endpoint{}
if setIdentifier != "" {
endpoint.SetIdentifier = setIdentifier
}
}
endpoint.DNSName = dnsName
endpoint.RecordType = string(recordType)
endpoint.Targets = targets
endpoint.RecordTTL = recordTTL
return endpoint
}

// removeDNSForDeletedListeners remove any DNSRecords that are associated with listeners that no longer exist in this gateway
func (dh *dnsHelper) removeDNSForDeletedListeners(ctx context.Context, upstreamGateway *gatewayapiv1.Gateway) error {
dnsList := &kuadrantdnsv1alpha1.DNSRecordList{}
Expand Down Expand Up @@ -283,11 +94,3 @@ func (dh *dnsHelper) deleteDNSRecordForListener(ctx context.Context, owner metav
}
return dh.Delete(ctx, &dnsRecord, &client.DeleteOptions{})
}

func isWildCardHost(host string) bool {
return strings.HasPrefix(host, "*")
}

func getSetID(endpoint *externaldns.Endpoint) string {
return endpoint.DNSName + endpoint.SetIdentifier
}
Loading

0 comments on commit c87d0b7

Please sign in to comment.