Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions api/v1alpha1/externaldns_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ type ExternalDNSSpec struct {
// +kubebuilder:validation:Optional
// +optional
Zones []string `json:"zones,omitempty"`

// Interval specifies the interval between two consecutive synchronizations
// performed by ExternalDNS. When omitted, ExternalDNS uses its default
// interval of 1 minute.
//
// +kubebuilder:validation:Optional
// +optional
Interval *metav1.Duration `json:"interval,omitempty"`
}

// ExternalDNSDomain describes how sets of included
Expand Down Expand Up @@ -363,6 +371,15 @@ type ExternalDNSInfobloxProviderOptions struct {
// +kubebuilder:validation:Required
// +required
WAPIVersion string `json:"wapiVersion"`

// MaxResults sets the _max_results query parameter on Infoblox WAPI GET
// requests. This should be set when integrating with Infoblox grids that
// contain a large number of DNS records.
//
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Minimum=1
// +optional
MaxResults *int `json:"maxResults,omitempty"`
}

// SecretReference contains the information to let you locate the desired secret.
Expand Down
12 changes: 11 additions & 1 deletion api/v1alpha1/zz_generated.deepcopy.go

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

17 changes: 17 additions & 0 deletions api/v1beta1/externaldns_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ type ExternalDNSSpec struct {
// +kubebuilder:validation:Optional
// +optional
Zones []string `json:"zones,omitempty"`

// Interval specifies the interval between two consecutive synchronizations
// performed by ExternalDNS. When omitted, ExternalDNS uses its default
// interval of 1 minute.
//
// +kubebuilder:validation:Optional
// +optional
Interval *metav1.Duration `json:"interval,omitempty"`
}

// ExternalDNSDomain describes how sets of included
Expand Down Expand Up @@ -361,6 +369,15 @@ type ExternalDNSInfobloxProviderOptions struct {
// +kubebuilder:validation:Required
// +required
WAPIVersion string `json:"wapiVersion"`

// MaxResults sets the _max_results query parameter on Infoblox WAPI GET
// requests. This should be set when integrating with Infoblox grids that
// contain a large number of DNS records.
//
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Minimum=1
// +optional
MaxResults *int `json:"maxResults,omitempty"`
}

// SecretReference contains the information to let you locate the desired secret.
Expand Down
16 changes: 16 additions & 0 deletions api/v1beta1/externaldns_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ func (r *ExternalDNS) validate(old runtime.Object) error {
r.validateHostnameAnnotationPolicy(),
r.validateProviderCredentials(),
r.validateAWSRoleARN(),
r.validateInterval(),
r.validateInfobloxMaxResults(),
})
}

Expand Down Expand Up @@ -168,3 +170,17 @@ func (r *ExternalDNS) validateAWSRoleARN() error {

return nil
}

func (r *ExternalDNS) validateInterval() error {
if r.Spec.Interval != nil && r.Spec.Interval.Duration <= 0 {
return errors.New(`"interval" must be greater than zero when specified`)
}
return nil
}

func (r *ExternalDNS) validateInfobloxMaxResults() error {
if r.Spec.Provider.Infoblox != nil && r.Spec.Provider.Infoblox.MaxResults != nil && *r.Spec.Provider.Infoblox.MaxResults <= 0 {
return errors.New(`"maxResults" must be greater than zero when specified for Infoblox provider`)
}
return nil
}
12 changes: 11 additions & 1 deletion api/v1beta1/zz_generated.deepcopy.go

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

26 changes: 26 additions & 0 deletions config/crd/bases/externaldns.olm.openshift.io_externaldnses.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ spec:
- matchType
type: object
type: array
interval:
description: |-
Interval specifies the interval between two consecutive synchronizations
performed by ExternalDNS. When omitted, ExternalDNS uses its default
interval of 1 minute.
type: string
provider:
description: |-
Provider refers to the DNS provider that ExternalDNS
Expand Down Expand Up @@ -282,6 +288,13 @@ spec:
gridHost:
description: GridHost is the IP of the Infoblox Grid host.
type: string
maxResults:
description: |-
MaxResults sets the _max_results query parameter on Infoblox WAPI GET
requests. This should be set when integrating with Infoblox grids that
contain a large number of DNS records.
minimum: 1
type: integer
wapiPort:
description: WAPIPort is the port for the Infoblox WAPI.
type: integer
Expand Down Expand Up @@ -692,6 +705,12 @@ spec:
- matchType
type: object
type: array
interval:
description: |-
Interval specifies the interval between two consecutive synchronizations
performed by ExternalDNS. When omitted, ExternalDNS uses its default
interval of 1 minute.
type: string
provider:
description: |-
Provider refers to the DNS provider that ExternalDNS
Expand Down Expand Up @@ -855,6 +874,13 @@ spec:
gridHost:
description: GridHost is the IP of the Infoblox Grid host.
type: string
maxResults:
description: |-
MaxResults sets the _max_results query parameter on Infoblox WAPI GET
requests. This should be set when integrating with Infoblox grids that
contain a large number of DNS records.
minimum: 1
type: integer
wapiPort:
description: WAPIPort is the port for the Infoblox WAPI.
type: integer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ spec:
gridHost: "100.100.100.100"
wapiPort: 443
wapiVersion: "2.12.2"
maxResults: 2000
interval: 5m
source:
# Source Type is route resource of OpenShift
type: OpenShiftRoute
Expand Down
2 changes: 2 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ the following information is required:
gridHost: # the grid master host from the previous step. eg: 172.26.1.200
wapiPort: # the WAPI port, eg: 80, 443, 8080
wapiVersion: # the WAPI version, eg: 2.11, 2.3.1
maxResults: 2000 # optional, sets --infoblox-max-results for large Infoblox grids
interval: 5m # optional, sets --interval for sync frequency
zones: # Replace with the desired hosted zones
- "ZG5zLm5ldHdvcmtfdmlldyQw"
source:
Expand Down
8 changes: 8 additions & 0 deletions pkg/operator/controller/externaldns/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ func (b *externalDNSContainerBuilder) fillProviderAgnosticFields(seq int, zone s
args = append(args, fmt.Sprintf("--openshift-router-name=%s", b.externalDNS.Spec.Source.OpenShiftRoute.RouterName))
}

if b.externalDNS.Spec.Interval != nil && b.externalDNS.Spec.Interval.Duration > 0 {
args = append(args, fmt.Sprintf("--interval=%s", b.externalDNS.Spec.Interval.Duration.String()))
}

filterArgs, err := b.domainFilters()
if err != nil {
return err
Expand Down Expand Up @@ -479,6 +483,10 @@ func (b *externalDNSContainerBuilder) fillInfobloxFields(container *corev1.Conta
args = append(args, fmt.Sprintf("--infoblox-wapi-version=%s", b.externalDNS.Spec.Provider.Infoblox.WAPIVersion))
}

if b.externalDNS.Spec.Provider.Infoblox.MaxResults != nil && *b.externalDNS.Spec.Provider.Infoblox.MaxResults > 0 {
args = append(args, fmt.Sprintf("--infoblox-max-results=%d", *b.externalDNS.Spec.Provider.Infoblox.MaxResults))
}

args = addTXTPrefixFlag(args)

env := []corev1.EnvVar{
Expand Down
136 changes: 136 additions & 0 deletions pkg/operator/controller/externaldns/pod_interval_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package externaldnscontroller

import (
"strings"
"testing"
"time"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"

"github.com/openshift/external-dns-operator/api/v1beta1"
)

func TestIntervalArg(t *testing.T) {
for _, tc := range []struct {
name string
interval *metav1.Duration
expectInterval bool
expectedInterval string
}{
{
name: "interval omitted",
interval: nil,
expectInterval: false,
},
{
name: "interval set",
interval: &metav1.Duration{Duration: 5 * time.Minute},
expectInterval: true,
expectedInterval: "--interval=5m0s",
},
} {
t.Run(tc.name, func(t *testing.T) {
b := &externalDNSContainerBuilder{
externalDNS: &v1beta1.ExternalDNS{
Spec: v1beta1.ExternalDNSSpec{
Interval: tc.interval,
Source: v1beta1.ExternalDNSSource{
ExternalDNSSourceUnion: v1beta1.ExternalDNSSourceUnion{
Type: v1beta1.SourceTypeRoute,
OpenShiftRoute: &v1beta1.ExternalDNSOpenShiftRouteOptions{
RouterName: "default",
},
},
HostnameAnnotationPolicy: v1beta1.HostnameAnnotationPolicyIgnore,
},
},
},
provider: externalDNSProviderTypeInfoblox,
source: "openshift-route",
}

container := b.defaultContainer("external-dns")
if err := b.fillProviderAgnosticFields(0, "", container); err != nil {
t.Fatalf("unexpected error: %v", err)
}

var intervalArg string
for _, arg := range container.Args {
if strings.HasPrefix(arg, "--interval=") {
intervalArg = arg
}
}

if tc.expectInterval {
if intervalArg != tc.expectedInterval {
t.Fatalf("expected %q, got %q from %v", tc.expectedInterval, intervalArg, container.Args)
}
return
}

if intervalArg != "" {
t.Fatalf("unexpected interval arg %q in %v", intervalArg, container.Args)
}
})
}
}

func TestInfobloxMaxResultsArg(t *testing.T) {
for _, tc := range []struct {
name string
maxResults *int
expectedArgs []string
}{
{
name: "max results omitted",
maxResults: nil,
expectedArgs: nil,
},
{
name: "max results set",
maxResults: ptr.To[int](2000),
expectedArgs: []string{"--infoblox-max-results=2000"},
},
} {
t.Run(tc.name, func(t *testing.T) {
b := &externalDNSContainerBuilder{
externalDNS: &v1beta1.ExternalDNS{
Spec: v1beta1.ExternalDNSSpec{
Provider: v1beta1.ExternalDNSProvider{
Type: v1beta1.ProviderTypeInfoblox,
Infoblox: &v1beta1.ExternalDNSInfobloxProviderOptions{
GridHost: "gridhost.example.com",
WAPIPort: 443,
WAPIVersion: "2.12.2",
MaxResults: tc.maxResults,
},
},
},
},
secretName: "infoblox-credentials",
}

container := b.defaultContainer("external-dns")
b.fillInfobloxFields(container)

var got []string
for _, arg := range container.Args {
if strings.HasPrefix(arg, "--infoblox-max-results=") {
got = append(got, arg)
}
}

if tc.expectedArgs == nil {
if len(got) != 0 {
t.Fatalf("unexpected max results args %v", got)
}
return
}

if len(got) != 1 || got[0] != tc.expectedArgs[0] {
t.Fatalf("expected max results args %v, got %v from %v", tc.expectedArgs, got, container.Args)
}
})
}
}