Files
bind-operator/internal/bind/exec.go
T
unkinben 4092a25f4f Target upstream ISC bind9 image
Uses internetsystemsconsortium/bind9 as the default base image instead of
a self-hosted one, verified against internetsystemsconsortium/bind9:9.20
(runs as root; named/rndc/nsupdate at /usr/sbin,/usr/sbin,/usr/bin).

- project operator config at /etc/bind-operator instead of overmounting
  the image's /etc/bind (keeps bind.keys / base config intact)
- reference named/rndc/nsupdate by absolute path (exec PATH may exclude
  /usr/sbin)
- centralise filesystem + binary paths in internal/bind/consts.go
- default spec.image to internetsystemsconsortium/bind9:9.20
2026-07-03 17:41:13 +10:00

64 lines
1.9 KiB
Go

// Package bind contains helpers for driving BIND9 pods: executing rndc and
// nsupdate over the Kubernetes exec subresource, and rendering named.conf.
package bind
import (
"bytes"
"context"
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
)
// Executor runs commands inside BIND pods via the exec subresource.
type Executor struct {
config *rest.Config
clientset kubernetes.Interface
}
// NewExecutor builds an Executor from a controller-runtime rest config.
func NewExecutor(cfg *rest.Config) (*Executor, error) {
cs, err := kubernetes.NewForConfig(cfg)
if err != nil {
return nil, fmt.Errorf("build clientset: %w", err)
}
return &Executor{config: cfg, clientset: cs}, nil
}
// Exec runs command in the BIND container of pod, optionally feeding stdin, and
// returns stdout. A non-zero exit or transport error yields an error that
// includes stderr.
func (e *Executor) Exec(ctx context.Context, namespace, pod string, command []string, stdin string) (string, error) {
req := e.clientset.CoreV1().RESTClient().Post().
Resource("pods").
Name(pod).
Namespace(namespace).
SubResource("exec").
VersionedParams(&corev1.PodExecOptions{
Container: ContainerName,
Command: command,
Stdin: stdin != "",
Stdout: true,
Stderr: true,
}, scheme.ParameterCodec)
exec, err := remotecommand.NewSPDYExecutor(e.config, "POST", req.URL())
if err != nil {
return "", fmt.Errorf("spdy executor: %w", err)
}
var stdout, stderr bytes.Buffer
opts := remotecommand.StreamOptions{Stdout: &stdout, Stderr: &stderr}
if stdin != "" {
opts.Stdin = bytes.NewBufferString(stdin)
}
if err := exec.StreamWithContext(ctx, opts); err != nil {
return stdout.String(), fmt.Errorf("exec %v: %w (stderr: %s)", command, err, stderr.String())
}
return stdout.String(), nil
}