penguin/monok8s

k8s image for Mono Gateway Dev Kit

commit 848daefffe9998a27055dd5ebffd17837f896d0612287458714f2ebb1991aad3

author斟酌 鵬兄 <tgckpg@gmail.com>
date2026-03-27T12:25:54Z
subjectclitools: Added ConfigureDNS
commit 848daefffe9998a27055dd5ebffd17837f896d0612287458714f2ebb1991aad3
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2026-03-27T12:25:54Z

    clitools: Added ConfigureDNS
---
 clitools/makefile                     |   4 +-
 clitools/pkg/bootstrap/registry.go    |  10 +--
 clitools/pkg/cmd/internal/internal.go |  12 +++-
 clitools/pkg/node/network.go          | 116 ++++++++++++++++++++++++++++++----
 makefile                              |  14 +++-
 5 files changed, 132 insertions(+), 24 deletions(-)

diff --git a/clitools/makefile b/clitools/makefile
index fac06f2..7ab571c 100644
--- a/clitools/makefile
+++ b/clitools/makefile
@@ -4,11 +4,11 @@ BIN_DIR := bin
 
 build:
 	mkdir -p $(BIN_DIR)
-	go build -o $(BIN_DIR)/ctl-$(VERSION) ./cmd/ctl
+	GOOS=linux GOARCH=arm64 go build -o $(BIN_DIR)/ctl-linux-aarch64-$(VERSION) ./cmd/ctl/
+#	go build -o $(BIN_DIR)/ctl-$(VERSION) ./cmd/ctl
 
 run:
 	go run ./cmd/ctl
 
 clean:
 	rm -rf $(BIN_DIR)
-
diff --git a/clitools/pkg/bootstrap/registry.go b/clitools/pkg/bootstrap/registry.go
index 372a73f..20ffccd 100644
--- a/clitools/pkg/bootstrap/registry.go
+++ b/clitools/pkg/bootstrap/registry.go
@@ -12,9 +12,11 @@ type Registry struct {
 
 func NewRegistry(ctx *node.NodeContext) *Registry {
 	netCfg := node.NetworkConfig{
-		MgmtIface:   ctx.Config.Spec.Network.ManagementIface,
-		MgmtAddress: ctx.Config.Spec.Network.ManagementCIDR,
-		MgmtGateway: ctx.Config.Spec.Network.ManagementGW,
+		MgmtIface:        ctx.Config.Spec.Network.ManagementIface,
+		MgmtAddress:      ctx.Config.Spec.Network.ManagementCIDR,
+		MgmtGateway:      ctx.Config.Spec.Network.ManagementGW,
+		DNSNameservers:   ctx.Config.Spec.Network.DNSNameservers,
+		DNSSearchDomains: ctx.Config.Spec.Network.DNSSearchDomains,
 	}
 
 	return &Registry{
@@ -34,7 +36,7 @@ func NewRegistry(ctx *node.NodeContext) *Registry {
 			"allow_single_node_scheduling":          node.AllowSingleNodeScheduling,
 			"ensure_ip_forward":                     node.EnsureIPForward,
 			"configure_mgmt_interface":              node.ConfigureMgmtInterface(netCfg),
-			"configure_dns":                         node.ConfigureDNS,
+			"configure_dns":                         node.ConfigureDNS(netCfg),
 			"set_hostname_if_needed":                node.SetHostnameIfNeeded,
 			"print_summary":                         node.PrintSummary,
 			"reconcile_control_plane":               node.ReconcileControlPlane,
diff --git a/clitools/pkg/cmd/internal/internal.go b/clitools/pkg/cmd/internal/internal.go
index 24f3684..953db45 100644
--- a/clitools/pkg/cmd/internal/internal.go
+++ b/clitools/pkg/cmd/internal/internal.go
@@ -1,9 +1,9 @@
 package internal
 
 import (
+	"github.com/spf13/cobra"
 	"undecided.project/monok8s/pkg/bootstrap"
 	"undecided.project/monok8s/pkg/config"
-	"github.com/spf13/cobra"
 )
 
 func NewCmdInternal() *cobra.Command {
@@ -18,11 +18,19 @@ func NewCmdInternal() *cobra.Command {
 			if err != nil {
 				return err
 			}
+
 			cfg, err := (config.Loader{}).Load(path)
 			if err != nil {
 				return err
 			}
-			return bootstrap.NewRunner(cfg).RunNamedStep(cmd.Context(), args[0])
+
+			err = bootstrap.NewRunner(cfg).RunNamedStep(cmd.Context(), args[0])
+			if err != nil {
+				return err
+			}
+
+			cmd.Println("OK")
+			return nil
 		},
 	})
 	cmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "path to MonoKSConfig yaml")
diff --git a/clitools/pkg/node/network.go b/clitools/pkg/node/network.go
index 28609b3..4f40943 100644
--- a/clitools/pkg/node/network.go
+++ b/clitools/pkg/node/network.go
@@ -4,16 +4,19 @@ import (
 	"context"
 	"fmt"
 	"net"
+	"os"
 	"strings"
 
-	system "undecided.project/monok8s/pkg/system"
 	"k8s.io/klog/v2"
+	system "undecided.project/monok8s/pkg/system"
 )
 
 type NetworkConfig struct {
-	MgmtIface   string
-	MgmtAddress string
-	MgmtGateway string
+	MgmtIface        string
+	MgmtAddress      string
+	MgmtGateway      string
+	DNSNameservers   []string
+	DNSSearchDomains []string
 }
 
 func ConfigureMgmtInterface(cfg NetworkConfig) Step {
@@ -24,18 +27,31 @@ func ConfigureMgmtInterface(cfg NetworkConfig) Step {
 		if strings.TrimSpace(cfg.MgmtAddress) == "" {
 			return fmt.Errorf("mgmt address is required")
 		}
-		ip, ipNet, err := net.ParseCIDR(cfg.MgmtAddress)
+
+		ip, ipNet, err := net.ParseCIDR(strings.TrimSpace(cfg.MgmtAddress))
 		if err != nil {
 			return fmt.Errorf("invalid mgmt address %q: %w", cfg.MgmtAddress, err)
 		}
-		wantIP := ip.String()
-		if gw := strings.TrimSpace(cfg.MgmtGateway); gw != "" && net.ParseIP(gw) == nil {
-			return fmt.Errorf("invalid mgmt gateway %q", gw)
+
+		ip4 := ip.To4()
+		if ip4 == nil {
+			return fmt.Errorf("mgmt address must be IPv4: %q", cfg.MgmtAddress)
+		}
+
+		wantIP := ip4.String()
+		wantCIDR := fmt.Sprintf("%s/%d", wantIP, maskSize(ipNet.Mask))
+
+		if gw := strings.TrimSpace(cfg.MgmtGateway); gw != "" {
+			gwIP := net.ParseIP(gw)
+			if gwIP == nil || gwIP.To4() == nil {
+				return fmt.Errorf("invalid mgmt gateway %q", gw)
+			}
 		}
 
 		if _, err := nctx.System.Run(ctx, "ip", "link", "show", "dev", cfg.MgmtIface); err != nil {
 			return fmt.Errorf("interface not found: %s: %w", cfg.MgmtIface, err)
 		}
+
 		if _, err := nctx.System.Run(ctx, "ip", "link", "set", "dev", cfg.MgmtIface, "up"); err != nil {
 			return fmt.Errorf("failed to bring up interface %s: %w", cfg.MgmtIface, err)
 		}
@@ -44,11 +60,12 @@ func ConfigureMgmtInterface(cfg NetworkConfig) Step {
 		if err != nil {
 			return fmt.Errorf("failed checking existing address on %s: %w", cfg.MgmtIface, err)
 		}
+
 		if hasAddr {
-			klog.Infof("address already present on %s: %s", cfg.MgmtIface, cfg.MgmtAddress)
+			klog.Infof("address already present on %s: %s", cfg.MgmtIface, wantCIDR)
 		} else {
-			if _, err := nctx.System.Run(ctx, "ip", "addr", "add", ipNet.String(), "dev", cfg.MgmtIface); err != nil {
-				return fmt.Errorf("failed assigning %s to %s: %w", ipNet.String(), cfg.MgmtIface, err)
+			if _, err := nctx.System.Run(ctx, "ip", "addr", "add", wantCIDR, "dev", cfg.MgmtIface); err != nil {
+				return fmt.Errorf("failed assigning %s to %s: %w", wantCIDR, cfg.MgmtIface, err)
 			}
 		}
 
@@ -57,17 +74,88 @@ func ConfigureMgmtInterface(cfg NetworkConfig) Step {
 				return fmt.Errorf("failed setting default route via %s dev %s: %w", gw, cfg.MgmtIface, err)
 			}
 		}
+
 		return nil
 	}
 }
 
+func maskSize(m net.IPMask) int {
+	ones, _ := m.Size()
+	return ones
+}
+
 func EnsureIPForward(ctx context.Context, n *NodeContext) error {
 	return system.EnsureSysctl(ctx, n.System, "net.ipv4.ip_forward", "1")
 }
 
-func ConfigureDNS(context.Context, *NodeContext) error {
-	klog.Info("configure_dns: TODO implement resolv.conf rendering")
-	return nil
+func ConfigureDNS(cfg NetworkConfig) Step {
+	return func(context.Context, *NodeContext) error {
+
+		if len(cfg.DNSNameservers) == 0 {
+			return nil
+		}
+
+		var nameservers []string
+		for _, ns := range cfg.DNSNameservers {
+			ns = strings.TrimSpace(ns)
+			if ns == "" {
+				continue
+			}
+			if ip := net.ParseIP(ns); ip == nil {
+				return fmt.Errorf("invalid DNS nameserver %q", ns)
+			}
+			nameservers = append(nameservers, ns)
+		}
+		if len(nameservers) == 0 {
+			return fmt.Errorf("DNSNameservers is set but no valid nameservers were parsed")
+		}
+
+		var searchDomains []string
+		for _, d := range cfg.DNSSearchDomains {
+			d = strings.TrimSpace(d)
+			if d == "" {
+				continue
+			}
+			searchDomains = append(searchDomains, d)
+		}
+
+		var b strings.Builder
+		if len(searchDomains) > 0 {
+			b.WriteString("search ")
+			b.WriteString(strings.Join(searchDomains, " "))
+			b.WriteByte('\n')
+		}
+		for _, ns := range nameservers {
+			b.WriteString("nameserver ")
+			b.WriteString(ns)
+			b.WriteByte('\n')
+		}
+		b.WriteString("options timeout:2 attempts:3\n")
+
+		const (
+			resolvDir  = "/etc"
+			tmpPath    = "/etc/resolv.conf.monok8s.tmp"
+			resolvPath = "/etc/resolv.conf"
+		)
+
+		if err := os.MkdirAll(resolvDir, 0o755); err != nil {
+			klog.Warningf("failed to create %s for DNS config: %v; leaving %s unchanged", resolvDir, err, resolvPath)
+			return nil
+		}
+
+		if err := os.WriteFile(tmpPath, []byte(b.String()), 0o644); err != nil {
+			klog.Warningf("failed to write temporary DNS config %s: %v; leaving %s unchanged", tmpPath, err, resolvPath)
+			return nil
+		}
+
+		if err := os.Rename(tmpPath, resolvPath); err != nil {
+			_ = os.Remove(tmpPath)
+			klog.Warningf("failed to install DNS config at %s: %v; leaving existing DNS config unchanged", resolvPath, err)
+			return nil
+		}
+
+		return nil
+	}
 }
 
 func interfaceHasIPv4(ctx context.Context, nctx *NodeContext, iface, wantIP string) (bool, error) {
diff --git a/makefile b/makefile
index 1928b19..ed0568c 100644
--- a/makefile
+++ b/makefile
@@ -91,6 +91,12 @@ RELEASE_DEPS := \
 	build.env \
 	makefile
 
+CLITOOLS := \
+	clitools/pkg \
+	clitools/cmd \
+	clitools/go.mod \
+	clitools/go.sum
+
 # ---- Directory creation ------------------------------------------------------
 
 $(PACKAGES_DIR):
@@ -258,13 +264,17 @@ initramfs: $(INITRAMFS)
 itb: $(BOARD_ITB)
 build-base: $(BUILD_BASE_STAMP)
 
+clitools: $(CLITOOLS)
+	$(MAKE) -C clitools
+
 clean:
 	rm -f \
 		$(BUILD_BASE_STAMP) \
 		$(KERNEL_IMAGE) \
 		$(INITRAMFS) \
 		$(BOARD_ITB) \
-		$(RELEASE_IMAGE)
+		$(RELEASE_IMAGE) \
+		$(CLITOOLS)
 
 distclean: clean
 	rm -rf $(OUT_DIR)
@@ -272,5 +282,5 @@ distclean: clean
 pkgclean:
 	rm -rf $(PACKAGES_DIR)
 
-.PHONY: release kernel initramfs itb build-base clean distclean pkgclean \
+.PHONY: release kernel initramfs itb build-base clitools clean distclean pkgclean \
 	cluster-config cluster-defconfig cluster-print