package controller import ( "context" "fmt" "strings" "sigs.k8s.io/controller-runtime/pkg/client" bindv1alpha1 "git.unkin.net/unkin/bind-operator/api/v1alpha1" "git.unkin.net/unkin/bind-operator/internal/bind" ) func isPrimaryType(t bindv1alpha1.ZoneType) bool { return t == bindv1alpha1.ZonePrimary || t == "" } // catalogEnabled reports whether a primary zone should be registered in the // cluster catalog zone. func catalogEnabled(zone *bindv1alpha1.BindZone) bool { if !isPrimaryType(zone.Spec.Type) { return false } if zone.Spec.Catalog == nil { return true } return *zone.Spec.Catalog } // fqdn resolves a record owner name relative to a zone origin. func fqdn(name, zone string) string { zone = strings.TrimSuffix(zone, ".") + "." if name == "" || name == "@" { return zone } if strings.HasSuffix(name, ".") { return name } return name + "." + zone } func recordsToUpdates(zone string, records []bindv1alpha1.Record, defaultTTL int32) []bind.RecordUpdate { updates := make([]bind.RecordUpdate, 0, len(records)) for _, rec := range records { ttl := defaultTTL if rec.TTL != nil { ttl = *rec.TTL } updates = append(updates, bind.RecordUpdate{ FQDN: fqdn(rec.Name, zone), Type: rec.Type, TTL: ttl, Values: rec.Values, }) } return updates } // updateKeyName returns the TSIG key name (as used in named.conf) for a zone's // update key, falling back to the object name. func updateKeyName(ctx context.Context, c client.Client, zone *bindv1alpha1.BindZone) string { return tsigKeyName(ctx, c, zone.Namespace, zone.Spec.UpdateKeyRef) } // tsigKeyName resolves a BindTSIGKey object reference to the TSIG key name used // in named.conf (the KeyName override when set, otherwise the object name). // Returns "" for an empty ref, and falls back to the ref if the object cannot be // read. func tsigKeyName(ctx context.Context, c client.Client, namespace, ref string) string { if ref == "" { return "" } var key bindv1alpha1.BindTSIGKey if err := c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: ref}, &key); err != nil { return ref } if key.Spec.KeyName != "" { return key.Spec.KeyName } return ref } // matchListInline renders address-match-list entries on one line. func matchListInline(entries []string) string { return terminateInline(entries) } func terminateInline(entries []string) string { var parts []string for _, e := range entries { e = strings.TrimSpace(strings.TrimRight(e, ";")) if e == "" { continue } parts = append(parts, e+";") } return strings.Join(parts, " ") } // alsoNotifyList renders also-notify entries, each optionally annotated with a // TSIG key so the primary signs its NOTIFYs and secondaries can accept them by // key (`allow-notify { key ... }`) rather than by pod IP. An entry that already // carries a `key` clause is left untouched. func alsoNotifyList(addrs []string, key string) string { key = strings.TrimSpace(key) var parts []string for _, a := range addrs { a = strings.TrimSpace(strings.TrimRight(a, ";")) if a == "" { continue } if key != "" && !strings.Contains(a, " key ") { a = fmt.Sprintf("%s key \"%s\"", a, key) } parts = append(parts, a+";") } return strings.Join(parts, " ") }