penguin/monok8s

k8s image for Mono Gateway Dev Kit

clitools/pkg/node/prereqs.go

raw ยท 2625 bytes

package node

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

	"k8s.io/klog/v2"
)

func ValidateNetworkRequirements(ctx context.Context, nct *NodeContext) error {
	requireLocalIP := func(wantedIP string) error {
		wantedIP = strings.TrimSpace(wantedIP)
		if wantedIP == "" {
			return fmt.Errorf("API server advertise address is required")
		}

		ip := net.ParseIP(wantedIP)
		if ip == nil {
			return fmt.Errorf("invalid API server advertise address %q", wantedIP)
		}

		ifaces, err := net.Interfaces()
		if err != nil {
			return fmt.Errorf("list interfaces: %w", err)
		}

		for _, iface := range ifaces {
			addrs, err := iface.Addrs()
			if err != nil {
				continue
			}
			for _, addr := range addrs {
				var got net.IP
				switch v := addr.(type) {
				case *net.IPNet:
					got = v.IP
				case *net.IPAddr:
					got = v.IP
				}
				if got != nil && got.Equal(ip) {
					return nil
				}
			}
		}

		return fmt.Errorf("required local IP is not present on any interface: %s", wantedIP)
	}

	checkAPIServerReachable := func(endpoint string) error {
		endpoint = strings.TrimSpace(endpoint)
		if endpoint == "" {
			return fmt.Errorf("API server endpoint is required")
		}

		host, port, err := net.SplitHostPort(endpoint)
		if err != nil {
			return fmt.Errorf("invalid API server endpoint %q: %w", endpoint, err)
		}
		if strings.TrimSpace(host) == "" || strings.TrimSpace(port) == "" {
			return fmt.Errorf("invalid API server endpoint %q", endpoint)
		}

		klog.Infof("checking API server reachability: %s:%s", host, port)

		var lastErr error
		for i := 0; i < 20; i++ {
			d := net.Dialer{Timeout: 1 * time.Second}
			conn, err := d.DialContext(ctx, "tcp", endpoint)
			if err == nil {
				_ = conn.Close()
				klog.Infof("API server is reachable")
				return nil
			}
			lastErr = err

			select {
			case <-ctx.Done():
				return ctx.Err()
			case <-time.After(1 * time.Second):
			}
		}

		return fmt.Errorf("cannot reach API server at %s: %w", endpoint, lastErr)
	}

	cfg := nct.Config.Spec
	switch strings.TrimSpace(cfg.ClusterRole) {
	case "control-plane":
		if err := requireLocalIP(cfg.APIServerAdvertiseAddress); err != nil {
			return err
		}
	case "worker":
		if err := requireLocalIP(cfg.APIServerAdvertiseAddress); err != nil {
			return err
		}
		if err := checkAPIServerReachable(cfg.APIServerEndpoint); err != nil {
			return err
		}
	default:
		return fmt.Errorf("Incorrect ClusterRole: %s", cfg.ClusterRole)
	}

	return nil
}

func CheckUpgradePrereqs(context.Context, *NodeContext) error {
	klog.Info("check_upgrade_prereqs: TODO implement kubeadm version / skew checks")
	return nil
}