Skip to content

Commit 66fcece

Browse files
committed
feat(source/node): Make exclusion of unschedulable Nodes configurable
This fixes a behavioral regression introduced in #4761, where nodes that were previously added to DNS are removed when they are considered unschedulable, for example due to automated maintenance tasks. This change will introduce a new flag called `exclude-unschedulable`, which defaults to `true` in order to keep in line with the current behavior. However, it would also be reasonable to restore the initial behavior before #4761, which would mean to not exclude unschedulable nodes by default.
1 parent e64e536 commit 66fcece

File tree

7 files changed

+55
-29
lines changed

7 files changed

+55
-29
lines changed

docs/flags.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
| `--[no-]traefik-disable-legacy` | Disable listeners on Resources under the traefik.containo.us API Group |
4949
| `--[no-]traefik-disable-new` | Disable listeners on Resources under the traefik.io API Group |
5050
| `--nat64-networks=NAT64-NETWORKS` | Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional) |
51+
| `--[no-]exclude-unschedulable` | Exclude nodes that are considered unschedulable (default: true) |
5152
| `--provider=provider` | The DNS provider where the DNS records will be created (required, options: akamai, alibabacloud, aws, aws-sd, azure, azure-dns, azure-private-dns, civo, cloudflare, coredns, designate, digitalocean, dnsimple, exoscale, gandi, godaddy, google, ibmcloud, inmemory, linode, ns1, oci, ovh, pdns, pihole, plural, rfc2136, scaleway, skydns, tencentcloud, transip, ultradns, webhook) |
5253
| `--provider-cache-time=0s` | The time to cache the DNS provider record list requests. |
5354
| `--domain-filter=` | Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional) |

main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ func main() {
154154
ResolveLoadBalancerHostname: cfg.ResolveServiceLoadBalancerHostname,
155155
TraefikDisableLegacy: cfg.TraefikDisableLegacy,
156156
TraefikDisableNew: cfg.TraefikDisableNew,
157+
ExcludeUnschedulable: cfg.ExcludeUnschedulable,
157158
}
158159

159160
// Lookup all the selected sources by names and pass them the desired configuration.

pkg/apis/externaldns/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ type Config struct {
211211
TraefikDisableLegacy bool
212212
TraefikDisableNew bool
213213
NAT64Networks []string
214+
ExcludeUnschedulable bool
214215
}
215216

216217
var defaultConfig = &Config{
@@ -367,6 +368,7 @@ var defaultConfig = &Config{
367368
TraefikDisableLegacy: false,
368369
TraefikDisableNew: false,
369370
NAT64Networks: []string{},
371+
ExcludeUnschedulable: true,
370372
}
371373

372374
// NewConfig returns new Config object
@@ -473,6 +475,7 @@ func App(cfg *Config) *kingpin.Application {
473475
app.Flag("traefik-disable-legacy", "Disable listeners on Resources under the traefik.containo.us API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableLegacy)).BoolVar(&cfg.TraefikDisableLegacy)
474476
app.Flag("traefik-disable-new", "Disable listeners on Resources under the traefik.io API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableNew)).BoolVar(&cfg.TraefikDisableNew)
475477
app.Flag("nat64-networks", "Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.NAT64Networks)
478+
app.Flag("exclude-unschedulable", "Exclude nodes that are considered unschedulable (default: true)").Default(strconv.FormatBool(defaultConfig.ExcludeUnschedulable)).BoolVar(&cfg.ExcludeUnschedulable)
476479

477480
// Flags related to providers
478481
providers := []string{"akamai", "alibabacloud", "aws", "aws-sd", "azure", "azure-dns", "azure-private-dns", "civo", "cloudflare", "coredns", "designate", "digitalocean", "dnsimple", "exoscale", "gandi", "godaddy", "google", "ibmcloud", "inmemory", "linode", "ns1", "oci", "ovh", "pdns", "pihole", "plural", "rfc2136", "scaleway", "skydns", "tencentcloud", "transip", "ultradns", "webhook"}

pkg/apis/externaldns/types_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ var (
128128
WebhookProviderURL: "http://localhost:8888",
129129
WebhookProviderReadTimeout: 5 * time.Second,
130130
WebhookProviderWriteTimeout: 10 * time.Second,
131+
ExcludeUnschedulable: true,
131132
}
132133

133134
overriddenConfig = &Config{
@@ -239,6 +240,7 @@ var (
239240
WebhookProviderURL: "http://localhost:8888",
240241
WebhookProviderReadTimeout: 5 * time.Second,
241242
WebhookProviderWriteTimeout: 10 * time.Second,
243+
ExcludeUnschedulable: false,
242244
}
243245
)
244246

@@ -374,6 +376,7 @@ func TestParseFlags(t *testing.T) {
374376
"--managed-record-types=AAAA",
375377
"--managed-record-types=CNAME",
376378
"--managed-record-types=NS",
379+
"--no-exclude-unschedulable",
377380
"--rfc2136-batch-change-size=100",
378381
"--rfc2136-load-balancing-strategy=round-robin",
379382
"--rfc2136-host=rfc2136-host1",
@@ -489,6 +492,7 @@ func TestParseFlags(t *testing.T) {
489492
"EXTERNAL_DNS_TRANSIP_KEYFILE": "/path/to/transip.key",
490493
"EXTERNAL_DNS_DIGITALOCEAN_API_PAGE_SIZE": "100",
491494
"EXTERNAL_DNS_MANAGED_RECORD_TYPES": "A\nAAAA\nCNAME\nNS",
495+
"EXTERNAL_DNS_EXCLUDE_UNSCHEDULABLE": "false",
492496
"EXTERNAL_DNS_RFC2136_BATCH_CHANGE_SIZE": "100",
493497
"EXTERNAL_DNS_RFC2136_LOAD_BALANCING_STRATEGY": "round-robin",
494498
"EXTERNAL_DNS_RFC2136_HOST": "rfc2136-host1\nrfc2136-host2",

source/node.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,16 @@ import (
3434
)
3535

3636
type nodeSource struct {
37-
client kubernetes.Interface
38-
annotationFilter string
39-
fqdnTemplate *template.Template
40-
nodeInformer coreinformers.NodeInformer
41-
labelSelector labels.Selector
37+
client kubernetes.Interface
38+
annotationFilter string
39+
fqdnTemplate *template.Template
40+
nodeInformer coreinformers.NodeInformer
41+
labelSelector labels.Selector
42+
excludeUnschedulable bool
4243
}
4344

4445
// NewNodeSource creates a new nodeSource with the given config.
45-
func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotationFilter, fqdnTemplate string, labelSelector labels.Selector) (Source, error) {
46+
func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotationFilter, fqdnTemplate string, labelSelector labels.Selector, excludeUnschedulable bool) (Source, error) {
4647
tmpl, err := parseTemplate(fqdnTemplate)
4748
if err != nil {
4849
return nil, err
@@ -70,11 +71,12 @@ func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotat
7071
}
7172

7273
return &nodeSource{
73-
client: kubeClient,
74-
annotationFilter: annotationFilter,
75-
fqdnTemplate: tmpl,
76-
nodeInformer: nodeInformer,
77-
labelSelector: labelSelector,
74+
client: kubeClient,
75+
annotationFilter: annotationFilter,
76+
fqdnTemplate: tmpl,
77+
nodeInformer: nodeInformer,
78+
labelSelector: labelSelector,
79+
excludeUnschedulable: excludeUnschedulable,
7880
}, nil
7981
}
8082

@@ -102,7 +104,7 @@ func (ns *nodeSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, erro
102104
continue
103105
}
104106

105-
if node.Spec.Unschedulable {
107+
if node.Spec.Unschedulable && ns.excludeUnschedulable {
106108
log.Debugf("Skipping node %s because it is unschedulable", node.Name)
107109
continue
108110
}

source/node_test.go

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ func testNodeSourceNewNodeSource(t *testing.T) {
7777
ti.annotationFilter,
7878
ti.fqdnTemplate,
7979
labels.Everything(),
80+
true,
8081
)
8182

8283
if ti.expectError {
@@ -93,17 +94,18 @@ func testNodeSourceEndpoints(t *testing.T) {
9394
t.Parallel()
9495

9596
for _, tc := range []struct {
96-
title string
97-
annotationFilter string
98-
labelSelector string
99-
fqdnTemplate string
100-
nodeName string
101-
nodeAddresses []v1.NodeAddress
102-
labels map[string]string
103-
annotations map[string]string
104-
unschedulable bool // default to false
105-
expected []*endpoint.Endpoint
106-
expectError bool
97+
title string
98+
annotationFilter string
99+
labelSelector string
100+
fqdnTemplate string
101+
nodeName string
102+
nodeAddresses []v1.NodeAddress
103+
labels map[string]string
104+
annotations map[string]string
105+
unschedulable bool // default to false
106+
excludeUnschedulable bool // default to false
107+
expected []*endpoint.Endpoint
108+
expectError bool
107109
}{
108110
{
109111
title: "node with short hostname returns one endpoint",
@@ -323,11 +325,22 @@ func testNodeSourceEndpoints(t *testing.T) {
323325
},
324326
},
325327
{
326-
title: "unschedulable node return nothing",
327-
nodeName: "node1",
328-
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
329-
unschedulable: true,
330-
expected: []*endpoint.Endpoint{},
328+
title: "unschedulable node return nothing with excludeUnschedulable=true",
329+
nodeName: "node1",
330+
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
331+
unschedulable: true,
332+
excludeUnschedulable: true,
333+
expected: []*endpoint.Endpoint{},
334+
},
335+
{
336+
title: "unschedulable node returns node with excludeUnschedulable=false",
337+
nodeName: "node1",
338+
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
339+
unschedulable: true,
340+
excludeUnschedulable: false,
341+
expected: []*endpoint.Endpoint{
342+
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
343+
},
331344
},
332345
} {
333346
tc := tc
@@ -368,6 +381,7 @@ func testNodeSourceEndpoints(t *testing.T) {
368381
tc.annotationFilter,
369382
tc.fqdnTemplate,
370383
labelSelector,
384+
tc.excludeUnschedulable,
371385
)
372386
require.NoError(t, err)
373387

source/store.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ type Config struct {
7979
ResolveLoadBalancerHostname bool
8080
TraefikDisableLegacy bool
8181
TraefikDisableNew bool
82+
ExcludeUnschedulable bool
8283
}
8384

8485
// ClientGenerator provides clients
@@ -215,7 +216,7 @@ func BuildWithConfig(ctx context.Context, source string, p ClientGenerator, cfg
215216
if err != nil {
216217
return nil, err
217218
}
218-
return NewNodeSource(ctx, client, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.LabelFilter)
219+
return NewNodeSource(ctx, client, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.LabelFilter, cfg.ExcludeUnschedulable)
219220
case "service":
220221
client, err := p.KubeClient()
221222
if err != nil {

0 commit comments

Comments
 (0)