~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
99 lines · 2.5 KB Raw History
package ccmmain

import (
	"context"
	"errors"
	"fmt"
	"log/slog"
	"os"
	"os/signal"
	"syscall"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"

	"github.com/johnandersen777/socialweb-computer-kcp/internal/cloudprovider"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/controllers/tenantnode"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/foldmain"
)

func logTo(logger *slog.Logger) func(string, map[string]any) {
	return func(event string, fields map[string]any) {
		attrs := make([]any, 0, len(fields)*2)
		for k, v := range fields {
			attrs = append(attrs, k, v)
		}
		logger.Info(event, attrs...)
	}
}

func Main(ctx context.Context, inv foldmain.Invocation) int {
	if err := run(ctx, inv); err != nil {
		fmt.Fprintln(inv.Stderr, "socialweb-cloud-controller-manager:", err)
		return 1
	}
	return 0
}

func run(ctx context.Context, inv foldmain.Invocation) error {
	cfg, err := load(inv.Env)
	if err != nil {
		return err
	}
	log := logTo(slog.New(slog.NewJSONHandler(inv.Stderr, nil)))

	ctx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
	defer stop()

	restCfg, err := clientcmd.BuildConfigFromFlags("", cfg.TenantKubeconfig)
	if err != nil {
		return fmt.Errorf(
			"socialweb-cloud-controller-manager: reading the minted tenant kubeconfig at %s: %w",
			cfg.TenantKubeconfig, err)
	}
	client, err := kubernetes.NewForConfig(restCfg)
	if err != nil {
		return fmt.Errorf(
			"socialweb-cloud-controller-manager: building the client for the tenant cluster %s "+
				"from %s: %w", cfg.Cluster, cfg.TenantKubeconfig, err)
	}

	reconciler, err := cloudprovider.NewReconciler(cloudprovider.Options{
		Cluster:   cfg.Cluster,
		Instances: cloudprovider.NewFileInstances(cfg.InstancesFile),
		Nodes:     tenantnode.NewClientNodeWriter(client),
		Log:       log,
	})
	if err != nil {
		return err
	}
	changes, err := cloudprovider.WatchSnapshot(ctx, cfg.InstancesFile)
	if err != nil {
		return err
	}
	controller, err := tenantnode.New(tenantnode.Options{
		Reconciler:      reconciler,
		InstanceChanges: changes,
		Log:             log,
	}, client)
	if err != nil {
		return err
	}

	log("cloud controller manager: status", map[string]any{
		"phase":         "Starting",
		"cluster":       cfg.Cluster,
		"tenant":        cfg.TenantKubeconfig,
		"instancesFile": cfg.InstancesFile,
		"maxNodes":      cfg.MaxNodes,
		"podsPerNode":   cfg.PodsPerNode,
	})

	if err := controller.Run(ctx); err != nil {
		if errors.Is(err, context.Canceled) {
			return nil
		}
		return err
	}
	return nil
}