Skip to content

Commit

Permalink
add optional rootHost
Browse files Browse the repository at this point in the history
add validate call to publish
  • Loading branch information
maleck13 committed Mar 11, 2024
1 parent 41d07c2 commit 810ac73
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 4 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*.dll
*.so
*.dylib
*.env
bin/*
Dockerfile.cross

Expand All @@ -29,3 +30,4 @@ Dockerfile.cross
tmp

config/local-setup/**/*.env
local
25 changes: 25 additions & 0 deletions api/v1alpha1/dnsrecord_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ import (

// DNSRecordSpec defines the desired state of DNSRecord
type DNSRecordSpec struct {

// rootHost is the single root for all endpoints in a DNSRecord.
//If rootHost is set, it is expected all defined endpoints are children of or equal to this rootHost
// +optional
RootHost *string `json:"rootHost,omitempty"`
// +kubebuilder:validation:Required
// +required
ManagedZoneRef *ManagedZoneReference `json:"managedZone,omitempty"`
Expand Down Expand Up @@ -104,6 +109,12 @@ const (
// GetRootDomain returns the shortest domain that is shared across all spec.Endpoints dns names.
// Validates that all endpoints share an equal root domain and returns an error if they don't.
func (s *DNSRecord) GetRootDomain() (string, error) {
if err := s.Validate(); err != nil {
return "", err
}
if s.Spec.RootHost != nil {
return *s.Spec.RootHost, nil
}
domain := ""
dnsNames := []string{}
for idx := range s.Spec.Endpoints {
Expand All @@ -128,6 +139,20 @@ func (s *DNSRecord) GetRootDomain() (string, error) {
return domain, nil
}

func (s *DNSRecord) Validate() error {
if s.Spec.RootHost != nil {
if len(strings.Split(*s.Spec.RootHost, ".")) <= 1 {
return fmt.Errorf("invalid domain format no tld discovered")
}
for _, ep := range s.Spec.Endpoints {
if !strings.HasSuffix(ep.DNSName, *s.Spec.RootHost) {
return fmt.Errorf("invalid endpoint discovered %s all endpoints should be equal to or end with the rootHost %s", ep.DNSName, *s.Spec.RootHost)
}
}
}
return nil
}

func init() {
SchemeBuilder.Register(&DNSRecord{}, &DNSRecordList{})
}
77 changes: 75 additions & 2 deletions api/v1alpha1/dnsrecord_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@ import (
)

func TestDNSRecord_GetRootDomain(t *testing.T) {
var (
rootTestExample = "test.example.com"
example = "example.com"
)
tests := []struct {
name string
rootHost *string
dnsNames []string
want string
wantErr bool
}{
{
name: "single endpoint",
name: "single endpoint",
rootHost: &rootTestExample,
dnsNames: []string{
"test.example.com",
},
Expand All @@ -40,12 +46,34 @@ func TestDNSRecord_GetRootDomain(t *testing.T) {
wantErr: true,
},
{
name: "multiple endpoints mismatching",
rootHost: &example,
name: "multiple endpoints",
dnsNames: []string{
"foo.bar.test.example.com",
"bar.test.example.com",
"baz.example.com",
},
want: "example.com",
wantErr: false,
},
{
rootHost: &example,
name: "multiple endpoints mismatching",
dnsNames: []string{
"foo.bar.test.other.com",
"bar.test.example.com",
"baz.example.com",
},
want: "",
wantErr: true,
},
{
name: "multiple endpoints no rootHost",
dnsNames: []string{
"foo.bar.test.other.com",
"bar.test.example.com",
"baz.example.com",
},
want: "",
wantErr: true,
},
Expand All @@ -65,6 +93,9 @@ func TestDNSRecord_GetRootDomain(t *testing.T) {
Endpoints: []*endpoint.Endpoint{},
},
}
if tt.rootHost != nil {
s.Spec.RootHost = tt.rootHost
}
for idx := range tt.dnsNames {
s.Spec.Endpoints = append(s.Spec.Endpoints, &endpoint.Endpoint{DNSName: tt.dnsNames[idx]})
}
Expand All @@ -79,3 +110,45 @@ func TestDNSRecord_GetRootDomain(t *testing.T) {
})
}
}

func TestValidate(t *testing.T) {
tests := []struct {
name string
rootHost string
dnsNames []string
wantErr bool
}{
{
name: "invalid domain",
rootHost: "example",
wantErr: true,
},
{
name: "valid domain",
rootHost: "example.com",
dnsNames: []string{
"example.com",
"a.b.example.com",
"b.a.example.com",
"a.example.com",
"b.example.com",
},
wantErr: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
record := &DNSRecord{
Spec: DNSRecordSpec{
RootHost: &tt.rootHost,
},
}
err := record.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
return
}
})
}
}
5 changes: 5 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bundle/manifests/dns-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ metadata:
capabilities: Basic Install
categories: Integration & Delivery
containerImage: quay.io/kuadrant/dns-operator:latest
createdAt: "2024-03-11T11:01:25Z"
createdAt: "2024-03-11T14:53:47Z"
description: A Kubernetes Operator to manage the lifecycle of DNS resources
operators.operatorframework.io/builder: operator-sdk-v1.33.0
operators.operatorframework.io/project_layout: go.kubebuilder.io/v4
Expand Down
5 changes: 5 additions & 0 deletions bundle/manifests/kuadrant.io_dnsrecords.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ spec:
required:
- name
type: object
rootHost:
description: "rootHost is the single root for all endpoints in a DNSRecord.
If rootHost is set, it is expected all defined endpoints are children
\tof or equal to this rootHost"
type: string
type: object
status:
description: DNSRecordStatus defines the observed state of DNSRecord
Expand Down
5 changes: 5 additions & 0 deletions config/crd/bases/kuadrant.io_dnsrecords.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ spec:
required:
- name
type: object
rootHost:
description: "rootHost is the single root for all endpoints in a DNSRecord.
If rootHost is set, it is expected all defined endpoints are children
\tof or equal to this rootHost"
type: string
type: object
status:
description: DNSRecordStatus defines the observed state of DNSRecord
Expand Down
4 changes: 3 additions & 1 deletion internal/controller/dnsrecord_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,9 @@ func (r *DNSRecordReconciler) deleteRecord(ctx context.Context, dnsRecord *v1alp
// DNSRecord (dnsRecord.Status.ParentManagedZone).
func (r *DNSRecordReconciler) publishRecord(ctx context.Context, dnsRecord *v1alpha1.DNSRecord) error {
logger := log.FromContext(ctx)

if err := dnsRecord.Validate(); err != nil {
return fmt.Errorf("failed validation pre publish : %s", err)
}
managedZone := &v1alpha1.ManagedZone{
ObjectMeta: metav1.ObjectMeta{
Name: dnsRecord.Spec.ManagedZoneRef.Name,
Expand Down

0 comments on commit 810ac73

Please sign in to comment.