From 655742efb573d59e405606809787e4199a764b97 Mon Sep 17 00:00:00 2001 From: Michael Nairn Date: Sun, 28 Jan 2024 12:40:07 +0000 Subject: [PATCH] DNS refactor Number of changes required(mostly) to isolate the dns code from the policy and gateway logic in preparation for moving it to it's own repo. Provider health checks were removed from the aws dns provider implementation. These have been replaced by provder agnostic health checks and are no longer a supported solution. DNS provider implementations are moved into a provider package (dns/provider) along with all other dns provider related interfaces and types. Matches external-dns layout and naming and how we want future providers to be added. Updates the dns provider factory to have each provider register its constructor with the factory on init. Adds fake provider and factory for testing and updates field names in reconcilers to better represent what the Factory resource is (DNSProvider -> ProviderFactory). Factory method (ProviderFor) now expects a resource implementing the ProviderAccessor interface. Move common dns consts and types into api (DefaultWeight, DefaultGeo, WildcardGeo, GeoCode ), remove redundant code from DNSRecord and make receiver name consistent. Added common pkg for consistency with kuadrant-operator and moved target and gateway wrapper resources into here. --- cmd/policy_controller/main.go | 21 +- go.mod | 1 - go.sum | 2 - pkg/_internal/gracePeriod/gracePeriod.go | 4 +- pkg/_internal/policy/policy.go | 21 - pkg/_internal/policy/policy_test.go | 77 ---- pkg/apis/v1alpha1/dnspolicy_types.go | 16 +- pkg/apis/v1alpha1/dnsrecord_types.go | 109 ++--- pkg/apis/v1alpha1/managedzone_types.go | 11 +- pkg/apis/v1alpha1/shared_types.go | 28 ++ pkg/apis/v1alpha1/zz_generated.deepcopy.go | 51 +-- pkg/{utils => common}/gateway_wrapper.go | 2 +- pkg/{utils => common}/gateway_wrapper_test.go | 2 +- pkg/{dns => common}/target.go | 48 +-- pkg/{dns => common}/target_test.go | 79 ++-- pkg/controllers/dnspolicy/dns_helper.go | 45 ++- pkg/controllers/dnspolicy/dns_helper_test.go | 113 +++--- .../dnspolicy/dnspolicy_controller.go | 6 +- .../dnspolicy/dnspolicy_dnsrecords.go | 9 +- .../dnspolicy/dnspolicy_healthchecks.go | 8 +- .../dnspolicy/dnspolicy_healthchecks_test.go | 44 +- .../dnsrecord/dnsrecord_controller.go | 12 +- pkg/controllers/gateway/gateway_controller.go | 4 +- .../managedzone/managedzone_controller.go | 10 +- pkg/dns/aws/health.go | 258 ------------ pkg/dns/aws/health_test.go | 378 ------------------ pkg/dns/dns.go | 98 ----- pkg/dns/dnsprovider/dnsProvider.go | 65 --- pkg/dns/health.go | 121 ------ pkg/dns/{aws/dns.go => provider/aws/aws.go} | 46 +-- pkg/dns/{ => provider}/aws/aws_test.go | 0 pkg/dns/{ => provider}/aws/client.go | 24 -- pkg/dns/{ => provider}/aws/metrics.go | 0 pkg/dns/provider/factory.go | 85 ++++ pkg/dns/provider/fake/factory.go | 18 + pkg/dns/provider/fake/provider.go | 31 ++ pkg/dns/{ => provider}/google/google.go | 48 +-- pkg/dns/{ => provider}/google/google_test.go | 8 +- pkg/dns/{ => provider}/iso3166.go | 2 +- pkg/dns/provider/provider.go | 47 +++ .../provider_test.go} | 2 +- test/gateway_integration/suite_test.go | 16 +- ...dnspolicy_controller_health_checks_test.go | 9 +- ...dnspolicy_controller_multi_cluster_test.go | 9 +- ...nspolicy_controller_single_cluster_test.go | 4 +- .../dnspolicy_controller_test.go | 8 +- .../managedzone_controller_test.go | 2 +- test/policy_integration/suite_test.go | 42 +- test/util/test_dnspolicy_types.go | 2 +- 49 files changed, 562 insertions(+), 1484 deletions(-) delete mode 100644 pkg/_internal/policy/policy.go delete mode 100644 pkg/_internal/policy/policy_test.go create mode 100644 pkg/apis/v1alpha1/shared_types.go rename pkg/{utils => common}/gateway_wrapper.go (99%) rename pkg/{utils => common}/gateway_wrapper_test.go (99%) rename pkg/{dns => common}/target.go (81%) rename pkg/{dns => common}/target_test.go (93%) delete mode 100644 pkg/dns/aws/health.go delete mode 100644 pkg/dns/aws/health_test.go delete mode 100644 pkg/dns/dns.go delete mode 100644 pkg/dns/dnsprovider/dnsProvider.go delete mode 100644 pkg/dns/health.go rename pkg/dns/{aws/dns.go => provider/aws/aws.go} (90%) rename pkg/dns/{ => provider}/aws/aws_test.go (100%) rename pkg/dns/{ => provider}/aws/client.go (78%) rename pkg/dns/{ => provider}/aws/metrics.go (100%) create mode 100644 pkg/dns/provider/factory.go create mode 100644 pkg/dns/provider/fake/factory.go create mode 100644 pkg/dns/provider/fake/provider.go rename pkg/dns/{ => provider}/google/google.go (92%) rename pkg/dns/{ => provider}/google/google_test.go (98%) rename pkg/dns/{ => provider}/iso3166.go (99%) create mode 100644 pkg/dns/provider/provider.go rename pkg/dns/{dns_test.go => provider/provider_test.go} (97%) diff --git a/cmd/policy_controller/main.go b/cmd/policy_controller/main.go index 2cc81ce0f..8bc64bf22 100644 --- a/cmd/policy_controller/main.go +++ b/cmd/policy_controller/main.go @@ -43,7 +43,9 @@ import ( "github.com/Kuadrant/multicluster-gateway-controller/pkg/controllers/dnsrecord" "github.com/Kuadrant/multicluster-gateway-controller/pkg/controllers/managedzone" "github.com/Kuadrant/multicluster-gateway-controller/pkg/controllers/tlspolicy" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/dnsprovider" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" + _ "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider/aws" + _ "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider/google" "github.com/Kuadrant/multicluster-gateway-controller/pkg/health" ) @@ -90,7 +92,8 @@ func main() { setupLog.Error(err, "unable to start manager") os.Exit(1) } - provider := dnsprovider.NewProvider(mgr.GetClient()) + + dnsProviderFactory := provider.NewFactory(mgr.GetClient()) healthMonitor := health.NewMonitor() healthCheckQueue := health.NewRequestQueue(time.Second * 5) @@ -106,9 +109,9 @@ func main() { } if err = (&dnsrecord.DNSRecordReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - DNSProvider: provider.DNSProviderFactory, + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + ProviderFactory: dnsProviderFactory, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "DNSRecord") os.Exit(1) @@ -124,7 +127,7 @@ func main() { TargetRefReconciler: reconcilers.TargetRefReconciler{ BaseReconciler: dnsPolicyBaseReconciler, }, - DNSProvider: provider.DNSProviderFactory, + ProviderFactory: dnsProviderFactory, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "DNSPolicy") os.Exit(1) @@ -157,9 +160,9 @@ func main() { //+kubebuilder:scaffold:builder if err = (&managedzone.ManagedZoneReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - DNSProvider: provider.DNSProviderFactory, + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + ProviderFactory: dnsProviderFactory, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "ManagedZone") os.Exit(1) diff --git a/go.mod b/go.mod index 17c3bf50a..9c284828c 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ require ( github.com/onsi/gomega v1.27.10 github.com/operator-framework/api v0.17.5 github.com/prometheus/client_golang v1.17.0 - github.com/rs/xid v1.4.0 golang.org/x/net v0.17.0 google.golang.org/api v0.126.0 k8s.io/api v0.28.3 diff --git a/go.sum b/go.sum index 9d5c01985..217a4d958 100644 --- a/go.sum +++ b/go.sum @@ -203,8 +203,6 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= -github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= diff --git a/pkg/_internal/gracePeriod/gracePeriod.go b/pkg/_internal/gracePeriod/gracePeriod.go index 4ca186fbd..fd6ab8648 100644 --- a/pkg/_internal/gracePeriod/gracePeriod.go +++ b/pkg/_internal/gracePeriod/gracePeriod.go @@ -10,12 +10,12 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/metadata" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" ) const ( GraceTimestampAnnotation = "kuadrant.io/grace-timeout" - DefaultGracePeriod = time.Second * dns.DefaultTTL * 10 + DefaultTTL = 60 //The TTL value here needs to match the one used by the DNSPolicy. This value however will no longer be available to gateway controller packages directly. + DefaultGracePeriod = time.Second * DefaultTTL * 10 ) var ErrGracePeriodNotExpired = fmt.Errorf("grace period has not yet expired") diff --git a/pkg/_internal/policy/policy.go b/pkg/_internal/policy/policy.go deleted file mode 100644 index acba12d15..000000000 --- a/pkg/_internal/policy/policy.go +++ /dev/null @@ -1,21 +0,0 @@ -package policy - -import ( - gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" - - "github.com/kuadrant/kuadrant-operator/pkg/common" -) - -const ( - TARGET_REF_KEY = "policyTargetRef" -) - -func GetTargetRefValueFromPolicy(policy common.KuadrantPolicy) string { - targetRef := policy.GetTargetRef() - ns := targetRef.Namespace - if ns == nil { - policyTypedNamespace := gatewayapiv1.Namespace(policy.GetNamespace()) - ns = &policyTypedNamespace - } - return string(targetRef.Name) + "," + string(*ns) -} diff --git a/pkg/_internal/policy/policy_test.go b/pkg/_internal/policy/policy_test.go deleted file mode 100644 index 4bb8dec04..000000000 --- a/pkg/_internal/policy/policy_test.go +++ /dev/null @@ -1,77 +0,0 @@ -//go:build unit - -package policy - -import ( - "testing" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" - gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - - "github.com/kuadrant/kuadrant-operator/pkg/common" - - "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - testutil "github.com/Kuadrant/multicluster-gateway-controller/test/util" -) - -func TestGetTargetRefValueFromPolicy(t *testing.T) { - type args struct { - policy common.KuadrantPolicy - } - testCases := []struct { - name string - args args - want string - }{ - { - name: "should use target namespace", - args: args{ - policy: &v1alpha1.DNSPolicy{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-policy", - Namespace: "test-policy-ns", - }, - Spec: v1alpha1.DNSPolicySpec{ - TargetRef: gatewayapiv1alpha2.PolicyTargetReference{ - Group: "gateway.networking.k8s.io", - Kind: "Gateway", - Name: "test-gateway", - }, - }, - }, - }, - want: "test-gateway,test-policy-ns", - }, - { - name: "should use policy namespace when no target namespace set", - args: args{ - policy: &v1alpha1.DNSPolicy{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-policy", - Namespace: "test-policy-ns", - }, - Spec: v1alpha1.DNSPolicySpec{ - TargetRef: gatewayapiv1alpha2.PolicyTargetReference{ - Group: "gateway.networking.k8s.io", - Kind: "Gateway", - Name: "test-gateway", - Namespace: (*gatewayapiv1.Namespace)(testutil.Pointer("test-gateway-ns")), - }, - }, - }, - }, - want: "test-gateway,test-gateway-ns", - }, - } - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - expected := GetTargetRefValueFromPolicy(testCase.args.policy) - if testCase.want != expected { - t.Errorf("GetTargetRefValueFromPolicy returned %v; expected %v", testCase.want, expected) - } - }) - } -} diff --git a/pkg/apis/v1alpha1/dnspolicy_types.go b/pkg/apis/v1alpha1/dnspolicy_types.go index 60ff89103..b0a4b2db7 100644 --- a/pkg/apis/v1alpha1/dnspolicy_types.go +++ b/pkg/apis/v1alpha1/dnspolicy_types.go @@ -30,6 +30,10 @@ type RoutingStrategy string const ( SimpleRoutingStrategy RoutingStrategy = "simple" LoadBalancedRoutingStrategy RoutingStrategy = "loadbalanced" + + DefaultWeight Weight = 120 + DefaultGeo GeoCode = "default" + WildcardGeo GeoCode = "*" ) // DNSPolicySpec defines the desired state of DNSPolicy @@ -81,6 +85,16 @@ type LoadBalancingWeighted struct { Custom []*CustomWeight `json:"custom,omitempty"` } +type GeoCode string + +func (gc GeoCode) IsDefaultCode() bool { + return gc == DefaultGeo +} + +func (gc GeoCode) IsWildcard() bool { + return gc == WildcardGeo +} + type LoadBalancingGeo struct { // defaultGeo is the country/continent/region code to use when no other can be determined for a dns target cluster. // @@ -228,5 +242,3 @@ type DNSRecordRef struct { func init() { SchemeBuilder.Register(&DNSPolicy{}, &DNSPolicyList{}) } - -const DefaultWeight Weight = 120 diff --git a/pkg/apis/v1alpha1/dnsrecord_types.go b/pkg/apis/v1alpha1/dnsrecord_types.go index 3b8fe43f2..58edee4c0 100644 --- a/pkg/apis/v1alpha1/dnsrecord_types.go +++ b/pkg/apis/v1alpha1/dnsrecord_types.go @@ -22,11 +22,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// SetID returns an id that should be unique across a set of endpoints -func (e *Endpoint) SetID() string { - return e.DNSName + e.SetIdentifier -} - // ProviderSpecificProperty holds the name and value of a configuration which is specific to individual DNS providers type ProviderSpecificProperty struct { Name string `json:"name,omitempty"` @@ -66,26 +61,17 @@ type Endpoint struct { ProviderSpecific ProviderSpecific `json:"providerSpecific,omitempty"` } +// SetID returns an id that should be unique across a set of endpoints +func (e *Endpoint) SetID() string { + return e.DNSName + e.SetIdentifier +} + // WithSetIdentifier applies the given set identifier to the endpoint. func (e *Endpoint) WithSetIdentifier(setIdentifier string) *Endpoint { e.SetIdentifier = setIdentifier return e } -// WithProviderSpecific attaches a key/value pair to the Endpoint and returns the Endpoint. -// This can be used to pass additional data through the stages of ExternalDNS's Endpoint processing. -// The assumption is that most of the time this will be provider specific metadata that doesn't -// warrant its own field on the Endpoint object itself. It differs from Labels in the fact that it's -// not persisted in the Registry but only kept in memory during a single record synchronization. -func (e *Endpoint) WithProviderSpecific(key, value string) *Endpoint { - if e.ProviderSpecific == nil { - e.ProviderSpecific = ProviderSpecific{} - } - - e.ProviderSpecific = append(e.ProviderSpecific, ProviderSpecificProperty{Name: key, Value: value}) - return e -} - // GetProviderSpecificProperty returns a ProviderSpecificProperty if the property exists. func (e *Endpoint) GetProviderSpecificProperty(key string) (ProviderSpecificProperty, bool) { for _, providerSpecific := range e.ProviderSpecific { @@ -96,6 +82,25 @@ func (e *Endpoint) GetProviderSpecificProperty(key string) (ProviderSpecificProp return ProviderSpecificProperty{}, false } +// SetProviderSpecific sets a provider specific key/value pair. +func (e *Endpoint) SetProviderSpecific(name, value string) { + if e.ProviderSpecific == nil { + e.ProviderSpecific = ProviderSpecific{} + } + + for i, pair := range e.ProviderSpecific { + if pair.Name == name { + e.ProviderSpecific[i].Value = value + return + } + } + + e.ProviderSpecific = append(e.ProviderSpecific, ProviderSpecificProperty{ + Name: name, + Value: value, + }) +} + func (e *Endpoint) String() string { return fmt.Sprintf("%s %d IN %s %s %s %s", e.DNSName, e.RecordTTL, e.RecordType, e.SetIdentifier, e.Targets, e.ProviderSpecific) } @@ -175,72 +180,6 @@ const ( NSRecordType DNSRecordType = "NS" ) -const ( - TargetTypeHost = "HOST" - TargetTypeIP = "IP" -) - -type Target struct { - Cluster string - TargetType string - Value string -} - -func (endpoint *Endpoint) GetAddress() (string, bool) { - if endpoint.SetIdentifier == "" || len(endpoint.Targets) == 0 { - return "", false - } - - return string(endpoint.Targets[0]), true -} - -func (endpoint *Endpoint) SetProviderSpecific(name, value string) { - if endpoint.ProviderSpecific == nil { - endpoint.ProviderSpecific = ProviderSpecific{} - } - - for i, pair := range endpoint.ProviderSpecific { - if pair.Name == name { - endpoint.ProviderSpecific[i].Value = value - return - } - } - - endpoint.ProviderSpecific = append(endpoint.ProviderSpecific, ProviderSpecificProperty{ - Name: name, - Value: value, - }) -} - -func (endpoint *Endpoint) GetProviderSpecific(name string) (string, bool) { - for _, property := range endpoint.ProviderSpecific { - if property.Name == name { - return property.Value, true - } - } - - return "", false -} - -func (endpoint *Endpoint) DeleteProviderSpecific(name string) bool { - if endpoint.ProviderSpecific == nil { - return false - } - - deleted := false - providerSpecific := make(ProviderSpecific, 0, len(endpoint.ProviderSpecific)) - for _, pair := range endpoint.ProviderSpecific { - if pair.Name == name { - deleted = true - } else { - providerSpecific = append(providerSpecific, pair) - } - } - - endpoint.ProviderSpecific = providerSpecific - return deleted -} - func init() { SchemeBuilder.Register(&DNSRecord{}, &DNSRecordList{}) } diff --git a/pkg/apis/v1alpha1/managedzone_types.go b/pkg/apis/v1alpha1/managedzone_types.go index 8cbbede47..df5230f8d 100644 --- a/pkg/apis/v1alpha1/managedzone_types.go +++ b/pkg/apis/v1alpha1/managedzone_types.go @@ -41,12 +41,7 @@ type ManagedZoneSpec struct { // +optional ParentManagedZone *ManagedZoneReference `json:"parentManagedZone,omitempty"` // +required - SecretRef *SecretRef `json:"dnsProviderSecretRef"` -} - -type SecretRef struct { - //+required - Name string `json:"name"` + SecretRef ProviderRef `json:"dnsProviderSecretRef"` } // ManagedZoneStatus defines the observed state of a Zone @@ -89,6 +84,10 @@ type ManagedZone struct { Status ManagedZoneStatus `json:"status,omitempty"` } +func (mz *ManagedZone) GetProviderRef() ProviderRef { + return mz.Spec.SecretRef +} + //+kubebuilder:object:root=true // ManagedZoneList contains a list of ManagedZone diff --git a/pkg/apis/v1alpha1/shared_types.go b/pkg/apis/v1alpha1/shared_types.go new file mode 100644 index 000000000..f002a4e51 --- /dev/null +++ b/pkg/apis/v1alpha1/shared_types.go @@ -0,0 +1,28 @@ +/* +Copyright 2023 The MultiCluster Traffic Controller Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +type ProviderRef struct { + //+required + Name string `json:"name"` +} + +// +kubebuilder:object:generate=false +type ProviderAccessor interface { + GetNamespace() string + GetProviderRef() ProviderRef +} diff --git a/pkg/apis/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/v1alpha1/zz_generated.deepcopy.go index 2aae0a414..e5360962b 100644 --- a/pkg/apis/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/v1alpha1/zz_generated.deepcopy.go @@ -792,11 +792,7 @@ func (in *ManagedZoneSpec) DeepCopyInto(out *ManagedZoneSpec) { *out = new(ManagedZoneReference) **out = **in } - if in.SecretRef != nil { - in, out := &in.SecretRef, &out.SecretRef - *out = new(SecretRef) - **out = **in - } + out.SecretRef = in.SecretRef } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedZoneSpec. @@ -842,6 +838,21 @@ func (in *ManagedZoneStatus) DeepCopy() *ManagedZoneStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProviderRef) DeepCopyInto(out *ProviderRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderRef. +func (in *ProviderRef) DeepCopy() *ProviderRef { + if in == nil { + return nil + } + out := new(ProviderRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in ProviderSpecific) DeepCopyInto(out *ProviderSpecific) { { @@ -876,21 +887,6 @@ func (in *ProviderSpecificProperty) DeepCopy() *ProviderSpecificProperty { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretRef) DeepCopyInto(out *SecretRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretRef. -func (in *SecretRef) DeepCopy() *SecretRef { - if in == nil { - return nil - } - out := new(SecretRef) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TLSPolicy) DeepCopyInto(out *TLSPolicy) { *out = *in @@ -989,21 +985,6 @@ func (in *TLSPolicyStatus) DeepCopy() *TLSPolicyStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Target) DeepCopyInto(out *Target) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Target. -func (in *Target) DeepCopy() *Target { - if in == nil { - return nil - } - out := new(Target) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in Targets) DeepCopyInto(out *Targets) { { diff --git a/pkg/utils/gateway_wrapper.go b/pkg/common/gateway_wrapper.go similarity index 99% rename from pkg/utils/gateway_wrapper.go rename to pkg/common/gateway_wrapper.go index 3094050b3..d254c84bd 100644 --- a/pkg/utils/gateway_wrapper.go +++ b/pkg/common/gateway_wrapper.go @@ -1,4 +1,4 @@ -package utils +package common import ( "fmt" diff --git a/pkg/utils/gateway_wrapper_test.go b/pkg/common/gateway_wrapper_test.go similarity index 99% rename from pkg/utils/gateway_wrapper_test.go rename to pkg/common/gateway_wrapper_test.go index 77c6f2480..c36f0218c 100644 --- a/pkg/utils/gateway_wrapper_test.go +++ b/pkg/common/gateway_wrapper_test.go @@ -1,4 +1,4 @@ -package utils +package common import ( "reflect" diff --git a/pkg/dns/target.go b/pkg/common/target.go similarity index 81% rename from pkg/dns/target.go rename to pkg/common/target.go index f00e6dd80..d469dd5e4 100644 --- a/pkg/dns/target.go +++ b/pkg/common/target.go @@ -1,4 +1,4 @@ -package dns +package common import ( "crypto/sha256" @@ -12,14 +12,10 @@ import ( gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/utils" ) const ( - DefaultWeight = int(v1alpha1.DefaultWeight) - DefaultGeo GeoCode = "default" - WildcardGeo GeoCode = "*" - LabelLBAttributeGeoCode = "kuadrant.io/lb-attribute-geo-code" + LabelLBAttributeGeoCode = "kuadrant.io/lb-attribute-geo-code" ) // MultiClusterGatewayTarget represents a Gateway that is placed on multiple clusters (ClusterGateway). @@ -29,7 +25,7 @@ type MultiClusterGatewayTarget struct { LoadBalancing *v1alpha1.LoadBalancingSpec } -func NewMultiClusterGatewayTarget(gateway *gatewayapiv1.Gateway, clusterGateways []utils.ClusterGateway, loadBalancing *v1alpha1.LoadBalancingSpec) (*MultiClusterGatewayTarget, error) { +func NewMultiClusterGatewayTarget(gateway *gatewayapiv1.Gateway, clusterGateways []ClusterGateway, loadBalancing *v1alpha1.LoadBalancingSpec) (*MultiClusterGatewayTarget, error) { mcg := &MultiClusterGatewayTarget{Gateway: gateway, LoadBalancing: loadBalancing} err := mcg.setClusterGatewayTargets(clusterGateways) return mcg, err @@ -44,29 +40,29 @@ func (t *MultiClusterGatewayTarget) GetShortCode() string { } // GroupTargetsByGeo groups targets based on Geo Code. -func (t *MultiClusterGatewayTarget) GroupTargetsByGeo() map[GeoCode][]ClusterGatewayTarget { - geoTargets := make(map[GeoCode][]ClusterGatewayTarget) +func (t *MultiClusterGatewayTarget) GroupTargetsByGeo() map[v1alpha1.GeoCode][]ClusterGatewayTarget { + geoTargets := make(map[v1alpha1.GeoCode][]ClusterGatewayTarget) for _, target := range t.ClusterGatewayTargets { geoTargets[target.GetGeo()] = append(geoTargets[target.GetGeo()], target) } return geoTargets } -func (t *MultiClusterGatewayTarget) GetDefaultGeo() GeoCode { +func (t *MultiClusterGatewayTarget) GetDefaultGeo() v1alpha1.GeoCode { if t.LoadBalancing != nil && t.LoadBalancing.Geo != nil { - return GeoCode(t.LoadBalancing.Geo.DefaultGeo) + return v1alpha1.GeoCode(t.LoadBalancing.Geo.DefaultGeo) } - return DefaultGeo + return v1alpha1.DefaultGeo } func (t *MultiClusterGatewayTarget) GetDefaultWeight() int { if t.LoadBalancing != nil && t.LoadBalancing.Weighted != nil { return int(t.LoadBalancing.Weighted.DefaultWeight) } - return DefaultWeight + return int(v1alpha1.DefaultWeight) } -func (t *MultiClusterGatewayTarget) setClusterGatewayTargets(clusterGateways []utils.ClusterGateway) error { +func (t *MultiClusterGatewayTarget) setClusterGatewayTargets(clusterGateways []ClusterGateway) error { var cgTargets []ClusterGatewayTarget for _, cg := range clusterGateways { var customWeights []*v1alpha1.CustomWeight @@ -83,24 +79,14 @@ func (t *MultiClusterGatewayTarget) setClusterGatewayTargets(clusterGateways []u return nil } -type GeoCode string - -func (gc GeoCode) IsDefaultCode() bool { - return gc == DefaultGeo -} - -func (gc GeoCode) IsWildcard() bool { - return gc == WildcardGeo -} - // ClusterGatewayTarget represents a cluster Gateway with geo and weighting info calculated type ClusterGatewayTarget struct { - *utils.ClusterGateway - Geo *GeoCode + *ClusterGateway + Geo *v1alpha1.GeoCode Weight *int } -func NewClusterGatewayTarget(cg utils.ClusterGateway, defaultGeoCode GeoCode, defaultWeight int, customWeights []*v1alpha1.CustomWeight) (ClusterGatewayTarget, error) { +func NewClusterGatewayTarget(cg ClusterGateway, defaultGeoCode v1alpha1.GeoCode, defaultWeight int, customWeights []*v1alpha1.CustomWeight) (ClusterGatewayTarget, error) { target := ClusterGatewayTarget{ ClusterGateway: &cg, } @@ -112,7 +98,7 @@ func NewClusterGatewayTarget(cg utils.ClusterGateway, defaultGeoCode GeoCode, de return target, nil } -func (t *ClusterGatewayTarget) GetGeo() GeoCode { +func (t *ClusterGatewayTarget) GetGeo() v1alpha1.GeoCode { return *t.Geo } @@ -128,14 +114,14 @@ func (t *ClusterGatewayTarget) GetShortCode() string { return ToBase36hash(t.GetName()) } -func (t *ClusterGatewayTarget) setGeo(defaultGeo GeoCode) { +func (t *ClusterGatewayTarget) setGeo(defaultGeo v1alpha1.GeoCode) { geoCode := defaultGeo - if geoCode == DefaultGeo { + if geoCode == v1alpha1.DefaultGeo { t.Geo = &geoCode return } if gc, ok := t.GetLabels()[LabelLBAttributeGeoCode]; ok { - geoCode = GeoCode(gc) + geoCode = v1alpha1.GeoCode(gc) } t.Geo = &geoCode } diff --git a/pkg/dns/target_test.go b/pkg/common/target_test.go similarity index 93% rename from pkg/dns/target_test.go rename to pkg/common/target_test.go index 1b97e2d5a..ee36eecbc 100644 --- a/pkg/dns/target_test.go +++ b/pkg/common/target_test.go @@ -1,6 +1,6 @@ //go:build unit -package dns +package common import ( "fmt" @@ -12,7 +12,6 @@ import ( gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/utils" testutil "github.com/Kuadrant/multicluster-gateway-controller/test/util" ) @@ -26,8 +25,8 @@ const ( func TestNewClusterGatewayTarget(t *testing.T) { type args struct { - clusterGateway utils.ClusterGateway - defaultGeoCode GeoCode + clusterGateway ClusterGateway + defaultGeoCode v1alpha1.GeoCode defaultWeight int customWeights []*v1alpha1.CustomWeight } @@ -40,7 +39,7 @@ func TestNewClusterGatewayTarget(t *testing.T) { { name: "set geo and weight from defaults", args: args{ - clusterGateway: utils.ClusterGateway{ + clusterGateway: ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -50,11 +49,11 @@ func TestNewClusterGatewayTarget(t *testing.T) { ClusterName: clusterName1, }, defaultWeight: 100, - defaultGeoCode: GeoCode("IE"), + defaultGeoCode: v1alpha1.GeoCode("IE"), customWeights: []*v1alpha1.CustomWeight{}, }, want: ClusterGatewayTarget{ - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -63,7 +62,7 @@ func TestNewClusterGatewayTarget(t *testing.T) { }, ClusterName: clusterName1, }, - Geo: testutil.Pointer(GeoCode("IE")), + Geo: testutil.Pointer(v1alpha1.GeoCode("IE")), Weight: testutil.Pointer(100), }, wantErr: false, @@ -71,7 +70,7 @@ func TestNewClusterGatewayTarget(t *testing.T) { { name: "set geo and weight from gateway labels", args: args{ - clusterGateway: utils.ClusterGateway{ + clusterGateway: ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -87,7 +86,7 @@ func TestNewClusterGatewayTarget(t *testing.T) { ClusterName: clusterName1, }, defaultWeight: 100, - defaultGeoCode: GeoCode("IE"), + defaultGeoCode: v1alpha1.GeoCode("IE"), customWeights: []*v1alpha1.CustomWeight{ { Selector: &metav1.LabelSelector{ @@ -100,7 +99,7 @@ func TestNewClusterGatewayTarget(t *testing.T) { }, }, want: ClusterGatewayTarget{ - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -115,7 +114,7 @@ func TestNewClusterGatewayTarget(t *testing.T) { }, ClusterName: clusterName1, }, - Geo: testutil.Pointer(GeoCode("EU")), + Geo: testutil.Pointer(v1alpha1.GeoCode("EU")), Weight: testutil.Pointer(60), }, wantErr: false, @@ -141,7 +140,7 @@ func TestNewClusterGatewayTarget(t *testing.T) { func TestNewMultiClusterGatewayTarget(t *testing.T) { type args struct { gateway *gatewayapiv1.Gateway - clusterGateways []utils.ClusterGateway + clusterGateways []ClusterGateway loadBalancing *v1alpha1.LoadBalancingSpec } gateway := &gatewayapiv1.Gateway{ @@ -160,7 +159,7 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { name: "set cluster gateway targets with default geo and weight values", args: args{ gateway: gateway, - clusterGateways: []utils.ClusterGateway{ + clusterGateways: []ClusterGateway{ { Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ @@ -190,7 +189,7 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { Gateway: gateway, ClusterGatewayTargets: []ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -201,11 +200,11 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { }, ClusterName: clusterName1, }, - Geo: testutil.Pointer(DefaultGeo), - Weight: testutil.Pointer(DefaultWeight), + Geo: testutil.Pointer(v1alpha1.DefaultGeo), + Weight: testutil.Pointer(int(v1alpha1.DefaultWeight)), }, { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -216,8 +215,8 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { }, ClusterName: clusterName2, }, - Geo: testutil.Pointer(DefaultGeo), - Weight: testutil.Pointer(DefaultWeight), + Geo: testutil.Pointer(v1alpha1.DefaultGeo), + Weight: testutil.Pointer(int(v1alpha1.DefaultWeight)), }, }, LoadBalancing: nil, @@ -228,7 +227,7 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { name: "set cluster gateway targets with default geo and weight from load balancing config", args: args{ gateway: gateway, - clusterGateways: []utils.ClusterGateway{ + clusterGateways: []ClusterGateway{ { Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ @@ -265,7 +264,7 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { Gateway: gateway, ClusterGatewayTargets: []ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -276,11 +275,11 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { }, ClusterName: clusterName1, }, - Geo: testutil.Pointer(GeoCode("IE")), + Geo: testutil.Pointer(v1alpha1.GeoCode("IE")), Weight: testutil.Pointer(255), }, { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -291,7 +290,7 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { }, ClusterName: clusterName2, }, - Geo: testutil.Pointer(GeoCode("IE")), + Geo: testutil.Pointer(v1alpha1.GeoCode("IE")), Weight: testutil.Pointer(255), }, }, @@ -310,7 +309,7 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { name: "set cluster gateway targets with default geo and weight from cluster labels", args: args{ gateway: gateway, - clusterGateways: []utils.ClusterGateway{ + clusterGateways: []ClusterGateway{ { Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ @@ -359,7 +358,7 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { Gateway: gateway, ClusterGatewayTargets: []ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -374,11 +373,11 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { }, ClusterName: clusterName1, }, - Geo: testutil.Pointer(GeoCode("EU")), + Geo: testutil.Pointer(v1alpha1.GeoCode("EU")), Weight: testutil.Pointer(60), }, { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -387,7 +386,7 @@ func TestNewMultiClusterGatewayTarget(t *testing.T) { }, ClusterName: clusterName2, }, - Geo: testutil.Pointer(GeoCode("IE")), + Geo: testutil.Pointer(v1alpha1.GeoCode("IE")), Weight: testutil.Pointer(255), }, }, @@ -458,9 +457,9 @@ func TestToBase36hash(t *testing.T) { func TestClusterGatewayTarget_setGeo(t *testing.T) { testCases := []struct { name string - defaultGeo GeoCode + defaultGeo v1alpha1.GeoCode gatewayLabels map[string]string - want GeoCode + want v1alpha1.GeoCode }{ { name: "sets geo from default", @@ -488,7 +487,7 @@ func TestClusterGatewayTarget_setGeo(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t1 *testing.T) { cgt := &ClusterGatewayTarget{ - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -609,7 +608,7 @@ func TestClusterGatewayTarget_setWeight(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t1 *testing.T) { cgt := &ClusterGatewayTarget{ - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -666,7 +665,7 @@ func TestMultiClusterGatewayTarget_RemoveUnhealthyGatewayAddresses(t *testing.T) fields: fields{ ClusterGatewayTargets: []ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -724,7 +723,7 @@ func TestMultiClusterGatewayTarget_RemoveUnhealthyGatewayAddresses(t *testing.T) }, want: []ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -751,7 +750,7 @@ func TestMultiClusterGatewayTarget_RemoveUnhealthyGatewayAddresses(t *testing.T) fields: fields{ ClusterGatewayTargets: []ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -809,7 +808,7 @@ func TestMultiClusterGatewayTarget_RemoveUnhealthyGatewayAddresses(t *testing.T) }, want: []ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -832,7 +831,7 @@ func TestMultiClusterGatewayTarget_RemoveUnhealthyGatewayAddresses(t *testing.T) fields: fields{ ClusterGatewayTargets: []ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", @@ -890,7 +889,7 @@ func TestMultiClusterGatewayTarget_RemoveUnhealthyGatewayAddresses(t *testing.T) }, want: []ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", diff --git a/pkg/controllers/dnspolicy/dns_helper.go b/pkg/controllers/dnspolicy/dns_helper.go index a38a7e452..412833914 100644 --- a/pkg/controllers/dnspolicy/dns_helper.go +++ b/pkg/controllers/dnspolicy/dns_helper.go @@ -18,23 +18,26 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" - "github.com/kuadrant/kuadrant-operator/pkg/common" + kuadrantcommon "github.com/kuadrant/kuadrant-operator/pkg/common" "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/slice" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/common" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" ) 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") ErrNoManagedZoneForHost = fmt.Errorf("no managed zone for host") - ErrAlreadyAssigned = fmt.Errorf("managed host already assigned") ) type dnsHelper struct { @@ -80,14 +83,14 @@ func findMatchingManagedZone(originalHost, host string, zones []v1alpha1.Managed } func commonDNSRecordLabels(gwKey, apKey client.ObjectKey) map[string]string { - common := map[string]string{} + commonLabels := map[string]string{} for k, v := range policyDNSRecordLabels(apKey) { - common[k] = v + commonLabels[k] = v } for k, v := range gatewayDNSRecordLabels(gwKey) { - common[k] = v + commonLabels[k] = v } - return common + return commonLabels } func policyDNSRecordLabels(apKey client.ObjectKey) map[string]string { @@ -135,7 +138,7 @@ func (dh *dnsHelper) getDNSRecordForListener(ctx context.Context, listener gatew return dnsRecord, nil } -func withGatewayListener[T metav1.Object](gateway common.GatewayWrapper, listener gatewayapiv1.Listener, obj T) T { +func withGatewayListener[T metav1.Object](gateway kuadrantcommon.GatewayWrapper, listener gatewayapiv1.Listener, obj T) T { if obj.GetAnnotations() == nil { obj.SetAnnotations(map[string]string{}) } @@ -146,7 +149,7 @@ func withGatewayListener[T metav1.Object](gateway common.GatewayWrapper, listene return obj } -func (dh *dnsHelper) setEndpoints(ctx context.Context, mcgTarget *dns.MultiClusterGatewayTarget, dnsRecord *v1alpha1.DNSRecord, listener gatewayapiv1.Listener, strategy v1alpha1.RoutingStrategy) error { +func (dh *dnsHelper) setEndpoints(ctx context.Context, mcgTarget *common.MultiClusterGatewayTarget, dnsRecord *v1alpha1.DNSRecord, listener gatewayapiv1.Listener, strategy v1alpha1.RoutingStrategy) error { old := dnsRecord.DeepCopy() gwListenerHost := string(*listener.Hostname) var endpoints []*v1alpha1.Endpoint @@ -181,7 +184,7 @@ func (dh *dnsHelper) setEndpoints(ctx context.Context, mcgTarget *dns.MultiClust // getSimpleEndpoints returns the endpoints for the given MultiClusterGatewayTarget using the simple routing strategy -func (dh *dnsHelper) getSimpleEndpoints(mcgTarget *dns.MultiClusterGatewayTarget, hostname string, currentEndpoints map[string]*v1alpha1.Endpoint) []*v1alpha1.Endpoint { +func (dh *dnsHelper) getSimpleEndpoints(mcgTarget *common.MultiClusterGatewayTarget, hostname string, currentEndpoints map[string]*v1alpha1.Endpoint) []*v1alpha1.Endpoint { var ( endpoints []*v1alpha1.Endpoint @@ -200,13 +203,13 @@ func (dh *dnsHelper) getSimpleEndpoints(mcgTarget *dns.MultiClusterGatewayTarget } if len(ipValues) > 0 { - endpoint := createOrUpdateEndpoint(hostname, ipValues, v1alpha1.ARecordType, "", dns.DefaultTTL, currentEndpoints) + endpoint := createOrUpdateEndpoint(hostname, ipValues, v1alpha1.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/multicluster-gateway-controller/issues/663 if len(hostValues) > 0 { - endpoint := createOrUpdateEndpoint(hostname, hostValues, v1alpha1.CNAMERecordType, "", dns.DefaultTTL, currentEndpoints) + endpoint := createOrUpdateEndpoint(hostname, hostValues, v1alpha1.CNAMERecordType, "", DefaultTTL, currentEndpoints) endpoints = append(endpoints, endpoint) } @@ -252,7 +255,7 @@ func (dh *dnsHelper) getSimpleEndpoints(mcgTarget *dns.MultiClusterGatewayTarget // 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 *dns.MultiClusterGatewayTarget, hostname string, currentEndpoints map[string]*v1alpha1.Endpoint) []*v1alpha1.Endpoint { +func (dh *dnsHelper) getLoadBalancedEndpoints(mcgTarget *common.MultiClusterGatewayTarget, hostname string, currentEndpoints map[string]*v1alpha1.Endpoint) []*v1alpha1.Endpoint { cnameHost := hostname if isWildCardHost(hostname) { @@ -283,14 +286,14 @@ func (dh *dnsHelper) getLoadBalancedEndpoints(mcgTarget *dns.MultiClusterGateway if len(ipValues) > 0 { clusterLbName := strings.ToLower(fmt.Sprintf("%s.%s", cgwTarget.GetShortCode(), lbName)) - endpoint = createOrUpdateEndpoint(clusterLbName, ipValues, v1alpha1.ARecordType, "", dns.DefaultTTL, currentEndpoints) + endpoint = createOrUpdateEndpoint(clusterLbName, ipValues, v1alpha1.ARecordType, "", DefaultTTL, currentEndpoints) clusterEndpoints = append(clusterEndpoints, endpoint) hostValues = append(hostValues, clusterLbName) } for _, hostValue := range hostValues { - endpoint = createOrUpdateEndpoint(geoLbName, []string{hostValue}, v1alpha1.CNAMERecordType, hostValue, dns.DefaultTTL, currentEndpoints) - endpoint.SetProviderSpecific(dns.ProviderSpecificWeight, strconv.Itoa(cgwTarget.GetWeight())) + endpoint = createOrUpdateEndpoint(geoLbName, []string{hostValue}, v1alpha1.CNAMERecordType, hostValue, DefaultTTL, currentEndpoints) + endpoint.SetProviderSpecific(provider.ProviderSpecificWeight, strconv.Itoa(cgwTarget.GetWeight())) clusterEndpoints = append(clusterEndpoints, endpoint) } } @@ -300,7 +303,7 @@ func (dh *dnsHelper) getLoadBalancedEndpoints(mcgTarget *dns.MultiClusterGateway endpoints = append(endpoints, clusterEndpoints...) //Create lbName CNAME (lb-a1b2.shop.example.com -> default.lb-a1b2.shop.example.com) - endpoint = createOrUpdateEndpoint(lbName, []string{geoLbName}, v1alpha1.CNAMERecordType, string(geoCode), dns.DefaultCnameTTL, currentEndpoints) + endpoint = createOrUpdateEndpoint(lbName, []string{geoLbName}, v1alpha1.CNAMERecordType, string(geoCode), DefaultCnameTTL, currentEndpoints) //Deal with the default geo endpoint first if geoCode.IsDefaultCode() { @@ -309,20 +312,20 @@ func (dh *dnsHelper) getLoadBalancedEndpoints(mcgTarget *dns.MultiClusterGateway continue } else if (geoCode == mcgTarget.GetDefaultGeo()) || defaultEndpoint == nil { // Ensure that a `defaultEndpoint` is always set, but the expected default takes precedence - defaultEndpoint = createOrUpdateEndpoint(lbName, []string{geoLbName}, v1alpha1.CNAMERecordType, "default", dns.DefaultCnameTTL, currentEndpoints) + defaultEndpoint = createOrUpdateEndpoint(lbName, []string{geoLbName}, v1alpha1.CNAMERecordType, "default", DefaultCnameTTL, currentEndpoints) } - endpoint.SetProviderSpecific(dns.ProviderSpecificGeoCode, string(geoCode)) + endpoint.SetProviderSpecific(provider.ProviderSpecificGeoCode, string(geoCode)) endpoints = append(endpoints, endpoint) } if len(endpoints) > 0 { // Add the `defaultEndpoint`, this should always be set by this point if `endpoints` isn't empty - defaultEndpoint.SetProviderSpecific(dns.ProviderSpecificGeoCode, string(dns.WildcardGeo)) + defaultEndpoint.SetProviderSpecific(provider.ProviderSpecificGeoCode, string(v1alpha1.WildcardGeo)) endpoints = append(endpoints, defaultEndpoint) //Create gwListenerHost CNAME (shop.example.com -> lb-a1b2.shop.example.com) - endpoint = createOrUpdateEndpoint(hostname, []string{lbName}, v1alpha1.CNAMERecordType, "", dns.DefaultCnameTTL, currentEndpoints) + endpoint = createOrUpdateEndpoint(hostname, []string{lbName}, v1alpha1.CNAMERecordType, "", DefaultCnameTTL, currentEndpoints) endpoints = append(endpoints, endpoint) } diff --git a/pkg/controllers/dnspolicy/dns_helper_test.go b/pkg/controllers/dnspolicy/dns_helper_test.go index 198a7dd35..f0a5776f7 100644 --- a/pkg/controllers/dnspolicy/dns_helper_test.go +++ b/pkg/controllers/dnspolicy/dns_helper_test.go @@ -17,8 +17,7 @@ import ( gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/utils" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/common" testutil "github.com/Kuadrant/multicluster-gateway-controller/test/util" ) @@ -407,7 +406,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { testCases := []struct { name string - mcgTarget *dns.MultiClusterGatewayTarget + mcgTarget *common.MultiClusterGatewayTarget listener gatewayapiv1.Listener dnsRecord *v1alpha1.DNSRecord wantSpec *v1alpha1.DNSRecordSpec @@ -416,13 +415,13 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { { name: "test wildcard listener weighted", listener: getTestListener("*.example.com"), - mcgTarget: &dns.MultiClusterGatewayTarget{ + mcgTarget: &common.MultiClusterGatewayTarget{ Gateway: &gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, }, - ClusterGatewayTargets: []dns.ClusterGatewayTarget{ + ClusterGatewayTargets: []common.ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &common.ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -440,12 +439,12 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { }, ClusterName: "test-cluster-1", }, - Geo: testutil.Pointer(dns.GeoCode("default")), + Geo: testutil.Pointer(v1alpha1.GeoCode("default")), Weight: testutil.Pointer(120), }, { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &common.ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -459,7 +458,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { }, ClusterName: "test-cluster-2", }, - Geo: testutil.Pointer(dns.GeoCode("default")), + Geo: testutil.Pointer(v1alpha1.GeoCode("default")), Weight: testutil.Pointer(120), }, }, @@ -475,14 +474,14 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { DNSName: "20qri0.lb-ocnswx.example.com", Targets: []string{"1.1.1.1", "2.2.2.2"}, RecordType: "A", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, }, { DNSName: "default.lb-ocnswx.example.com", Targets: []string{"20qri0.lb-ocnswx.example.com"}, RecordType: "CNAME", SetIdentifier: "20qri0.lb-ocnswx.example.com", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "weight", @@ -495,7 +494,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"mylb.example.com"}, RecordType: "CNAME", SetIdentifier: "mylb.example.com", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "weight", @@ -508,7 +507,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"default.lb-ocnswx.example.com"}, RecordType: "CNAME", SetIdentifier: "default", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "geo-code", @@ -520,7 +519,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { DNSName: "*.example.com", Targets: []string{"lb-ocnswx.example.com"}, RecordType: "CNAME", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, }, }, }, @@ -528,13 +527,13 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { { name: "sets geo weighted endpoints wildcard", listener: getTestListener("*.example.com"), - mcgTarget: &dns.MultiClusterGatewayTarget{ + mcgTarget: &common.MultiClusterGatewayTarget{ Gateway: &gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, }, - ClusterGatewayTargets: []dns.ClusterGatewayTarget{ + ClusterGatewayTargets: []common.ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &common.ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -552,12 +551,12 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { }, ClusterName: "test-cluster-1", }, - Geo: testutil.Pointer(dns.GeoCode("NA")), + Geo: testutil.Pointer(v1alpha1.GeoCode("NA")), Weight: testutil.Pointer(120), }, { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &common.ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -571,7 +570,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { }, ClusterName: "test-cluster-2", }, - Geo: testutil.Pointer(dns.GeoCode("IE")), + Geo: testutil.Pointer(v1alpha1.GeoCode("IE")), Weight: testutil.Pointer(120), }, }, @@ -592,14 +591,14 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { DNSName: "20qri0.lb-ocnswx.example.com", Targets: []string{"1.1.1.1", "2.2.2.2"}, RecordType: "A", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, }, { DNSName: "na.lb-ocnswx.example.com", Targets: []string{"20qri0.lb-ocnswx.example.com"}, RecordType: "CNAME", SetIdentifier: "20qri0.lb-ocnswx.example.com", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "weight", @@ -612,7 +611,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"mylb.example.com"}, RecordType: "CNAME", SetIdentifier: "mylb.example.com", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "weight", @@ -625,7 +624,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"na.lb-ocnswx.example.com"}, RecordType: "CNAME", SetIdentifier: "default", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "geo-code", @@ -638,7 +637,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"na.lb-ocnswx.example.com"}, RecordType: "CNAME", SetIdentifier: "NA", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "geo-code", @@ -651,7 +650,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"ie.lb-ocnswx.example.com"}, RecordType: "CNAME", SetIdentifier: "IE", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "geo-code", @@ -663,7 +662,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { DNSName: "*.example.com", Targets: []string{"lb-ocnswx.example.com"}, RecordType: "CNAME", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, }, }, }, @@ -671,17 +670,17 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { { name: "sets weighted endpoints", listener: getTestListener("test.example.com"), - mcgTarget: &dns.MultiClusterGatewayTarget{ + mcgTarget: &common.MultiClusterGatewayTarget{ Gateway: &gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{ Name: "testgw", Namespace: "testns", }, }, - ClusterGatewayTargets: []dns.ClusterGatewayTarget{ + ClusterGatewayTargets: []common.ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &common.ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -699,12 +698,12 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { }, ClusterName: "test-cluster-1", }, - Geo: testutil.Pointer(dns.GeoCode("default")), + Geo: testutil.Pointer(v1alpha1.GeoCode("default")), Weight: testutil.Pointer(120), }, { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &common.ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -718,7 +717,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { }, ClusterName: "test-cluster-2", }, - Geo: testutil.Pointer(dns.GeoCode("default")), + Geo: testutil.Pointer(v1alpha1.GeoCode("default")), Weight: testutil.Pointer(120), }, }, @@ -734,14 +733,14 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { DNSName: "20qri0.lb-0ecjaw.test.example.com", Targets: []string{"1.1.1.1", "2.2.2.2"}, RecordType: "A", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, }, { DNSName: "default.lb-0ecjaw.test.example.com", Targets: []string{"20qri0.lb-0ecjaw.test.example.com"}, RecordType: "CNAME", SetIdentifier: "20qri0.lb-0ecjaw.test.example.com", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "weight", @@ -754,7 +753,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"mylb.example.com"}, RecordType: "CNAME", SetIdentifier: "mylb.example.com", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "weight", @@ -767,7 +766,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"default.lb-0ecjaw.test.example.com"}, RecordType: "CNAME", SetIdentifier: "default", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "geo-code", @@ -779,7 +778,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { DNSName: "test.example.com", Targets: []string{"lb-0ecjaw.test.example.com"}, RecordType: "CNAME", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, }, }, }, @@ -787,14 +786,14 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { { name: "sets geo weighted endpoints", listener: getTestListener("test.example.com"), - mcgTarget: &dns.MultiClusterGatewayTarget{ + mcgTarget: &common.MultiClusterGatewayTarget{ Gateway: &gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, }, - ClusterGatewayTargets: []dns.ClusterGatewayTarget{ + ClusterGatewayTargets: []common.ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &common.ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -812,12 +811,12 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { }, ClusterName: "test-cluster-1", }, - Geo: testutil.Pointer(dns.GeoCode("NA")), + Geo: testutil.Pointer(v1alpha1.GeoCode("NA")), Weight: testutil.Pointer(120), }, { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &common.ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -831,7 +830,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { }, ClusterName: "test-cluster-2", }, - Geo: testutil.Pointer(dns.GeoCode("IE")), + Geo: testutil.Pointer(v1alpha1.GeoCode("IE")), Weight: testutil.Pointer(120), }, }, @@ -852,14 +851,14 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { DNSName: "20qri0.lb-ocnswx.test.example.com", Targets: []string{"1.1.1.1", "2.2.2.2"}, RecordType: "A", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, }, { DNSName: "na.lb-ocnswx.test.example.com", Targets: []string{"20qri0.lb-ocnswx.test.example.com"}, RecordType: "CNAME", SetIdentifier: "20qri0.lb-ocnswx.test.example.com", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "weight", @@ -872,7 +871,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"mylb.example.com"}, RecordType: "CNAME", SetIdentifier: "mylb.example.com", - RecordTTL: dns.DefaultTTL, + RecordTTL: DefaultTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "weight", @@ -885,7 +884,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"na.lb-ocnswx.test.example.com"}, RecordType: "CNAME", SetIdentifier: "default", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "geo-code", @@ -898,7 +897,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"na.lb-ocnswx.test.example.com"}, RecordType: "CNAME", SetIdentifier: "NA", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "geo-code", @@ -911,7 +910,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { Targets: []string{"ie.lb-ocnswx.test.example.com"}, RecordType: "CNAME", SetIdentifier: "IE", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, ProviderSpecific: []v1alpha1.ProviderSpecificProperty{ { Name: "geo-code", @@ -923,7 +922,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { DNSName: "test.example.com", Targets: []string{"lb-ocnswx.test.example.com"}, RecordType: "CNAME", - RecordTTL: dns.DefaultCnameTTL, + RecordTTL: DefaultCnameTTL, }, }, }, @@ -931,14 +930,14 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { { name: "sets no endpoints when no target addresses", listener: getTestListener("test.example.com"), - mcgTarget: &dns.MultiClusterGatewayTarget{ + mcgTarget: &common.MultiClusterGatewayTarget{ Gateway: &gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, }, - ClusterGatewayTargets: []dns.ClusterGatewayTarget{ + ClusterGatewayTargets: []common.ClusterGatewayTarget{ { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &common.ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -947,12 +946,12 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { }, ClusterName: "test-cluster-1", }, - Geo: testutil.Pointer(dns.GeoCode("NA")), + Geo: testutil.Pointer(v1alpha1.GeoCode("NA")), Weight: testutil.Pointer(120), }, { - ClusterGateway: &utils.ClusterGateway{ + ClusterGateway: &common.ClusterGateway{ Gateway: gatewayapiv1.Gateway{ ObjectMeta: v1.ObjectMeta{Name: "testgw"}, Status: gatewayapiv1.GatewayStatus{ @@ -961,7 +960,7 @@ func Test_dnsHelper_setEndpoints(t *testing.T) { }, ClusterName: "test-cluster-2", }, - Geo: testutil.Pointer(dns.GeoCode("IE")), + Geo: testutil.Pointer(v1alpha1.GeoCode("IE")), Weight: testutil.Pointer(120), }, }, diff --git a/pkg/controllers/dnspolicy/dnspolicy_controller.go b/pkg/controllers/dnspolicy/dnspolicy_controller.go index ebdf574ff..301a264de 100644 --- a/pkg/controllers/dnspolicy/dnspolicy_controller.go +++ b/pkg/controllers/dnspolicy/dnspolicy_controller.go @@ -38,7 +38,7 @@ import ( "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/conditions" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" "github.com/Kuadrant/multicluster-gateway-controller/pkg/controllers/events" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" ) const ( @@ -57,8 +57,8 @@ func (c *DNSPolicyRefsConfig) PolicyRefsAnnotation() string { // DNSPolicyReconciler reconciles a DNSPolicy object type DNSPolicyReconciler struct { reconcilers.TargetRefReconciler - DNSProvider dns.DNSProviderFactory - dnsHelper dnsHelper + ProviderFactory provider.Factory + dnsHelper dnsHelper } //+kubebuilder:rbac:groups=kuadrant.io,resources=dnspolicies,verbs=get;list;watch;update;patch;delete diff --git a/pkg/controllers/dnspolicy/dnspolicy_dnsrecords.go b/pkg/controllers/dnspolicy/dnspolicy_dnsrecords.go index 1b058a5b2..2356246e6 100644 --- a/pkg/controllers/dnspolicy/dnspolicy_dnsrecords.go +++ b/pkg/controllers/dnspolicy/dnspolicy_dnsrecords.go @@ -14,8 +14,7 @@ import ( "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/slice" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/utils" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/common" ) func (r *DNSPolicyReconciler) reconcileDNSRecords(ctx context.Context, dnsPolicy *v1alpha1.DNSPolicy, gwDiffObj *reconcilers.GatewayDiff) error { @@ -42,7 +41,7 @@ func (r *DNSPolicyReconciler) reconcileDNSRecords(ctx context.Context, dnsPolicy func (r *DNSPolicyReconciler) reconcileGatewayDNSRecords(ctx context.Context, gw *gatewayapiv1.Gateway, dnsPolicy *v1alpha1.DNSPolicy) error { log := crlog.FromContext(ctx) - gatewayWrapper := utils.NewGatewayWrapper(gw) + gatewayWrapper := common.NewGatewayWrapper(gw) if err := gatewayWrapper.Validate(); err != nil { return err } @@ -67,7 +66,7 @@ func (r *DNSPolicyReconciler) reconcileGatewayDNSRecords(ctx context.Context, gw continue } - listenerGateways := slice.Filter(clusterGateways, func(cgw utils.ClusterGateway) bool { + listenerGateways := slice.Filter(clusterGateways, func(cgw common.ClusterGateway) bool { hasAttachedRoute := false for _, statusListener := range cgw.Status.Listeners { if string(statusListener.Name) == string(listener.Name) { @@ -97,7 +96,7 @@ func (r *DNSPolicyReconciler) reconcileGatewayDNSRecords(ctx context.Context, gw } } - mcgTarget, err := dns.NewMultiClusterGatewayTarget(gatewayWrapper.Gateway, listenerGateways, dnsPolicy.Spec.LoadBalancing) + mcgTarget, err := common.NewMultiClusterGatewayTarget(gatewayWrapper.Gateway, listenerGateways, dnsPolicy.Spec.LoadBalancing) if err != nil { return fmt.Errorf("failed to create multi cluster gateway target for listener %s : %s ", listener.Name, err) } diff --git a/pkg/controllers/dnspolicy/dnspolicy_healthchecks.go b/pkg/controllers/dnspolicy/dnspolicy_healthchecks.go index cec93ab47..9c4902213 100644 --- a/pkg/controllers/dnspolicy/dnspolicy_healthchecks.go +++ b/pkg/controllers/dnspolicy/dnspolicy_healthchecks.go @@ -13,12 +13,12 @@ import ( crlog "sigs.k8s.io/controller-runtime/pkg/log" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" - "github.com/kuadrant/kuadrant-operator/pkg/common" + kuadrantcommon "github.com/kuadrant/kuadrant-operator/pkg/common" "github.com/kuadrant/kuadrant-operator/pkg/reconcilers" "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/slice" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/utils" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/common" ) func (r *DNSPolicyReconciler) reconcileHealthCheckProbes(ctx context.Context, dnsPolicy *v1alpha1.DNSPolicy, gwDiffObj *reconcilers.GatewayDiff) error { @@ -110,7 +110,7 @@ func (r *DNSPolicyReconciler) deleteUnexpectedGatewayHealthCheckProbes(ctx conte return nil } -func (r *DNSPolicyReconciler) expectedHealthCheckProbesForGateway(ctx context.Context, gw common.GatewayWrapper, dnsPolicy *v1alpha1.DNSPolicy) []*v1alpha1.DNSHealthCheckProbe { +func (r *DNSPolicyReconciler) expectedHealthCheckProbesForGateway(ctx context.Context, gw kuadrantcommon.GatewayWrapper, dnsPolicy *v1alpha1.DNSPolicy) []*v1alpha1.DNSHealthCheckProbe { log := crlog.FromContext(ctx) var healthChecks []*v1alpha1.DNSHealthCheckProbe if dnsPolicy.Spec.HealthCheck == nil { @@ -123,7 +123,7 @@ func (r *DNSPolicyReconciler) expectedHealthCheckProbesForGateway(ctx context.Co interval = *dnsPolicy.Spec.HealthCheck.Interval } - gatewayWrapper := utils.NewGatewayWrapper(gw.Gateway) + gatewayWrapper := common.NewGatewayWrapper(gw.Gateway) if err := gatewayWrapper.Validate(); err != nil { return nil } diff --git a/pkg/controllers/dnspolicy/dnspolicy_healthchecks_test.go b/pkg/controllers/dnspolicy/dnspolicy_healthchecks_test.go index 26257bb8a..1767a9544 100644 --- a/pkg/controllers/dnspolicy/dnspolicy_healthchecks_test.go +++ b/pkg/controllers/dnspolicy/dnspolicy_healthchecks_test.go @@ -11,13 +11,13 @@ import ( controllerruntime "sigs.k8s.io/controller-runtime" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" - "github.com/kuadrant/kuadrant-operator/pkg/common" + kuadrantcommon "github.com/kuadrant/kuadrant-operator/pkg/common" "github.com/kuadrant/kuadrant-operator/pkg/reconcilers" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/common" "github.com/Kuadrant/multicluster-gateway-controller/pkg/controllers/gateway" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/utils" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" testutil "github.com/Kuadrant/multicluster-gateway-controller/test/util" ) @@ -31,13 +31,13 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { type fields struct { TargetRefReconciler reconcilers.TargetRefReconciler - DNSProvider dns.DNSProviderFactory + ProviderFactory provider.Factory dnsHelper dnsHelper Placer gateway.GatewayPlacer } type args struct { ctx context.Context - gw common.GatewayWrapper + gw kuadrantcommon.GatewayWrapper dnsPolicy *v1alpha1.DNSPolicy } tests := []struct { @@ -50,13 +50,13 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { name: "expected probes not nil when all values specified in the check", fields: fields{ TargetRefReconciler: reconcilers.TargetRefReconciler{}, - DNSProvider: nil, + ProviderFactory: nil, dnsHelper: dnsHelper{}, Placer: nil, }, args: args{ ctx: nil, - gw: common.GatewayWrapper{ + gw: kuadrantcommon.GatewayWrapper{ Gateway: &gatewayapiv1.Gateway{ ObjectMeta: controllerruntime.ObjectMeta{ Name: "testgateway", @@ -73,7 +73,7 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { Status: gatewayapiv1.GatewayStatus{ Addresses: []gatewayapiv1.GatewayStatusAddress{ { - Type: testutil.Pointer(utils.MultiClusterIPAddressType), + Type: testutil.Pointer(common.MultiClusterIPAddressType), Value: "clusterName/172.31.200.0", }, }, @@ -139,13 +139,13 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { name: "expected probes not nil when some values not specified in the check", fields: fields{ TargetRefReconciler: reconcilers.TargetRefReconciler{}, - DNSProvider: nil, + ProviderFactory: nil, dnsHelper: dnsHelper{}, Placer: nil, }, args: args{ ctx: nil, - gw: common.GatewayWrapper{ + gw: kuadrantcommon.GatewayWrapper{ Gateway: &gatewayapiv1.Gateway{ ObjectMeta: controllerruntime.ObjectMeta{ Name: "testgateway", @@ -164,7 +164,7 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { Status: gatewayapiv1.GatewayStatus{ Addresses: []gatewayapiv1.GatewayStatusAddress{ { - Type: testutil.Pointer(utils.MultiClusterIPAddressType), + Type: testutil.Pointer(common.MultiClusterIPAddressType), Value: "clusterName/172.31.200.0", }, }, @@ -211,13 +211,13 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { name: "no probes when listener has a wildcard domain", fields: fields{ TargetRefReconciler: reconcilers.TargetRefReconciler{}, - DNSProvider: nil, + ProviderFactory: nil, dnsHelper: dnsHelper{}, Placer: nil, }, args: args{ ctx: nil, - gw: common.GatewayWrapper{ + gw: kuadrantcommon.GatewayWrapper{ Gateway: &gatewayapiv1.Gateway{ Spec: gatewayapiv1.GatewaySpec{ Listeners: []gatewayapiv1.Listener{ @@ -248,13 +248,13 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { name: "expected probes when status.address.value is an IP address", fields: fields{ TargetRefReconciler: reconcilers.TargetRefReconciler{}, - DNSProvider: nil, + ProviderFactory: nil, dnsHelper: dnsHelper{}, Placer: nil, }, args: args{ ctx: nil, - gw: common.GatewayWrapper{ + gw: kuadrantcommon.GatewayWrapper{ Gateway: &gatewayapiv1.Gateway{ ObjectMeta: controllerruntime.ObjectMeta{ Name: "testgateway", @@ -320,13 +320,13 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { name: "no probes when address.Value doesn't contain /", fields: fields{ TargetRefReconciler: reconcilers.TargetRefReconciler{}, - DNSProvider: nil, + ProviderFactory: nil, dnsHelper: dnsHelper{}, Placer: nil, }, args: args{ ctx: nil, - gw: common.GatewayWrapper{ + gw: kuadrantcommon.GatewayWrapper{ Gateway: &gatewayapiv1.Gateway{ Status: gatewayapiv1.GatewayStatus{ Addresses: []gatewayapiv1.GatewayStatusAddress{ @@ -350,13 +350,13 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { name: "no probes when no listeners defined", fields: fields{ TargetRefReconciler: reconcilers.TargetRefReconciler{}, - DNSProvider: nil, + ProviderFactory: nil, dnsHelper: dnsHelper{}, Placer: nil, }, args: args{ ctx: nil, - gw: common.GatewayWrapper{ + gw: kuadrantcommon.GatewayWrapper{ Gateway: &gatewayapiv1.Gateway{ Status: gatewayapiv1.GatewayStatus{ Addresses: []gatewayapiv1.GatewayStatusAddress{ @@ -380,13 +380,13 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { name: "no probes when no address defined", fields: fields{ TargetRefReconciler: reconcilers.TargetRefReconciler{}, - DNSProvider: nil, + ProviderFactory: nil, dnsHelper: dnsHelper{}, Placer: nil, }, args: args{ ctx: nil, - gw: common.GatewayWrapper{ + gw: kuadrantcommon.GatewayWrapper{ Gateway: &gatewayapiv1.Gateway{ Status: gatewayapiv1.GatewayStatus{}, }, @@ -412,7 +412,7 @@ func TestDNSPolicyReconciler_expectedProbesForGateway(t *testing.T) { t.Run(tt.name, func(t *testing.T) { r := &DNSPolicyReconciler{ TargetRefReconciler: tt.fields.TargetRefReconciler, - DNSProvider: tt.fields.DNSProvider, + ProviderFactory: tt.fields.ProviderFactory, dnsHelper: tt.fields.dnsHelper, } got := r.expectedHealthCheckProbesForGateway(tt.args.ctx, tt.args.gw, tt.args.dnsPolicy) diff --git a/pkg/controllers/dnsrecord/dnsrecord_controller.go b/pkg/controllers/dnsrecord/dnsrecord_controller.go index b38812a8f..acbeb7716 100644 --- a/pkg/controllers/dnsrecord/dnsrecord_controller.go +++ b/pkg/controllers/dnsrecord/dnsrecord_controller.go @@ -34,7 +34,7 @@ import ( "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/conditions" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" ) const ( @@ -46,8 +46,8 @@ var Clock clock.Clock = clock.RealClock{} // DNSRecordReconciler reconciles a DNSRecord object type DNSRecordReconciler struct { client.Client - Scheme *runtime.Scheme - DNSProvider dns.DNSProviderFactory + Scheme *runtime.Scheme + ProviderFactory provider.Factory } //+kubebuilder:rbac:groups=kuadrant.io,resources=dnsrecords,verbs=get;list;watch;create;update;patch;delete @@ -103,7 +103,7 @@ func (r *DNSRecordReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( if err != nil { status = metav1.ConditionFalse reason = "ProviderError" - message = fmt.Sprintf("The DNS provider failed to ensure the record: %v", dns.SanitizeError(err)) + message = fmt.Sprintf("The DNS provider failed to ensure the record: %v", provider.SanitizeError(err)) } else { dnsRecord.Status.ObservedGeneration = dnsRecord.Generation dnsRecord.Status.Endpoints = dnsRecord.Spec.Endpoints @@ -151,7 +151,7 @@ func (r *DNSRecordReconciler) deleteRecord(ctx context.Context, dnsRecord *v1alp return fmt.Errorf("the managed zone is not in a ready state : %s", managedZone.Name) } - dnsProvider, err := r.DNSProvider(ctx, managedZone) + dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone) if err != nil { return err } @@ -196,7 +196,7 @@ func (r *DNSRecordReconciler) publishRecord(ctx context.Context, dnsRecord *v1al log.Log.V(3).Info("Skipping managed zone to which the DNS dnsRecord is already published", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) return nil } - dnsProvider, err := r.DNSProvider(ctx, managedZone) + dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone) if err != nil { return err } diff --git a/pkg/controllers/gateway/gateway_controller.go b/pkg/controllers/gateway/gateway_controller.go index b8a485fa5..046e7a9c7 100644 --- a/pkg/controllers/gateway/gateway_controller.go +++ b/pkg/controllers/gateway/gateway_controller.go @@ -51,8 +51,8 @@ import ( "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/gracePeriod" "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/metadata" "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/slice" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/common" "github.com/Kuadrant/multicluster-gateway-controller/pkg/policysync" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/utils" ) const ( @@ -221,7 +221,7 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct } for _, address := range addresses { log.V(3).Info("checking address type for mapping", "address.Type", address.Type) - addressType, supported := utils.AddressTypeToMultiCluster(address) + addressType, supported := common.AddressTypeToMultiCluster(address) if !supported { continue // ignore address type gatewayapiv1.NamedAddressType. Unsupported for multi cluster gateway } diff --git a/pkg/controllers/managedzone/managedzone_controller.go b/pkg/controllers/managedzone/managedzone_controller.go index bed66f846..3c5e2c9f9 100644 --- a/pkg/controllers/managedzone/managedzone_controller.go +++ b/pkg/controllers/managedzone/managedzone_controller.go @@ -32,7 +32,7 @@ import ( "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/conditions" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" ) const ( @@ -42,8 +42,8 @@ const ( // ManagedZoneReconciler reconciles a ManagedZone object type ManagedZoneReconciler struct { client.Client - Scheme *runtime.Scheme - DNSProvider dns.DNSProviderFactory + Scheme *runtime.Scheme + ProviderFactory provider.Factory } //+kubebuilder:rbac:groups=kuadrant.io,resources=managedzones,verbs=get;list;watch;create;update;patch;delete @@ -163,7 +163,7 @@ func (r *ManagedZoneReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *ManagedZoneReconciler) publishManagedZone(ctx context.Context, managedZone *v1alpha1.ManagedZone) error { - dnsProvider, err := r.DNSProvider(ctx, managedZone) + dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone) if err != nil { return err } @@ -185,7 +185,7 @@ func (r *ManagedZoneReconciler) deleteManagedZone(ctx context.Context, managedZo return nil } - dnsProvider, err := r.DNSProvider(ctx, managedZone) + dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone) if err != nil { var reason, message string status := metav1.ConditionFalse diff --git a/pkg/dns/aws/health.go b/pkg/dns/aws/health.go deleted file mode 100644 index 1d726cf97..000000000 --- a/pkg/dns/aws/health.go +++ /dev/null @@ -1,258 +0,0 @@ -package aws - -import ( - "context" - "fmt" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/route53" - "github.com/aws/aws-sdk-go/service/route53/route53iface" - "github.com/rs/xid" - - "sigs.k8s.io/controller-runtime/pkg/log" - - "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" -) - -const ( - idTag = "kuadrant.dev/healthcheck" - - defaultHealthCheckPath = "/" - defaultHealthCheckPort = 80 - defaultHealthCheckFailureThreshold = 3 -) - -var ( - callerReference func(id string) *string -) - -type Route53HealthCheckReconciler struct { - client route53iface.Route53API -} - -var _ dns.HealthCheckReconciler = &Route53HealthCheckReconciler{} - -func NewRoute53HealthCheckReconciler(client route53iface.Route53API) *Route53HealthCheckReconciler { - return &Route53HealthCheckReconciler{ - client: client, - } -} - -func (r *Route53HealthCheckReconciler) Reconcile(ctx context.Context, spec dns.HealthCheckSpec, endpoint *v1alpha1.Endpoint) (dns.HealthCheckResult, error) { - healthCheck, exists, err := r.findHealthCheck(ctx, endpoint) - if err != nil { - return dns.HealthCheckResult{}, err - } - - defer func() { - if healthCheck != nil { - endpoint.SetProviderSpecific(ProviderSpecificHealthCheckID, *healthCheck.Id) - } - }() - - if exists { - status, err := r.updateHealthCheck(ctx, spec, endpoint, healthCheck) - if err != nil { - return dns.HealthCheckResult{}, err - } - - return dns.NewHealthCheckResult(status, ""), nil - } - - healthCheck, err = r.createHealthCheck(ctx, spec, endpoint) - if err != nil { - return dns.HealthCheckResult{}, err - } - - return dns.NewHealthCheckResult(dns.HealthCheckCreated, fmt.Sprintf("Created health check with ID %s", *healthCheck.Id)), nil -} - -func (r *Route53HealthCheckReconciler) Delete(ctx context.Context, endpoint *v1alpha1.Endpoint) (dns.HealthCheckResult, error) { - healthCheck, found, err := r.findHealthCheck(ctx, endpoint) - if err != nil { - return dns.HealthCheckResult{}, err - } - if !found { - return dns.NewHealthCheckResult(dns.HealthCheckNoop, ""), nil - } - - _, err = r.client.DeleteHealthCheckWithContext(ctx, &route53.DeleteHealthCheckInput{ - HealthCheckId: healthCheck.Id, - }) - - if err != nil { - return dns.HealthCheckResult{}, err - } - - endpoint.DeleteProviderSpecific(ProviderSpecificHealthCheckID) - return dns.NewHealthCheckResult(dns.HealthCheckDeleted, ""), nil -} - -func (c *Route53HealthCheckReconciler) findHealthCheck(ctx context.Context, endpoint *v1alpha1.Endpoint) (*route53.HealthCheck, bool, error) { - id, hasId := getHealthCheckId(endpoint) - if !hasId { - return nil, false, nil - } - - response, err := c.client.GetHealthCheckWithContext(ctx, &route53.GetHealthCheckInput{ - HealthCheckId: &id, - }) - if err != nil { - return nil, false, err - } - - return response.HealthCheck, true, nil - -} - -func (c *Route53HealthCheckReconciler) createHealthCheck(ctx context.Context, spec dns.HealthCheckSpec, endpoint *v1alpha1.Endpoint) (*route53.HealthCheck, error) { - address, _ := endpoint.GetAddress() - host := endpoint.DNSName - - // Create the health check - output, err := c.client.CreateHealthCheck(&route53.CreateHealthCheckInput{ - - CallerReference: callerReference(spec.Id), - - HealthCheckConfig: &route53.HealthCheckConfig{ - IPAddress: &address, - FullyQualifiedDomainName: &host, - Port: spec.Port, - ResourcePath: &spec.Path, - Type: healthCheckType(spec.Protocol), - FailureThreshold: spec.FailureThreshold, - }, - }) - if err != nil { - return nil, err - } - - // Add the tag to identify it - _, err = c.client.ChangeTagsForResourceWithContext(ctx, &route53.ChangeTagsForResourceInput{ - AddTags: []*route53.Tag{ - { - Key: aws.String(idTag), - Value: aws.String(spec.Id), - }, - { - Key: aws.String("Name"), - Value: &spec.Name, - }, - }, - ResourceId: output.HealthCheck.Id, - ResourceType: aws.String(route53.TagResourceTypeHealthcheck), - }) - if err != nil { - return nil, err - } - - return output.HealthCheck, nil -} - -func (r *Route53HealthCheckReconciler) updateHealthCheck(ctx context.Context, spec dns.HealthCheckSpec, endpoint *v1alpha1.Endpoint, healthCheck *route53.HealthCheck) (dns.HealthCheckReconciliationResult, error) { - diff := healthCheckDiff(healthCheck, spec, endpoint) - if diff == nil { - return dns.HealthCheckNoop, nil - } - - log.Log.Info("Updating health check", "diff", *diff) - - _, err := r.client.UpdateHealthCheckWithContext(ctx, diff) - if err != nil { - return dns.HealthCheckFailed, err - } - - return dns.HealthCheckUpdated, nil -} - -// healthCheckDiff creates a `UpdateHealthCheckInput` object with the fields to -// update on healthCheck based on the given spec. -// If the health check matches the spec, returns `nil` -func healthCheckDiff(healthCheck *route53.HealthCheck, spec dns.HealthCheckSpec, endpoint *v1alpha1.Endpoint) *route53.UpdateHealthCheckInput { - var result *route53.UpdateHealthCheckInput - - // "Lazily" set the value for result only once and only when there is - // a change, to ensure that it's nil if there's no change - diff := func() *route53.UpdateHealthCheckInput { - if result == nil { - result = &route53.UpdateHealthCheckInput{ - HealthCheckId: healthCheck.Id, - } - } - - return result - } - - if !valuesEqual(&endpoint.DNSName, healthCheck.HealthCheckConfig.FullyQualifiedDomainName) { - diff().FullyQualifiedDomainName = &endpoint.DNSName - } - - address, _ := endpoint.GetAddress() - if !valuesEqual(&address, healthCheck.HealthCheckConfig.IPAddress) { - diff().IPAddress = &address - } - if !valuesEqualWithDefault(&spec.Path, healthCheck.HealthCheckConfig.ResourcePath, defaultHealthCheckPath) { - diff().ResourcePath = &spec.Path - } - if !valuesEqualWithDefault(spec.Port, healthCheck.HealthCheckConfig.Port, defaultHealthCheckPort) { - diff().Port = spec.Port - } - if !valuesEqualWithDefault(spec.FailureThreshold, healthCheck.HealthCheckConfig.FailureThreshold, defaultHealthCheckFailureThreshold) { - diff().FailureThreshold = spec.FailureThreshold - } - - return result -} - -func init() { - sid := xid.New() - callerReference = func(s string) *string { - return aws.String(fmt.Sprintf("%s.%s", s, sid)) - } -} - -func healthCheckType(protocol *dns.HealthCheckProtocol) *string { - if protocol == nil { - return nil - } - - switch *protocol { - case dns.HealthCheckProtocolHTTP: - return aws.String(route53.HealthCheckTypeHttp) - - case dns.HealthCheckProtocolHTTPS: - return aws.String(route53.HealthCheckTypeHttps) - } - - return nil -} - -func valuesEqual[T comparable](ptr1, ptr2 *T) bool { - if (ptr1 == nil && ptr2 != nil) || (ptr1 != nil && ptr2 == nil) { - return false - } - if ptr1 == nil && ptr2 == nil { - return true - } - - return *ptr1 == *ptr2 -} - -func valuesEqualWithDefault[T comparable](ptr1, ptr2 *T, defaultValue T) bool { - value1 := defaultValue - if ptr1 != nil { - value1 = *ptr1 - } - - value2 := defaultValue - if ptr2 != nil { - value2 = *ptr2 - } - - return value1 == value2 -} - -func getHealthCheckId(endpoint *v1alpha1.Endpoint) (string, bool) { - return endpoint.GetProviderSpecific(ProviderSpecificHealthCheckID) -} diff --git a/pkg/dns/aws/health_test.go b/pkg/dns/aws/health_test.go deleted file mode 100644 index e5d4afa37..000000000 --- a/pkg/dns/aws/health_test.go +++ /dev/null @@ -1,378 +0,0 @@ -//go:build unit - -package aws - -import ( - "context" - "fmt" - "testing" - - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/route53" - "github.com/aws/aws-sdk-go/service/route53/route53iface" - - "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/slice" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" -) - -func TestHealthCheckReconcile(t *testing.T) { - testCases := []struct { - name string - - spec dns.HealthCheckSpec - endpoint *v1alpha1.Endpoint - existingHealthChecks []*mockHealthCheck - - assertion func(dns.HealthCheckResult, error, *v1alpha1.Endpoint, *mockRoute53API) error - }{ - { - name: "New health check created", - - spec: dns.HealthCheckSpec{ - Name: "test-health-check", - }, - endpoint: &v1alpha1.Endpoint{}, - existingHealthChecks: []*mockHealthCheck{ - { - HealthCheck: &route53.HealthCheck{ - Id: ptrTo("test-0"), - }, - }, - }, - - assertion: func(hcr dns.HealthCheckResult, err error, e *v1alpha1.Endpoint, mra *mockRoute53API) error { - if hcr.Result != dns.HealthCheckCreated { - return fmt.Errorf("unexpected result. Expected Created, but got %s", hcr.Result) - } - if err != nil { - return fmt.Errorf("unexpected error %v", err) - } - healthCheckId, ok := e.GetProviderSpecific(ProviderSpecificHealthCheckID) - if !ok { - return fmt.Errorf("expected provider specific to be set") - } - - if healthCheckId != "test-1" { - return fmt.Errorf("expected health check id to be test-1, but got %s", healthCheckId) - } - if len(mra.healthChecks) != 2 { - return fmt.Errorf("expected 2 health checks after update, got %v", mra.healthChecks) - } - - return nil - }, - }, - { - name: "Update existing health check", - - spec: dns.HealthCheckSpec{ - Port: ptrTo(int64(443)), - Id: "test-0", - Path: "/", - }, - endpoint: &v1alpha1.Endpoint{ - ProviderSpecific: v1alpha1.ProviderSpecific{ - { - Name: ProviderSpecificHealthCheckID, - Value: "test-0", - }, - }, - }, - existingHealthChecks: []*mockHealthCheck{ - { - HealthCheck: &route53.HealthCheck{ - Id: ptrTo("test-0"), - HealthCheckConfig: &route53.HealthCheckConfig{ - Port: ptrTo(int64(8000)), - }, - }, - }, - { - HealthCheck: &route53.HealthCheck{ - Id: ptrTo("test-1"), - }, - }, - }, - assertion: func(hcr dns.HealthCheckResult, err error, e *v1alpha1.Endpoint, mra *mockRoute53API) error { - if err != nil { - return fmt.Errorf("unexpected errror %v", err) - } - if hcr.Result != dns.HealthCheckUpdated { - return fmt.Errorf("unexpected result. Expected Updated, got %v", hcr) - - } - if len(mra.healthChecks) != 2 { - return fmt.Errorf("expected 2 health checks after update, got %v", mra.healthChecks) - } - - return nil - }, - }, - { - name: "Existing health check not updated", - - spec: dns.HealthCheckSpec{ - Port: ptrTo(int64(443)), - Id: "test-0", - Path: "/", - }, - endpoint: &v1alpha1.Endpoint{ - DNSName: "test.example.com", - Targets: v1alpha1.Targets{"0.0.0.0"}, - SetIdentifier: "0.0.0.0", - ProviderSpecific: v1alpha1.ProviderSpecific{ - { - Name: ProviderSpecificHealthCheckID, - Value: "test-0", - }, - }, - }, - existingHealthChecks: []*mockHealthCheck{ - { - HealthCheck: &route53.HealthCheck{ - Id: ptrTo("test-0"), - HealthCheckConfig: &route53.HealthCheckConfig{ - Port: ptrTo(int64(443)), - ResourcePath: ptrTo("/"), - IPAddress: ptrTo("0.0.0.0"), - FullyQualifiedDomainName: ptrTo("test.example.com"), - }, - }, - }, - { - HealthCheck: &route53.HealthCheck{ - Id: ptrTo("test-1"), - }, - }, - }, - assertion: func(hcr dns.HealthCheckResult, err error, e *v1alpha1.Endpoint, mra *mockRoute53API) error { - if err != nil { - return fmt.Errorf("unexpected errror %v", err) - } - if hcr.Result != dns.HealthCheckNoop { - return fmt.Errorf("unexpected result. Expected Noop, got %v", hcr) - - } - if len(mra.healthChecks) != 2 { - return fmt.Errorf("expected 2 health checks after update, got %v", mra.healthChecks) - } - - return nil - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - client := &mockRoute53API{ - healthChecks: testCase.existingHealthChecks, - } - reconciler := NewRoute53HealthCheckReconciler(client) - - result, reconcileErr := reconciler.Reconcile(context.TODO(), testCase.spec, testCase.endpoint) - if testErr := testCase.assertion(result, reconcileErr, testCase.endpoint, client); testErr != nil { - t.Fatal(testErr) - } - }) - } -} - -func TestHealthCheckDelete(t *testing.T) { - testCases := []struct { - name string - - endpoint *v1alpha1.Endpoint - existingHealthChecks []*mockHealthCheck - - assertion func(dns.HealthCheckResult, error, *v1alpha1.Endpoint, *mockRoute53API) error - }{ - { - name: "Test case deleted", - - endpoint: &v1alpha1.Endpoint{ - ProviderSpecific: v1alpha1.ProviderSpecific{ - { - Name: ProviderSpecificHealthCheckID, - Value: "test-1", - }, - }, - }, - existingHealthChecks: []*mockHealthCheck{ - { - HealthCheck: &route53.HealthCheck{ - Id: ptrTo("test-0"), - }, - }, - { - HealthCheck: &route53.HealthCheck{ - Id: ptrTo("test-1"), - }, - }, - }, - - assertion: func(hcr dns.HealthCheckResult, err error, e *v1alpha1.Endpoint, mra *mockRoute53API) error { - if err != nil { - return fmt.Errorf("unexpected error %v", err) - } - if hcr.Result != dns.HealthCheckDeleted { - return fmt.Errorf("unexpected result. Expected Deleted, got %s", hcr.Result) - } - healthCheckID, ok := e.GetProviderSpecific(ProviderSpecificHealthCheckID) - if ok { - return fmt.Errorf("expected provider specific %s to be removed, but got %s", ProviderSpecificHealthCheckID, healthCheckID) - } - if len(mra.healthChecks) != 1 { - return fmt.Errorf("expected number of remaining health checks to be 1 but got %v", mra.healthChecks) - } - - return nil - }, - }, - - { - name: "Test case not found", - - endpoint: &v1alpha1.Endpoint{ - ProviderSpecific: v1alpha1.ProviderSpecific{}, - }, - existingHealthChecks: []*mockHealthCheck{ - { - HealthCheck: &route53.HealthCheck{ - Id: ptrTo("test-0"), - }, - }, - }, - - assertion: func(hcr dns.HealthCheckResult, err error, e *v1alpha1.Endpoint, mra *mockRoute53API) error { - if err != nil { - return fmt.Errorf("unexpected error %v", err) - } - if hcr.Result != dns.HealthCheckNoop { - return fmt.Errorf("unexpected result. Expected Noop, got %s", hcr.Result) - } - healthCheckID, ok := e.GetProviderSpecific(ProviderSpecificHealthCheckID) - if ok { - return fmt.Errorf("expected provider specific %s to be removed, but got %s", ProviderSpecificHealthCheckID, healthCheckID) - } - if len(mra.healthChecks) != 1 { - return fmt.Errorf("expected number of remaining health checks to be 1 but got %v", mra.healthChecks) - } - - return nil - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - client := &mockRoute53API{ - healthChecks: testCase.existingHealthChecks, - } - reconciler := NewRoute53HealthCheckReconciler(client) - - result, reconcileErr := reconciler.Delete(context.TODO(), testCase.endpoint) - if testErr := testCase.assertion(result, reconcileErr, testCase.endpoint, client); testErr != nil { - t.Fatal(testErr) - } - }) - } -} - -type mockRoute53API struct { - unimplementedRoute53 - healthChecks []*mockHealthCheck -} - -type mockHealthCheck struct { - *route53.HealthCheck - tags []*route53.Tag -} - -func (m *mockRoute53API) ChangeTagsForResourceWithContext(_ context.Context, i *route53.ChangeTagsForResourceInput, _ ...request.Option) (*route53.ChangeTagsForResourceOutput, error) { - healthCheck, ok := slice.Find(m.healthChecks, func(h *mockHealthCheck) bool { - return *h.Id == *i.ResourceId - }) - if !ok { - return &route53.ChangeTagsForResourceOutput{}, nil - } - - healthCheck.tags = append(healthCheck.tags, i.AddTags...) - return &route53.ChangeTagsForResourceOutput{}, nil -} - -func (m *mockRoute53API) CreateHealthCheck(input *route53.CreateHealthCheckInput) (*route53.CreateHealthCheckOutput, error) { - return m.CreateHealthCheckWithContext(context.TODO(), input) -} - -func (m *mockRoute53API) CreateHealthCheckWithContext(_ context.Context, i *route53.CreateHealthCheckInput, _ ...request.Option) (*route53.CreateHealthCheckOutput, error) { - healthCheck := &route53.HealthCheck{ - HealthCheckConfig: i.HealthCheckConfig, - Id: ptrTo(fmt.Sprintf("test-%d", len(m.healthChecks))), - } - - m.healthChecks = append(m.healthChecks, &mockHealthCheck{ - HealthCheck: healthCheck, - tags: []*route53.Tag{}, - }) - - return &route53.CreateHealthCheckOutput{ - HealthCheck: healthCheck, - }, nil -} - -func (m *mockRoute53API) DeleteHealthCheck(i *route53.DeleteHealthCheckInput) (*route53.DeleteHealthCheckOutput, error) { - return m.DeleteHealthCheckWithContext(context.TODO(), i) -} - -func (m *mockRoute53API) DeleteHealthCheckWithContext(_ context.Context, i *route53.DeleteHealthCheckInput, _ ...request.Option) (*route53.DeleteHealthCheckOutput, error) { - m.healthChecks = slice.Filter(m.healthChecks, func(h *mockHealthCheck) bool { - return *h.Id == *i.HealthCheckId - }) - return &route53.DeleteHealthCheckOutput{}, nil -} - -func (m *mockRoute53API) GetHealthCheck(i *route53.GetHealthCheckInput) (*route53.GetHealthCheckOutput, error) { - return m.GetHealthCheckWithContext(context.TODO(), i) -} - -func (m *mockRoute53API) GetHealthCheckWithContext(_ context.Context, i *route53.GetHealthCheckInput, _ ...request.Option) (*route53.GetHealthCheckOutput, error) { - healthCheck, ok := slice.Find(m.healthChecks, func(hc *mockHealthCheck) bool { - return *i.HealthCheckId == *hc.Id - }) - - var result *route53.HealthCheck = nil - if ok { - result = healthCheck.HealthCheck - } - - return &route53.GetHealthCheckOutput{ - HealthCheck: result, - }, nil -} - -func (m *mockRoute53API) UpdateHealthCheck(i *route53.UpdateHealthCheckInput) (*route53.UpdateHealthCheckOutput, error) { - return m.UpdateHealthCheckWithContext(context.TODO(), i) -} - -// UpdateHealthCheckWithContext implements route53iface.Route53API -func (m *mockRoute53API) UpdateHealthCheckWithContext(_ context.Context, i *route53.UpdateHealthCheckInput, _ ...request.Option) (*route53.UpdateHealthCheckOutput, error) { - healthCheck, ok := slice.Find(m.healthChecks, func(h *mockHealthCheck) bool { - return *h.Id == *i.HealthCheckId - }) - if !ok { - return &route53.UpdateHealthCheckOutput{}, nil - } - - healthCheck.HealthCheckConfig.FailureThreshold = i.FailureThreshold - healthCheck.HealthCheckConfig.Port = i.Port - healthCheck.HealthCheckConfig.IPAddress = i.IPAddress - - return &route53.UpdateHealthCheckOutput{HealthCheck: healthCheck.HealthCheck}, nil -} - -var _ route53iface.Route53API = &mockRoute53API{} - -func ptrTo[T any](value T) *T { - return &value -} diff --git a/pkg/dns/dns.go b/pkg/dns/dns.go deleted file mode 100644 index 7bc69f7c3..000000000 --- a/pkg/dns/dns.go +++ /dev/null @@ -1,98 +0,0 @@ -/* -Copyright 2022 The MultiCluster Traffic Controller Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package dns - -import ( - "context" - "errors" - "regexp" - - "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" -) - -const ( - DefaultTTL = 60 - DefaultCnameTTL = 300 - ProviderSpecificWeight = "weight" - ProviderSpecificGeoCode = "geo-code" -) - -type DNSProviderFactory func(ctx context.Context, managedZone *v1alpha1.ManagedZone) (Provider, error) - -// Provider knows how to manage DNS zones only as pertains to routing. -type Provider interface { - - // Ensure will create or update record. - Ensure(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error - - // Delete will delete record. - Delete(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error - - // Ensure will create or update a managed zone, returns an array of NameServers for that zone. - EnsureManagedZone(managedZone *v1alpha1.ManagedZone) (ManagedZoneOutput, error) - - // Delete will delete a managed zone. - DeleteManagedZone(managedZone *v1alpha1.ManagedZone) error - - // Get an instance of HealthCheckReconciler for this provider - HealthCheckReconciler() HealthCheckReconciler - - ProviderSpecific() ProviderSpecificLabels -} - -type ProviderSpecificLabels struct { - Weight string - HealthCheckID string -} - -type ManagedZoneOutput struct { - ID string - NameServers []*string - RecordCount int64 -} - -var _ Provider = &FakeProvider{} - -type FakeProvider struct{} - -func (*FakeProvider) Ensure(dnsRecord *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error { - return nil -} -func (*FakeProvider) Delete(dnsRecord *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error { - return nil -} -func (*FakeProvider) EnsureManagedZone(managedZone *v1alpha1.ManagedZone) (ManagedZoneOutput, error) { - return ManagedZoneOutput{}, nil -} -func (*FakeProvider) DeleteManagedZone(managedZone *v1alpha1.ManagedZone) error { return nil } - -func (*FakeProvider) HealthCheckReconciler() HealthCheckReconciler { - return &FakeHealthCheckReconciler{} -} -func (*FakeProvider) ProviderSpecific() ProviderSpecificLabels { - return ProviderSpecificLabels{ - Weight: "weight", - HealthCheckID: "fake/health-check-id", - } -} - -// SanitizeError removes request specific data from error messages in order to make them consistent across multiple similar requests to the provider. e.g AWS SDK Request ids `request id: 051c860b-9b30-4c19-be1a-1280c3e9fdc4` -func SanitizeError(err error) error { - re := regexp.MustCompile(`request id: [^\s]+`) - sanitizedErr := re.ReplaceAllString(err.Error(), "") - return errors.New(sanitizedErr) -} diff --git a/pkg/dns/dnsprovider/dnsProvider.go b/pkg/dns/dnsprovider/dnsProvider.go deleted file mode 100644 index c2cf87b08..000000000 --- a/pkg/dns/dnsprovider/dnsProvider.go +++ /dev/null @@ -1,65 +0,0 @@ -package dnsprovider - -import ( - "context" - "fmt" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/aws" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/google" -) - -var errUnsupportedProvider = fmt.Errorf("provider type given is not supported") - -type providerFactory struct { - client.Client -} - -func NewProvider(c client.Client) *providerFactory { - - return &providerFactory{ - Client: c, - } -} - -// depending on the provider type specified in the form of a custom secret type https://kubernetes.io/docs/concepts/configuration/secret/#secret-types in the dnsprovider secret it returns a dnsprovider. -func (p *providerFactory) DNSProviderFactory(ctx context.Context, managedZone *v1alpha1.ManagedZone) (dns.Provider, error) { - providerSecret := &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: managedZone.Spec.SecretRef.Name, - Namespace: managedZone.Namespace, // must be in same namespace as ManagedZone - }} - - if err := p.Client.Get(ctx, client.ObjectKeyFromObject(providerSecret), providerSecret); err != nil { - return nil, err - } - - switch providerSecret.Type { - case "kuadrant.io/aws": - dnsProvider, err := aws.NewProviderFromSecret(providerSecret) - if err != nil { - return nil, fmt.Errorf("unable to create AWS dns provider from secret: %v", err) - } - log.Log.V(1).Info("Route53 provider created", "managed zone:", managedZone.Name) - - return dnsProvider, nil - case "kuadrant.io/gcp": - dnsProvider, err := google.NewProviderFromSecret(ctx, providerSecret) - if err != nil { - return nil, fmt.Errorf("unable to create GCP dns provider from secret: %v", err) - } - log.Log.V(1).Info("Google provider created", "managed zone:", managedZone.Name) - - return dnsProvider, nil - - default: - return nil, errUnsupportedProvider - } - -} diff --git a/pkg/dns/health.go b/pkg/dns/health.go deleted file mode 100644 index 0f7d47349..000000000 --- a/pkg/dns/health.go +++ /dev/null @@ -1,121 +0,0 @@ -package dns - -import ( - "context" - "reflect" - "sync" - - "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" -) - -type HealthCheckReconciler interface { - Reconcile(ctx context.Context, spec HealthCheckSpec, endpoint *v1alpha1.Endpoint) (HealthCheckResult, error) - - Delete(ctx context.Context, endpoint *v1alpha1.Endpoint) (HealthCheckResult, error) -} - -type HealthCheckSpec struct { - Id string - Name string - Port *int64 - FailureThreshold *int64 - Protocol *HealthCheckProtocol - - Path string -} - -type HealthCheckResult struct { - Result HealthCheckReconciliationResult - Message string -} - -func NewHealthCheckResult(result HealthCheckReconciliationResult, message string) HealthCheckResult { - return HealthCheckResult{ - Result: result, - Message: message, - } -} - -type HealthCheckReconciliationResult string - -const ( - HealthCheckCreated HealthCheckReconciliationResult = "Created" - HealthCheckUpdated HealthCheckReconciliationResult = "Updated" - HealthCheckDeleted HealthCheckReconciliationResult = "Deleted" - HealthCheckNoop HealthCheckReconciliationResult = "Noop" - HealthCheckFailed HealthCheckReconciliationResult = "Failed" -) - -type HealthCheckProtocol string - -const HealthCheckProtocolHTTP HealthCheckProtocol = "HTTP" -const HealthCheckProtocolHTTPS HealthCheckProtocol = "HTTPS" - -type FakeHealthCheckReconciler struct{} - -func (*FakeHealthCheckReconciler) Reconcile(ctx context.Context, _ HealthCheckSpec, _ *v1alpha1.Endpoint) (HealthCheckResult, error) { - return HealthCheckResult{HealthCheckCreated, ""}, nil -} - -func (*FakeHealthCheckReconciler) Delete(ctx context.Context, _ *v1alpha1.Endpoint) (HealthCheckResult, error) { - return HealthCheckResult{HealthCheckDeleted, ""}, nil -} - -var _ HealthCheckReconciler = &FakeHealthCheckReconciler{} - -type CachedHealthCheckReconciler struct { - reconciler HealthCheckReconciler - provider Provider - - syncCache *sync.Map -} - -var _ HealthCheckReconciler = &CachedHealthCheckReconciler{} - -func NewCachedHealthCheckReconciler(provider Provider, reconciler HealthCheckReconciler) *CachedHealthCheckReconciler { - return &CachedHealthCheckReconciler{ - reconciler: reconciler, - provider: provider, - syncCache: &sync.Map{}, - } -} - -// Delete implements HealthCheckReconciler -func (r *CachedHealthCheckReconciler) Delete(ctx context.Context, endpoint *v1alpha1.Endpoint) (HealthCheckResult, error) { - id, ok := r.getHealthCheckID(endpoint) - if !ok { - return NewHealthCheckResult(HealthCheckNoop, ""), nil - } - - defer r.syncCache.Delete(id) - return r.reconciler.Delete(ctx, endpoint) -} - -// Reconcile implements HealthCheckReconciler -func (r *CachedHealthCheckReconciler) Reconcile(ctx context.Context, spec HealthCheckSpec, endpoint *v1alpha1.Endpoint) (HealthCheckResult, error) { - id, ok := r.getHealthCheckID(endpoint) - if !ok { - return r.reconciler.Reconcile(ctx, spec, endpoint) - } - - // Update the cache with the new spec - defer r.syncCache.Store(id, spec) - - // If the health heck is not cached, delegate the reconciliation - existingSpec, ok := r.syncCache.Load(id) - if !ok { - return r.reconciler.Reconcile(ctx, spec, endpoint) - } - - // If the spec is unchanged, return Noop - if reflect.DeepEqual(spec, existingSpec.(HealthCheckSpec)) { - return NewHealthCheckResult(HealthCheckNoop, "Spec unchanged"), nil - } - - // Otherwise, delegate the reconciliation - return r.reconciler.Reconcile(ctx, spec, endpoint) -} - -func (r *CachedHealthCheckReconciler) getHealthCheckID(endpoint *v1alpha1.Endpoint) (string, bool) { - return endpoint.GetProviderSpecific(r.provider.ProviderSpecific().HealthCheckID) -} diff --git a/pkg/dns/aws/dns.go b/pkg/dns/provider/aws/aws.go similarity index 90% rename from pkg/dns/aws/dns.go rename to pkg/dns/provider/aws/aws.go index 97517163c..957dc5922 100644 --- a/pkg/dns/aws/dns.go +++ b/pkg/dns/provider/aws/aws.go @@ -17,6 +17,7 @@ limitations under the License. package aws import ( + "context" "fmt" "strconv" "time" @@ -32,7 +33,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" ) const ( @@ -46,13 +47,12 @@ const ( type Route53DNSProvider struct { client *InstrumentedRoute53 logger logr.Logger - - healthCheckReconciler dns.HealthCheckReconciler + ctx context.Context } -var _ dns.Provider = &Route53DNSProvider{} +var _ provider.Provider = &Route53DNSProvider{} -func NewProviderFromSecret(s *v1.Secret) (*Route53DNSProvider, error) { +func NewProviderFromSecret(ctx context.Context, s *v1.Secret) (provider.Provider, error) { config := aws.NewConfig() sessionOpts := session.Options{ @@ -75,6 +75,7 @@ func NewProviderFromSecret(s *v1.Secret) (*Route53DNSProvider, error) { p := &Route53DNSProvider{ client: &InstrumentedRoute53{route53.New(sess, config)}, logger: log.Log.WithName("aws-route53").WithValues("region", config.Region), + ctx: ctx, } if err := validateServiceEndpoints(p); err != nil { @@ -99,7 +100,7 @@ func (p *Route53DNSProvider) Delete(record *v1alpha1.DNSRecord, managedZone *v1a return p.change(record, managedZone, deleteAction) } -func (p *Route53DNSProvider) EnsureManagedZone(zone *v1alpha1.ManagedZone) (dns.ManagedZoneOutput, error) { +func (p *Route53DNSProvider) EnsureManagedZone(zone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { var zoneID string if zone.Spec.ID != "" { zoneID = zone.Spec.ID @@ -107,7 +108,7 @@ func (p *Route53DNSProvider) EnsureManagedZone(zone *v1alpha1.ManagedZone) (dns. zoneID = zone.Status.ID } - var managedZoneOutput dns.ManagedZoneOutput + var managedZoneOutput provider.ManagedZoneOutput if zoneID != "" { getResp, err := p.client.GetHostedZone(&route53.GetHostedZoneInput{ @@ -167,24 +168,6 @@ func (p *Route53DNSProvider) DeleteManagedZone(zone *v1alpha1.ManagedZone) error return nil } -func (p *Route53DNSProvider) HealthCheckReconciler() dns.HealthCheckReconciler { - if p.healthCheckReconciler == nil { - p.healthCheckReconciler = dns.NewCachedHealthCheckReconciler( - p, - NewRoute53HealthCheckReconciler(p.client.route53), - ) - } - - return p.healthCheckReconciler -} - -func (*Route53DNSProvider) ProviderSpecific() dns.ProviderSpecificLabels { - return dns.ProviderSpecificLabels{ - Weight: dns.ProviderSpecificWeight, - HealthCheckID: ProviderSpecificHealthCheckID, - } -} - func (p *Route53DNSProvider) change(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone, action action) error { // Configure records. if len(record.Spec.Endpoints) == 0 { @@ -277,10 +260,10 @@ func (p *Route53DNSProvider) changeForEndpoint(endpoint *v1alpha1.Endpoint, acti if endpoint.SetIdentifier != "" { resourceRecordSet.SetIdentifier = aws.String(endpoint.SetIdentifier) } - if prop, ok := endpoint.GetProviderSpecificProperty(dns.ProviderSpecificWeight); ok { + if prop, ok := endpoint.GetProviderSpecificProperty(provider.ProviderSpecificWeight); ok { weight, err := strconv.ParseInt(prop.Value, 10, 64) if err != nil { - p.logger.Error(err, "Failed parsing value, using weight of 0", "weight", dns.ProviderSpecificWeight, "value", prop.Value) + p.logger.Error(err, "Failed parsing value, using weight of 0", "weight", provider.ProviderSpecificWeight, "value", prop.Value) weight = 0 } resourceRecordSet.Weight = aws.Int64(weight) @@ -298,8 +281,8 @@ func (p *Route53DNSProvider) changeForEndpoint(endpoint *v1alpha1.Endpoint, acti var geolocation = &route53.GeoLocation{} useGeolocation := false - if prop, ok := endpoint.GetProviderSpecificProperty(dns.ProviderSpecificGeoCode); ok { - if dns.IsISO3166Alpha2Code(prop.Value) || dns.GeoCode(prop.Value).IsWildcard() { + if prop, ok := endpoint.GetProviderSpecificProperty(provider.ProviderSpecificGeoCode); ok { + if provider.IsISO3166Alpha2Code(prop.Value) || prop.Value == "*" { geolocation.CountryCode = aws.String(prop.Value) } else { geolocation.ContinentCode = aws.String(prop.Value) @@ -338,3 +321,8 @@ func validateServiceEndpoints(provider *Route53DNSProvider) error { } return kerrors.NewAggregate(errs) } + +// Register this Provider with the provider factory +func init() { + provider.RegisterProvider("aws", NewProviderFromSecret) +} diff --git a/pkg/dns/aws/aws_test.go b/pkg/dns/provider/aws/aws_test.go similarity index 100% rename from pkg/dns/aws/aws_test.go rename to pkg/dns/provider/aws/aws_test.go diff --git a/pkg/dns/aws/client.go b/pkg/dns/provider/aws/client.go similarity index 78% rename from pkg/dns/aws/client.go rename to pkg/dns/provider/aws/client.go index cc9ebc03f..8851d62ec 100644 --- a/pkg/dns/aws/client.go +++ b/pkg/dns/provider/aws/client.go @@ -109,30 +109,6 @@ func (c *InstrumentedRoute53) DeleteHostedZone(input *route53.DeleteHostedZoneIn return } -func (c *InstrumentedRoute53) GetHealthCheckWithContext(ctx aws.Context, input *route53.GetHealthCheckInput, opts ...request.Option) (output *route53.GetHealthCheckOutput, err error) { - observe("GetHealthCheckWithContext", func() error { - output, err = c.route53.GetHealthCheckWithContext(ctx, input, opts...) - return err - }) - return -} - -func (c *InstrumentedRoute53) UpdateHealthCheckWithContext(ctx aws.Context, input *route53.UpdateHealthCheckInput, opts ...request.Option) (output *route53.UpdateHealthCheckOutput, err error) { - observe("UpdateHealthCheckWithContext", func() error { - output, err = c.route53.UpdateHealthCheckWithContext(ctx, input, opts...) - return err - }) - return -} - -func (c *InstrumentedRoute53) DeleteHealthCheckWithContext(ctx aws.Context, input *route53.DeleteHealthCheckInput, opts ...request.Option) (output *route53.DeleteHealthCheckOutput, err error) { - observe("DeleteHealthCheckWithContext", func() error { - output, err = c.route53.DeleteHealthCheckWithContext(ctx, input, opts...) - return err - }) - return -} - func (c *InstrumentedRoute53) ChangeTagsForResourceWithContext(ctx aws.Context, input *route53.ChangeTagsForResourceInput, opts ...request.Option) (output *route53.ChangeTagsForResourceOutput, err error) { observe("ChangeTagsForResourceWithContext", func() error { output, err = c.route53.ChangeTagsForResourceWithContext(ctx, input, opts...) diff --git a/pkg/dns/aws/metrics.go b/pkg/dns/provider/aws/metrics.go similarity index 100% rename from pkg/dns/aws/metrics.go rename to pkg/dns/provider/aws/metrics.go diff --git a/pkg/dns/provider/factory.go b/pkg/dns/provider/factory.go new file mode 100644 index 000000000..451559b66 --- /dev/null +++ b/pkg/dns/provider/factory.go @@ -0,0 +1,85 @@ +package provider + +import ( + "context" + "fmt" + "sync" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" +) + +var errUnsupportedProvider = fmt.Errorf("provider type given is not supported") + +// ProviderConstructor constructs a provider given a Secret resource and a Context. +// An error will be returned if the appropriate provider is not registered. +type ProviderConstructor func(context.Context, *v1.Secret) (Provider, error) + +var ( + constructors = make(map[string]ProviderConstructor) + constructorsLock sync.RWMutex +) + +// RegisterProvider will register a provider constructor, so it can be used within the application. +// 'name' should be unique, and should be used to identify this provider. +func RegisterProvider(name string, c ProviderConstructor) { + constructorsLock.Lock() + defer constructorsLock.Unlock() + constructors[name] = c +} + +// Factory is an interface that can be used to obtain Provider implementations. +// It determines which provider implementation to use by introspecting the given ProviderAccessor resource. +type Factory interface { + ProviderFor(context.Context, v1alpha1.ProviderAccessor) (Provider, error) +} + +// factory is the default Factory implementation +type factory struct { + client.Client +} + +// NewFactory returns a new provider factory with the given client. +func NewFactory(c client.Client) Factory { + return &factory{Client: c} +} + +// ProviderFor will return a Provider interface for the given ProviderAccessor secret. +// If the requested ProviderAccessor secret does not exist, an error will be returned. +func (f *factory) ProviderFor(ctx context.Context, pa v1alpha1.ProviderAccessor) (Provider, error) { + providerSecret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: pa.GetProviderRef().Name, + Namespace: pa.GetNamespace(), + }} + + if err := f.Client.Get(ctx, client.ObjectKeyFromObject(providerSecret), providerSecret); err != nil { + return nil, err + } + + providerType, err := nameForProviderSecret(providerSecret) + if err != nil { + return nil, err + } + + constructorsLock.RLock() + defer constructorsLock.RUnlock() + if constructor, ok := constructors[providerType]; ok { + return constructor(ctx, providerSecret) + } + + return nil, fmt.Errorf("provider '%s' not registered", providerType) +} + +func nameForProviderSecret(secret *v1.Secret) (string, error) { + switch secret.Type { + case "kuadrant.io/aws": + return "aws", nil + case "kuadrant.io/gcp": + return "google", nil + } + return "", errUnsupportedProvider +} diff --git a/pkg/dns/provider/fake/factory.go b/pkg/dns/provider/fake/factory.go new file mode 100644 index 000000000..7e45ef45d --- /dev/null +++ b/pkg/dns/provider/fake/factory.go @@ -0,0 +1,18 @@ +package fake + +import ( + "context" + + "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" +) + +type Factory struct { + ProviderForFunc func(ctx context.Context, pa v1alpha1.ProviderAccessor) (provider.Provider, error) +} + +var _ provider.Factory = &Factory{} + +func (f *Factory) ProviderFor(ctx context.Context, pa v1alpha1.ProviderAccessor) (provider.Provider, error) { + return f.ProviderForFunc(ctx, pa) +} diff --git a/pkg/dns/provider/fake/provider.go b/pkg/dns/provider/fake/provider.go new file mode 100644 index 000000000..51e2e9225 --- /dev/null +++ b/pkg/dns/provider/fake/provider.go @@ -0,0 +1,31 @@ +package fake + +import ( + "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" +) + +type Provider struct { + EnsureFunc func(*v1alpha1.DNSRecord, *v1alpha1.ManagedZone) error + DeleteFunc func(*v1alpha1.DNSRecord, *v1alpha1.ManagedZone) error + EnsureManagedZoneFunc func(*v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) + DeleteManagedZoneFunc func(*v1alpha1.ManagedZone) error +} + +var _ provider.Provider = &Provider{} + +func (p Provider) Ensure(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error { + return p.EnsureFunc(record, managedZone) +} + +func (p Provider) Delete(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error { + return p.DeleteFunc(record, managedZone) +} + +func (p Provider) EnsureManagedZone(managedZone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { + return p.EnsureManagedZoneFunc(managedZone) +} + +func (p Provider) DeleteManagedZone(managedZone *v1alpha1.ManagedZone) error { + return p.DeleteManagedZoneFunc(managedZone) +} diff --git a/pkg/dns/google/google.go b/pkg/dns/provider/google/google.go similarity index 92% rename from pkg/dns/google/google.go rename to pkg/dns/provider/google/google.go index a269d29c4..9369d3ee5 100644 --- a/pkg/dns/google/google.go +++ b/pkg/dns/provider/google/google.go @@ -34,7 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" ) type action string @@ -145,9 +145,9 @@ type GoogleDNSProvider struct { ctx context.Context } -var _ dns.Provider = &GoogleDNSProvider{} +var _ provider.Provider = &GoogleDNSProvider{} -func NewProviderFromSecret(ctx context.Context, s *v1.Secret) (*GoogleDNSProvider, error) { +func NewProviderFromSecret(ctx context.Context, s *v1.Secret) (provider.Provider, error) { if string(s.Data["GOOGLE"]) == "" || string(s.Data["PROJECT_ID"]) == "" { return nil, fmt.Errorf("GCP Provider credentials is empty") @@ -160,7 +160,7 @@ func NewProviderFromSecret(ctx context.Context, s *v1.Secret) (*GoogleDNSProvide var project = string(s.Data["PROJECT_ID"]) - provider := &GoogleDNSProvider{ + p := &GoogleDNSProvider{ logger: log.Log.WithName("google-dns").WithValues("project", project), project: project, dryRun: DryRun, @@ -172,7 +172,7 @@ func NewProviderFromSecret(ctx context.Context, s *v1.Secret) (*GoogleDNSProvide ctx: ctx, } - return provider, nil + return p, nil } // ManagedZones @@ -181,7 +181,7 @@ func (g *GoogleDNSProvider) DeleteManagedZone(managedZone *v1alpha1.ManagedZone) return g.managedZonesClient.Delete(g.project, managedZone.Status.ID).Do() } -func (g *GoogleDNSProvider) EnsureManagedZone(managedZone *v1alpha1.ManagedZone) (dns.ManagedZoneOutput, error) { +func (g *GoogleDNSProvider) EnsureManagedZone(managedZone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { var zoneID string if managedZone.Spec.ID != "" { @@ -198,7 +198,7 @@ func (g *GoogleDNSProvider) EnsureManagedZone(managedZone *v1alpha1.ManagedZone) return g.createManagedZone(managedZone) } -func (g *GoogleDNSProvider) createManagedZone(managedZone *v1alpha1.ManagedZone) (dns.ManagedZoneOutput, error) { +func (g *GoogleDNSProvider) createManagedZone(managedZone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { zoneID := strings.Replace(managedZone.Spec.DomainName, ".", "-", -1) zone := dnsv1.ManagedZone{ Name: zoneID, @@ -207,21 +207,21 @@ func (g *GoogleDNSProvider) createManagedZone(managedZone *v1alpha1.ManagedZone) } mz, err := g.managedZonesClient.Create(g.project, &zone).Do() if err != nil { - return dns.ManagedZoneOutput{}, err + return provider.ManagedZoneOutput{}, err } return g.toManagedZoneOutput(mz) } -func (g *GoogleDNSProvider) getManagedZone(zoneID string) (dns.ManagedZoneOutput, error) { +func (g *GoogleDNSProvider) getManagedZone(zoneID string) (provider.ManagedZoneOutput, error) { mz, err := g.managedZonesClient.Get(g.project, zoneID).Do() if err != nil { - return dns.ManagedZoneOutput{}, err + return provider.ManagedZoneOutput{}, err } return g.toManagedZoneOutput(mz) } -func (g *GoogleDNSProvider) toManagedZoneOutput(mz *dnsv1.ManagedZone) (dns.ManagedZoneOutput, error) { - var managedZoneOutput dns.ManagedZoneOutput +func (g *GoogleDNSProvider) toManagedZoneOutput(mz *dnsv1.ManagedZone) (provider.ManagedZoneOutput, error) { + var managedZoneOutput provider.ManagedZoneOutput zoneID := mz.Name var nameservers []*string @@ -250,15 +250,6 @@ func (g *GoogleDNSProvider) Delete(record *v1alpha1.DNSRecord, managedZone *v1al return g.updateRecord(record, managedZone.Status.ID, deleteAction) } -func (g *GoogleDNSProvider) HealthCheckReconciler() dns.HealthCheckReconciler { - // This can be ignored and likely removed as part of the provider-agnostic health check work - return &dns.FakeHealthCheckReconciler{} -} - -func (g *GoogleDNSProvider) ProviderSpecific() dns.ProviderSpecificLabels { - return dns.ProviderSpecificLabels{} -} - func (g *GoogleDNSProvider) updateRecord(dnsRecord *v1alpha1.DNSRecord, zoneID string, action action) error { // When updating records the Google DNS API expects you to delete any existing record and add the new one as part of // the same change request. The record to be deleted must match exactly what currently exists in the provider or the @@ -432,8 +423,8 @@ func toResourceRecordSets(allEndpoints []*v1alpha1.Endpoint) []*dnsv1.ResourceRe // and contain the same rrdata (weighted or geo), so we can just get that from the first endpoint in the list. ttl := int64(endpoints[0].RecordTTL) recordType := endpoints[0].RecordType - _, weighted := endpoints[0].GetProviderSpecificProperty(dns.ProviderSpecificWeight) - _, geoCode := endpoints[0].GetProviderSpecificProperty(dns.ProviderSpecificGeoCode) + _, weighted := endpoints[0].GetProviderSpecificProperty(provider.ProviderSpecificWeight) + _, geoCode := endpoints[0].GetProviderSpecificProperty(provider.ProviderSpecificGeoCode) record := &dnsv1.ResourceRecordSet{ Name: ensureTrailingDot(dnsName), @@ -461,7 +452,7 @@ func toResourceRecordSets(allEndpoints []*v1alpha1.Endpoint) []*dnsv1.ResourceRe record.Rrdatas = targets } if weighted { - weightProp, _ := ep.GetProviderSpecificProperty(dns.ProviderSpecificWeight) + weightProp, _ := ep.GetProviderSpecificProperty(provider.ProviderSpecificWeight) weight, err := strconv.ParseFloat(weightProp.Value, 64) if err != nil { weight = 0 @@ -473,9 +464,9 @@ func toResourceRecordSets(allEndpoints []*v1alpha1.Endpoint) []*dnsv1.ResourceRe record.RoutingPolicy.Wrr.Items = append(record.RoutingPolicy.Wrr.Items, item) } if geoCode { - geoCodeProp, _ := ep.GetProviderSpecificProperty(dns.ProviderSpecificGeoCode) + geoCodeProp, _ := ep.GetProviderSpecificProperty(provider.ProviderSpecificGeoCode) geoCodeValue := geoCodeProp.Value - targetIsDefaultGroup := strings.HasPrefix(ep.Targets[0], string(dns.DefaultGeo)) + targetIsDefaultGroup := strings.HasPrefix(ep.Targets[0], string(v1alpha1.DefaultGeo)) // GCP doesn't accept * as value for default geolocations like AWS does. // To ensure the dns chain doesn't break if a * is given we map the value to europe-west1 instead // We cant drop the record as the chain will break @@ -505,3 +496,8 @@ func ensureTrailingDot(hostname string) string { return strings.TrimSuffix(hostname, ".") + "." } + +// Register this Provider with the provider factory +func init() { + provider.RegisterProvider("google", NewProviderFromSecret) +} diff --git a/pkg/dns/google/google_test.go b/pkg/dns/provider/google/google_test.go similarity index 98% rename from pkg/dns/google/google_test.go rename to pkg/dns/provider/google/google_test.go index fc9e1ed84..6c86a7cc5 100644 --- a/pkg/dns/google/google_test.go +++ b/pkg/dns/provider/google/google_test.go @@ -13,7 +13,7 @@ import ( dnsv1 "google.golang.org/api/dns/v1" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" ) func TestGoogleDNSProvider_toManagedZoneOutput(t *testing.T) { @@ -61,7 +61,7 @@ func TestGoogleDNSProvider_toManagedZoneOutput(t *testing.T) { name string fields fields args args - want dns.ManagedZoneOutput + want provider.ManagedZoneOutput wantErr bool }{ @@ -79,7 +79,7 @@ func TestGoogleDNSProvider_toManagedZoneOutput(t *testing.T) { }, }, }, - want: dns.ManagedZoneOutput{ + want: provider.ManagedZoneOutput{ ID: "testname", NameServers: []*string{ aws.String("nameserver1"), @@ -103,7 +103,7 @@ func TestGoogleDNSProvider_toManagedZoneOutput(t *testing.T) { }, }, }, - want: dns.ManagedZoneOutput{ + want: provider.ManagedZoneOutput{ ID: "testname", NameServers: []*string{ aws.String("nameserver1"), diff --git a/pkg/dns/iso3166.go b/pkg/dns/provider/iso3166.go similarity index 99% rename from pkg/dns/iso3166.go rename to pkg/dns/provider/iso3166.go index adbd90254..85c955c2d 100644 --- a/pkg/dns/iso3166.go +++ b/pkg/dns/provider/iso3166.go @@ -1,4 +1,4 @@ -package dns +package provider import "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/slice" diff --git a/pkg/dns/provider/provider.go b/pkg/dns/provider/provider.go new file mode 100644 index 000000000..bacb973e4 --- /dev/null +++ b/pkg/dns/provider/provider.go @@ -0,0 +1,47 @@ +package provider + +import ( + "errors" + "regexp" + + "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" +) + +const ( + ProviderSpecificWeight = "weight" + ProviderSpecificGeoCode = "geo-code" +) + +// Provider knows how to manage DNS zones only as pertains to routing. +type Provider interface { + + // Ensure will create or update record. + Ensure(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error + + // Delete will delete record. + Delete(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error + + // Ensure will create or update a managed zone, returns an array of NameServers for that zone. + EnsureManagedZone(managedZone *v1alpha1.ManagedZone) (ManagedZoneOutput, error) + + // Delete will delete a managed zone. + DeleteManagedZone(managedZone *v1alpha1.ManagedZone) error +} + +type ProviderSpecificLabels struct { + Weight string + HealthCheckID string +} + +type ManagedZoneOutput struct { + ID string + NameServers []*string + RecordCount int64 +} + +// SanitizeError removes request specific data from error messages in order to make them consistent across multiple similar requests to the provider. e.g AWS SDK Request ids `request id: 051c860b-9b30-4c19-be1a-1280c3e9fdc4` +func SanitizeError(err error) error { + re := regexp.MustCompile(`request id: [^\s]+`) + sanitizedErr := re.ReplaceAllString(err.Error(), "") + return errors.New(sanitizedErr) +} diff --git a/pkg/dns/dns_test.go b/pkg/dns/provider/provider_test.go similarity index 97% rename from pkg/dns/dns_test.go rename to pkg/dns/provider/provider_test.go index 80985f7b6..367641204 100644 --- a/pkg/dns/dns_test.go +++ b/pkg/dns/provider/provider_test.go @@ -1,6 +1,6 @@ //go:build unit -package dns +package provider import ( "errors" diff --git a/test/gateway_integration/suite_test.go b/test/gateway_integration/suite_test.go index 7e2d30b21..a91dd7b1e 100644 --- a/test/gateway_integration/suite_test.go +++ b/test/gateway_integration/suite_test.go @@ -39,7 +39,6 @@ import ( "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" . "github.com/Kuadrant/multicluster-gateway-controller/pkg/controllers/gateway" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" "github.com/Kuadrant/multicluster-gateway-controller/pkg/placement" //+kubebuilder:scaffold:imports ) @@ -48,15 +47,12 @@ import ( // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. var ( - cfg *rest.Config - k8sClient client.Client - testEnv *envtest.Environment - ctx context.Context - cancel context.CancelFunc - logger logr.Logger - providerFactory = func(ctx context.Context, managedZone *v1alpha1.ManagedZone) (dns.Provider, error) { - return &dns.FakeProvider{}, nil - } + cfg *rest.Config + k8sClient client.Client + testEnv *envtest.Environment + ctx context.Context + cancel context.CancelFunc + logger logr.Logger ) func testClient() client.Client { return k8sClient } diff --git a/test/policy_integration/dnspolicy_controller_health_checks_test.go b/test/policy_integration/dnspolicy_controller_health_checks_test.go index 322e6a23f..133f6f80e 100644 --- a/test/policy_integration/dnspolicy_controller_health_checks_test.go +++ b/test/policy_integration/dnspolicy_controller_health_checks_test.go @@ -18,8 +18,7 @@ import ( gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/utils" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/common" testutil "github.com/Kuadrant/multicluster-gateway-controller/test/util" ) @@ -66,11 +65,11 @@ var _ = Describe("DNSPolicy Health Checks", func() { } gateway.Status.Addresses = []gatewayapiv1.GatewayStatusAddress{ { - Type: testutil.Pointer(utils.MultiClusterIPAddressType), + Type: testutil.Pointer(common.MultiClusterIPAddressType), Value: TestClusterNameOne + "/" + TestIPAddressOne, }, { - Type: testutil.Pointer(utils.MultiClusterIPAddressType), + Type: testutil.Pointer(common.MultiClusterIPAddressType), Value: TestClusterNameTwo + "/" + TestIPAddressTwo, }, } @@ -106,7 +105,7 @@ var _ = Describe("DNSPolicy Health Checks", func() { dnsPolicyBuilder = testutil.NewDNSPolicyBuilder("test-dns-policy", testNamespace) dnsPolicyBuilder.WithTargetGateway(TestGatewayName) - lbHash = dns.ToBase36hash(fmt.Sprintf("%s-%s", gateway.Name, gateway.Namespace)) + lbHash = common.ToBase36hash(fmt.Sprintf("%s-%s", gateway.Name, gateway.Namespace)) recordName = fmt.Sprintf("%s-%s", TestGatewayName, TestListenerNameOne) wildcardRecordName = fmt.Sprintf("%s-%s", TestGatewayName, TestListenerNameWildcard) }) diff --git a/test/policy_integration/dnspolicy_controller_multi_cluster_test.go b/test/policy_integration/dnspolicy_controller_multi_cluster_test.go index 2dd61d3d5..fc8bf36d6 100644 --- a/test/policy_integration/dnspolicy_controller_multi_cluster_test.go +++ b/test/policy_integration/dnspolicy_controller_multi_cluster_test.go @@ -17,8 +17,7 @@ import ( gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/utils" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/common" testutil "github.com/Kuadrant/multicluster-gateway-controller/test/util" ) @@ -65,11 +64,11 @@ var _ = Describe("DNSPolicy Multi Cluster", func() { } gateway.Status.Addresses = []gatewayapiv1.GatewayStatusAddress{ { - Type: testutil.Pointer(utils.MultiClusterIPAddressType), + Type: testutil.Pointer(common.MultiClusterIPAddressType), Value: TestClusterNameOne + "/" + TestIPAddressOne, }, { - Type: testutil.Pointer(utils.MultiClusterIPAddressType), + Type: testutil.Pointer(common.MultiClusterIPAddressType), Value: TestClusterNameTwo + "/" + TestIPAddressTwo, }, } @@ -105,7 +104,7 @@ var _ = Describe("DNSPolicy Multi Cluster", func() { dnsPolicyBuilder = testutil.NewDNSPolicyBuilder("test-dns-policy", testNamespace) dnsPolicyBuilder.WithTargetGateway(TestGatewayName) - lbHash = dns.ToBase36hash(fmt.Sprintf("%s-%s", gateway.Name, gateway.Namespace)) + lbHash = common.ToBase36hash(fmt.Sprintf("%s-%s", gateway.Name, gateway.Namespace)) recordName = fmt.Sprintf("%s-%s", TestGatewayName, TestListenerNameOne) wildcardRecordName = fmt.Sprintf("%s-%s", TestGatewayName, TestListenerNameWildcard) }) diff --git a/test/policy_integration/dnspolicy_controller_single_cluster_test.go b/test/policy_integration/dnspolicy_controller_single_cluster_test.go index be0a00c17..0b3282d22 100644 --- a/test/policy_integration/dnspolicy_controller_single_cluster_test.go +++ b/test/policy_integration/dnspolicy_controller_single_cluster_test.go @@ -15,7 +15,7 @@ import ( gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/common" testutil "github.com/Kuadrant/multicluster-gateway-controller/test/util" ) @@ -76,7 +76,7 @@ var _ = Describe("DNSPolicy Single Cluster", func() { dnsPolicyBuilder = testutil.NewDNSPolicyBuilder("test-dns-policy", testNamespace) dnsPolicyBuilder.WithTargetGateway(TestGatewayName) - lbHash = dns.ToBase36hash(fmt.Sprintf("%s-%s", gateway.Name, gateway.Namespace)) + lbHash = common.ToBase36hash(fmt.Sprintf("%s-%s", gateway.Name, gateway.Namespace)) recordName = fmt.Sprintf("%s-%s", TestGatewayName, TestListenerNameOne) wildcardRecordName = fmt.Sprintf("%s-%s", TestGatewayName, TestListenerNameWildcard) }) diff --git a/test/policy_integration/dnspolicy_controller_test.go b/test/policy_integration/dnspolicy_controller_test.go index 8755a41cd..2d77285c2 100644 --- a/test/policy_integration/dnspolicy_controller_test.go +++ b/test/policy_integration/dnspolicy_controller_test.go @@ -19,8 +19,8 @@ import ( "github.com/Kuadrant/multicluster-gateway-controller/pkg/_internal/conditions" "github.com/Kuadrant/multicluster-gateway-controller/pkg/apis/v1alpha1" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/common" . "github.com/Kuadrant/multicluster-gateway-controller/pkg/controllers/dnspolicy" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/utils" testutil "github.com/Kuadrant/multicluster-gateway-controller/test/util" ) @@ -150,7 +150,7 @@ var _ = Describe("DNSPolicy", func() { Value: TestClusterNameOne + "/" + TestIPAddressOne, }, { - Type: testutil.Pointer(utils.MultiClusterIPAddressType), + Type: testutil.Pointer(common.MultiClusterIPAddressType), Value: TestIPAddressTwo, }, } @@ -284,11 +284,11 @@ var _ = Describe("DNSPolicy", func() { gateway.Status.Addresses = []gatewayapiv1.GatewayStatusAddress{ { - Type: testutil.Pointer(utils.MultiClusterIPAddressType), + Type: testutil.Pointer(common.MultiClusterIPAddressType), Value: TestClusterNameOne + "/" + TestIPAddressOne, }, { - Type: testutil.Pointer(utils.MultiClusterIPAddressType), + Type: testutil.Pointer(common.MultiClusterIPAddressType), Value: TestClusterNameTwo + "/" + TestIPAddressTwo, }, } diff --git a/test/policy_integration/managedzone_controller_test.go b/test/policy_integration/managedzone_controller_test.go index e8f346e4f..d796e6d2d 100644 --- a/test/policy_integration/managedzone_controller_test.go +++ b/test/policy_integration/managedzone_controller_test.go @@ -41,7 +41,7 @@ var _ = Describe("ManagedZoneReconciler", func() { Spec: v1alpha1.ManagedZoneSpec{ ID: testutil.Domain, DomainName: testutil.Domain, - SecretRef: &v1alpha1.SecretRef{ + SecretRef: v1alpha1.ProviderRef{ Name: providerCredential, }, }, diff --git a/test/policy_integration/suite_test.go b/test/policy_integration/suite_test.go index 0b48c4685..5af5585fa 100644 --- a/test/policy_integration/suite_test.go +++ b/test/policy_integration/suite_test.go @@ -46,7 +46,8 @@ import ( . "github.com/Kuadrant/multicluster-gateway-controller/pkg/controllers/dnspolicy" . "github.com/Kuadrant/multicluster-gateway-controller/pkg/controllers/managedzone" . "github.com/Kuadrant/multicluster-gateway-controller/pkg/controllers/tlspolicy" - "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns" + "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider" + providerFake "github.com/Kuadrant/multicluster-gateway-controller/pkg/dns/provider/fake" "github.com/Kuadrant/multicluster-gateway-controller/pkg/health" //+kubebuilder:scaffold:imports ) @@ -55,14 +56,29 @@ import ( // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. var ( - cfg *rest.Config - k8sClient client.Client - testEnv *envtest.Environment - ctx context.Context - cancel context.CancelFunc - logger logr.Logger - providerFactory = func(ctx context.Context, managedZone *v1alpha1.ManagedZone) (dns.Provider, error) { - return &dns.FakeProvider{}, nil + cfg *rest.Config + k8sClient client.Client + testEnv *envtest.Environment + ctx context.Context + cancel context.CancelFunc + logger logr.Logger + dnsProviderFactory = &providerFake.Factory{ + ProviderForFunc: func(ctx context.Context, pa v1alpha1.ProviderAccessor) (provider.Provider, error) { + return &providerFake.Provider{ + EnsureFunc: func(record *v1alpha1.DNSRecord, zone *v1alpha1.ManagedZone) error { + return nil + }, + DeleteFunc: func(record *v1alpha1.DNSRecord, zone *v1alpha1.ManagedZone) error { + return nil + }, + EnsureManagedZoneFunc: func(zone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { + return provider.ManagedZoneOutput{}, nil + }, + DeleteManagedZoneFunc: func(zone *v1alpha1.ManagedZone) error { + return nil + }, + }, nil + }, } ) @@ -159,7 +175,7 @@ var _ = BeforeSuite(func() { TargetRefReconciler: reconcilers.TargetRefReconciler{ BaseReconciler: dnsPolicyBaseReconciler, }, - DNSProvider: providerFactory, + ProviderFactory: dnsProviderFactory, }).SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) @@ -177,9 +193,9 @@ var _ = BeforeSuite(func() { Expect(err).ToNot(HaveOccurred()) err = (&ManagedZoneReconciler{ - Client: k8sManager.GetClient(), - Scheme: k8sManager.GetScheme(), - DNSProvider: providerFactory, + Client: k8sManager.GetClient(), + Scheme: k8sManager.GetScheme(), + ProviderFactory: dnsProviderFactory, }).SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) diff --git a/test/util/test_dnspolicy_types.go b/test/util/test_dnspolicy_types.go index 958def82f..4a8961127 100644 --- a/test/util/test_dnspolicy_types.go +++ b/test/util/test_dnspolicy_types.go @@ -121,7 +121,7 @@ func NewManagedZoneBuilder(name, ns, domainName string) *ManagedZoneBuilder { ID: "1234", DomainName: domainName, Description: domainName, - SecretRef: &v1alpha1.SecretRef{ + SecretRef: v1alpha1.ProviderRef{ Name: "secretname", }, },