~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
104 lines · 4.4 KB Raw History
package providermain

import (
	"context"
	"fmt"
	"log/slog"
	"time"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"

	"github.com/johnandersen777/socialweb-computer-kcp/internal/clusterkcp"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/clusterprovider"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/controllers/runtime/kube"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/esovault"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/kcpclient"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/kcpserver"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/tenantnet"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/vault/openbao"
)

const tenantAddOnTimeout = 60 * time.Second

func externalSecretsFor(cfg Config) *clusterprovider.ExternalSecrets {
	return clusterkcp.ExternalSecrets(cfg.ExternalSecrets, cfg.ESOBundle, cfg.ESONamespace)
}

func tenantAddOns(cfg Config, logins *openbao.Logins, log *slog.Logger) func(context.Context, string, *clusterprovider.Credential) error {
	return func(ctx context.Context, cluster string, cred *clusterprovider.Credential) error {
		restCfg := clusterkcp.RestConfig(cred)
		dataDir, err := clusterprovider.ClusterDataDir(cfg.StateDir, cluster)
		if err != nil {
			return err
		}
		kc, err := kube.New(kcpserver.Throughput(rest.CopyConfig(restCfg)))
		if err != nil {
			return fmt.Errorf("clusterprovider: a dynamic client for %s's tenant add-ons: %w", cluster, err)
		}
		netCtx, netCancel := context.WithTimeout(ctx, tenantAddOnTimeout)
		err = tenantnet.Apply(netCtx, kc, clusterprovider.AddOnFieldManager)
		netCancel()
		if err != nil {
			return fmt.Errorf("clusterprovider: the node network add-ons of %s: %w", cluster, err)
		}
		log.Info("cluster provider: applied the node network add-ons",
			"cluster", cluster, "nodeReader", tenantnet.NodeReaderName, "nodeDNS", tenantnet.DNSName,
			"address", tenantnet.Address, "nodeLabel", tenantnet.NodeLabel,
			"meaning", "every node may list Nodes for socialweb-meshd, and a node whose user_data carries "+
				"the link-local DNS address runs its own CoreDNS there; both are ours and baseline",
			"item", "plan 0005 M5-DNS, M5-MESHD")
		bounded, cancel := context.WithTimeout(ctx, tenantAddOnTimeout)
		defer cancel()
		client, access, err := clusterprovider.ClusterVaultClient(bounded, logins, dataDir)
		if err != nil {
			return fmt.Errorf("clusterprovider: logging in to the cluster vault for the tenant add-ons of %s: %w", cluster, err)
		}
		vaultURL, err := esovault.ApplyVaultStore(bounded, kc, esovault.VaultStore{
			Cluster:     cluster,
			DataDir:     dataDir,
			VaultPort:   access.Port(),
			Client:      client,
			ManifestDir: cfg.ESOManifestDir,
			Namespace:   kcpclient.TenantNamespace,
		})
		if err != nil {
			return err
		}
		cs, err := kubernetes.NewForConfig(restCfg)
		if err != nil {
			return fmt.Errorf("clusterprovider: a client to measure the add-on baseline of %s: %w", cluster, err)
		}
		if err := measureTenantBaseline(ctx, cs, dataDir, cluster, log); err != nil {
			return err
		}
		log.Info("cluster provider: applied the tenant add-ons",
			"cluster", cluster, "manifests", cfg.ESOManifestDir,
			"namespace", kcpclient.TenantNamespace, "vault", vaultURL,
			"decision", "the External Secrets controller runs beside the control plane in this "+
				"cluster's process group, so the store dials the cluster vault on loopback and "+
				"syncs at zero nodes; the tenant holds only its CRDs and RBAC",
			"item", "NEXT.yaml ESO-4")
		return nil
	}
}

func measureTenantBaseline(ctx context.Context, cs kubernetes.Interface, dataDir, cluster string, log *slog.Logger) error {
	b, err := clusterkcp.MeasureAddOnBaseline(ctx, cs, clusterprovider.AddOnFieldManager, time.Now())
	if err != nil {
		return fmt.Errorf("clusterprovider: measuring the add-on baseline of %s: %w", cluster, err)
	}
	if err := clusterprovider.WriteAddOnBaseline(dataDir, b); err != nil {
		return err
	}
	names := make([]string, 0, len(b.Workloads))
	for _, w := range b.Workloads {
		names = append(names, w.WorkloadKey.String())
	}
	log.Info("cluster provider: measured the add-on baseline",
		"cluster", cluster, "manager", b.Manager, "workloads", names,
		"path", clusterprovider.AddOnBaselinePath(dataDir),
		"meaning", "a cluster holding exactly these workloads, with these specs, has nothing deployed "+
			"and scales to zero nodes; a changed spec or any other workload is a tenant's intent")
	return nil
}