penguin/monok8s

k8s image for Mono Gateway Dev Kit

clitools/pkg/node/network.go

raw ยท 2838 bytes

package node

import (
	"context"
	"fmt"
	"net"
	"strings"

	system "undecided.project/monok8s/pkg/system"
	"k8s.io/klog/v2"
)

type NetworkConfig struct {
	MgmtIface   string
	MgmtAddress string
	MgmtGateway string
}

func ConfigureMgmtInterface(cfg NetworkConfig) Step {
	return func(ctx context.Context, nctx *NodeContext) error {
		if strings.TrimSpace(cfg.MgmtIface) == "" {
			return fmt.Errorf("mgmt interface is required")
		}
		if strings.TrimSpace(cfg.MgmtAddress) == "" {
			return fmt.Errorf("mgmt address is required")
		}
		ip, ipNet, err := net.ParseCIDR(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)
		}

		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)
		}

		hasAddr, err := interfaceHasIPv4(ctx, nctx, cfg.MgmtIface, wantIP)
		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)
		} 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 gw := strings.TrimSpace(cfg.MgmtGateway); gw != "" {
			if _, err := nctx.System.Run(ctx, "ip", "route", "replace", "default", "via", gw, "dev", cfg.MgmtIface); err != nil {
				return fmt.Errorf("failed setting default route via %s dev %s: %w", gw, cfg.MgmtIface, err)
			}
		}
		return nil
	}
}

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 interfaceHasIPv4(ctx context.Context, nctx *NodeContext, iface, wantIP string) (bool, error) {
	res, err := nctx.System.Run(ctx, "ip", "-o", "-4", "addr", "show", "dev", iface)
	if err != nil {
		return false, err
	}
	for _, line := range strings.Split(res.Stdout, "\n") {
		fields := strings.Fields(strings.TrimSpace(line))
		for i := 0; i < len(fields)-1; i++ {
			if fields[i] != "inet" {
				continue
			}
			ip, _, err := net.ParseCIDR(fields[i+1])
			if err == nil && ip.String() == wantIP {
				return true, nil
			}
		}
	}
	return false, nil
}