From b9249233582a8289e9a5252db2c4c005dd787972 Mon Sep 17 00:00:00 2001 From: Vassiliy Yegorov Date: Mon, 2 Nov 2026 18:01:26 +0700 Subject: [PATCH] fix --- internal/provider/selectel/selectel.go | 84 +++++++++++++++++--------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/internal/provider/selectel/selectel.go b/internal/provider/selectel/selectel.go index 5717676..0862731 100644 --- a/internal/provider/selectel/selectel.go +++ b/internal/provider/selectel/selectel.go @@ -337,40 +337,64 @@ func (c *Client) ApplyChanges(ctx context.Context, creds provider.Credentials, z } base := "/zones/" + url.PathEscape(zoneID) + "/rrset" + applied := 0 for _, d := range cs.Diffs { if d.ReadOnly || d.Kind == diff.InSync { continue } - switch d.Kind { - case diff.Add: - if d.Desired == nil { - return fmt.Errorf("selectel: add/update diff without Desired record") - } - if err := c.do(ctx, http.MethodPost, base, tok, toRRSet(*d.Desired), nil); err != nil { - return err - } - case diff.Update: - if d.Desired == nil { - return fmt.Errorf("selectel: add/update diff without Desired record") - } - id, ok := idByKey[d.Desired.Key()] - if !ok { - return fmt.Errorf("cannot update: rrset %s not found in zone", d.Desired.Key()) - } - if err := c.do(ctx, http.MethodPatch, base+"/"+url.PathEscape(id), tok, toRRSet(*d.Desired), nil); err != nil { - return err - } - case diff.Delete: - if d.Actual == nil { - return fmt.Errorf("selectel: delete diff without Actual record") - } - id, ok := idByKey[d.Actual.Key()] - if !ok { - return fmt.Errorf("cannot delete: rrset %s not found in zone", d.Actual.Key()) - } - if err := c.do(ctx, http.MethodDelete, base+"/"+url.PathEscape(id), tok, nil, nil); err != nil { - return err - } + if err := c.applyOne(ctx, base, tok, idByKey, d); err != nil { + // Apply is not atomic: name the failing record and how many + // diffs already went through, so the operator can see the state. + return fmt.Errorf("%s (применено до ошибки: %d): %w", describeDiff(d), applied, err) + } + applied++ + } + return nil +} + +// describeDiff renders a diff for error messages: "add CNAME mail.x. [value]". +func describeDiff(d diff.RecordDiff) string { + rec := d.Desired + if rec == nil { + rec = d.Actual + } + out := fmt.Sprintf("%s %s", d.Kind, d.Key()) + if rec != nil { + out += fmt.Sprintf(" ttl=%d %q", rec.TTL, rec.Values) + } + return out +} + +func (c *Client) applyOne(ctx context.Context, base, tok string, idByKey map[string]string, d diff.RecordDiff) error { + switch d.Kind { + case diff.Add: + if d.Desired == nil { + return fmt.Errorf("selectel: add/update diff without Desired record") + } + if err := c.do(ctx, http.MethodPost, base, tok, toRRSet(*d.Desired), nil); err != nil { + return err + } + case diff.Update: + if d.Desired == nil { + return fmt.Errorf("selectel: add/update diff without Desired record") + } + id, ok := idByKey[d.Desired.Key()] + if !ok { + return fmt.Errorf("cannot update: rrset %s not found in zone", d.Desired.Key()) + } + if err := c.do(ctx, http.MethodPatch, base+"/"+url.PathEscape(id), tok, toRRSet(*d.Desired), nil); err != nil { + return err + } + case diff.Delete: + if d.Actual == nil { + return fmt.Errorf("selectel: delete diff without Actual record") + } + id, ok := idByKey[d.Actual.Key()] + if !ok { + return fmt.Errorf("cannot delete: rrset %s not found in zone", d.Actual.Key()) + } + if err := c.do(ctx, http.MethodDelete, base+"/"+url.PathEscape(id), tok, nil, nil); err != nil { + return err } } return nil