From 1ee6c0a77d9e34b554a430e07aa24d2565c45751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandor=20Sz=C3=BCcs?= Date: Tue, 9 Jan 2024 22:06:02 +0100 Subject: [PATCH 1/3] fix: provide possibility to have a soft error mode to only log error and not fatal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sandor Szücs --- controller/controller.go | 7 ++++++- provider/aws/aws.go | 15 +++++++-------- provider/provider.go | 7 +++++++ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/controller/controller.go b/controller/controller.go index 63ae9f6240..a3ef2e8b23 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -18,6 +18,7 @@ package controller import ( "context" + "errors" "fmt" "sync" "time" @@ -331,7 +332,11 @@ func (c *Controller) Run(ctx context.Context) { for { if c.ShouldRunOnce(time.Now()) { if err := c.RunOnce(ctx); err != nil { - log.Fatal(err) + if errors.Is(err, provider.SoftError) { + log.Errorf("Failed to do run once: %v", err) + } else { + log.Fatalf("Failed to do run once: %v", err) + } } } select { diff --git a/provider/aws/aws.go b/provider/aws/aws.go index fd16a6d1ac..26de97df08 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -27,7 +27,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/service/route53" - "github.com/pkg/errors" log "github.com/sirupsen/logrus" "sigs.k8s.io/external-dns/endpoint" @@ -325,10 +324,10 @@ func (p *AWSProvider) Zones(ctx context.Context) (map[string]*route53.HostedZone err := p.client.ListHostedZonesPagesWithContext(ctx, &route53.ListHostedZonesInput{}, f) if err != nil { - return nil, errors.Wrap(err, "failed to list hosted zones") + return nil, provider.WrapSoftError(fmt.Errorf("failed to list hosted zones: %w", err)) } if tagErr != nil { - return nil, errors.Wrap(tagErr, "failed to list zones tags") + return nil, provider.WrapSoftError(fmt.Errorf("failed to list zones tags: %w", tagErr)) } for _, zone := range zones { @@ -353,7 +352,7 @@ func wildcardUnescape(s string) string { func (p *AWSProvider) Records(ctx context.Context) (endpoints []*endpoint.Endpoint, _ error) { zones, err := p.Zones(ctx) if err != nil { - return nil, errors.Wrap(err, "records retrieval failed") + return nil, provider.WrapSoftError(fmt.Errorf("records retrieval failed: %w", err)) } return p.records(ctx, zones) @@ -445,7 +444,7 @@ func (p *AWSProvider) records(ctx context.Context, zones map[string]*route53.Hos } if err := p.client.ListResourceRecordSetsPagesWithContext(ctx, params, f); err != nil { - return nil, errors.Wrapf(err, "failed to list resource records sets for zone %s", *z.Id) + return nil, provider.WrapSoftError(fmt.Errorf("failed to list resource records sets for zone %s: %w", *z.Id, err)) } } @@ -530,7 +529,7 @@ func (p *AWSProvider) GetDomainFilter() endpoint.DomainFilter { func (p *AWSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { zones, err := p.Zones(ctx) if err != nil { - return errors.Wrap(err, "failed to list zones, not applying changes") + return provider.WrapSoftError(fmt.Errorf("failed to list zones, not applying changes: %w", err)) } updateChanges := p.createUpdateChanges(changes.UpdateNew, changes.UpdateOld) @@ -632,7 +631,7 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes, } if len(failedZones) > 0 { - return errors.Errorf("failed to submit all changes for the following zones: %v", failedZones) + return provider.WrapSoftError(fmt.Errorf("failed to submit all changes for the following zones: %v", failedZones)) } return nil @@ -847,7 +846,7 @@ func (p *AWSProvider) tagsForZone(ctx context.Context, zoneID string) (map[strin ResourceId: aws.String(zoneID), }) if err != nil { - return nil, errors.Wrapf(err, "failed to list tags for zone %s", zoneID) + return nil, provider.WrapSoftError(fmt.Errorf("failed to list tags for zone %s: %w", zoneID, err)) } tagMap := map[string]string{} for _, tag := range response.ResourceTagSet.Tags { diff --git a/provider/provider.go b/provider/provider.go index 68492183bf..6b146ee3f5 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -18,6 +18,7 @@ package provider import ( "context" + "errors" "net" "strings" @@ -25,6 +26,12 @@ import ( "sigs.k8s.io/external-dns/plan" ) +var SoftError error = errors.New("soft error") + +func WrapSoftError(err error) error { + return errors.Join(SoftError, err) +} + // Provider defines the interface DNS providers should implement. type Provider interface { Records(ctx context.Context) ([]*endpoint.Endpoint, error) From e5f7e91c0c9b08d213eaa4191b353611dc919a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandor=20Sz=C3=BCcs?= Date: Tue, 9 Jan 2024 22:06:02 +0100 Subject: [PATCH 2/3] fix: provide possibility to have a soft error mode to only log error and not fatal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sandor Szücs --- provider/aws/aws.go | 14 +++++++------- provider/provider.go | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 26de97df08..6b1690f3c5 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -324,10 +324,10 @@ func (p *AWSProvider) Zones(ctx context.Context) (map[string]*route53.HostedZone err := p.client.ListHostedZonesPagesWithContext(ctx, &route53.ListHostedZonesInput{}, f) if err != nil { - return nil, provider.WrapSoftError(fmt.Errorf("failed to list hosted zones: %w", err)) + return nil, provider.NewSoftError(fmt.Errorf("failed to list hosted zones: %w", err)) } if tagErr != nil { - return nil, provider.WrapSoftError(fmt.Errorf("failed to list zones tags: %w", tagErr)) + return nil, provider.NewSoftError(fmt.Errorf("failed to list zones tags: %w", tagErr)) } for _, zone := range zones { @@ -352,7 +352,7 @@ func wildcardUnescape(s string) string { func (p *AWSProvider) Records(ctx context.Context) (endpoints []*endpoint.Endpoint, _ error) { zones, err := p.Zones(ctx) if err != nil { - return nil, provider.WrapSoftError(fmt.Errorf("records retrieval failed: %w", err)) + return nil, provider.NewSoftError(fmt.Errorf("records retrieval failed: %w", err)) } return p.records(ctx, zones) @@ -444,7 +444,7 @@ func (p *AWSProvider) records(ctx context.Context, zones map[string]*route53.Hos } if err := p.client.ListResourceRecordSetsPagesWithContext(ctx, params, f); err != nil { - return nil, provider.WrapSoftError(fmt.Errorf("failed to list resource records sets for zone %s: %w", *z.Id, err)) + return nil, provider.NewSoftError(fmt.Errorf("failed to list resource records sets for zone %s: %w", *z.Id, err)) } } @@ -529,7 +529,7 @@ func (p *AWSProvider) GetDomainFilter() endpoint.DomainFilter { func (p *AWSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { zones, err := p.Zones(ctx) if err != nil { - return provider.WrapSoftError(fmt.Errorf("failed to list zones, not applying changes: %w", err)) + return provider.NewSoftError(fmt.Errorf("failed to list zones, not applying changes: %w", err)) } updateChanges := p.createUpdateChanges(changes.UpdateNew, changes.UpdateOld) @@ -631,7 +631,7 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes, } if len(failedZones) > 0 { - return provider.WrapSoftError(fmt.Errorf("failed to submit all changes for the following zones: %v", failedZones)) + return provider.NewSoftError(fmt.Errorf("failed to submit all changes for the following zones: %v", failedZones)) } return nil @@ -846,7 +846,7 @@ func (p *AWSProvider) tagsForZone(ctx context.Context, zoneID string) (map[strin ResourceId: aws.String(zoneID), }) if err != nil { - return nil, provider.WrapSoftError(fmt.Errorf("failed to list tags for zone %s: %w", zoneID, err)) + return nil, provider.NewSoftError(fmt.Errorf("failed to list tags for zone %s: %w", zoneID, err)) } tagMap := map[string]string{} for _, tag := range response.ResourceTagSet.Tags { diff --git a/provider/provider.go b/provider/provider.go index 6b146ee3f5..3c9b9d562f 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -28,7 +28,7 @@ import ( var SoftError error = errors.New("soft error") -func WrapSoftError(err error) error { +func NewSoftError(err error) error { return errors.Join(SoftError, err) } From b8ac272f99a76ca21b43a65a60607a9a6b466f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandor=20Sz=C3=BCcs?= Date: Fri, 12 Jan 2024 20:53:58 +0100 Subject: [PATCH 3/3] doc: add godoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sandor Szücs --- provider/provider.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/provider/provider.go b/provider/provider.go index 3c9b9d562f..6a9c591e10 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -26,8 +26,12 @@ import ( "sigs.k8s.io/external-dns/plan" ) +// SoftError is an error, that provider will only log as error instead +// of fatal. It is meant for error propagation from providers to tell +// that this is a transient error. var SoftError error = errors.New("soft error") +// NewSoftError creates a SoftError from the given error func NewSoftError(err error) error { return errors.Join(SoftError, err) }