package vsphere import ( "context" rigv1 "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" vspheretpl "vanderlande.com/ittp/appstack/rig-operator/internal/templates/vsphere" ) type Strategy struct { blueprint *rigv1.VsphereBlueprint userData string rancherURL string defaults vspheretpl.Defaults } // NewStrategy creates the vSphere logic handler func NewStrategy(vbp *rigv1.VsphereBlueprint, userData string, rancherURL string, defaults vspheretpl.Defaults) *Strategy { // 1. Resolve UserData (Infra > Template Default) finalUserData := userData if finalUserData == "" { finalUserData = defaults.UserData } return &Strategy{ blueprint: vbp, userData: finalUserData, rancherURL: rancherURL, defaults: defaults, } } // GenerateNodePools maps the generic ClusterBlueprint to vSphere-specific NodePool maps func (s *Strategy) GenerateNodePools(ctx context.Context, cbp *rigv1.ClusterBlueprint) (interface{}, error) { var nodePools []map[string]interface{} // 1. Control Plane Node Pool // We rely on the defaults extracted from values.yaml (e.g. 4 Core, 8GB) // vSphere Chart expects MB, so we multiply GB * 1024. cpQty := 1 if cbp.Spec.ControlPlaneHA { cpQty = 3 } nodePools = append(nodePools, s.buildPool( "control-plane-nodes", // Name "cp-nodes", // Display Name cpQty, // Quantity s.defaults.CP_CPU, // Cores s.defaults.CP_Mem*1024, // RAM (GB -> MB) s.defaults.CP_Disk*1024, // Disk (GB -> MB) true, // Etcd true, // ControlPlane false, // Worker )) // 2. Worker Pools // We iterate over the user's requested pools in the CBP for _, wp := range cbp.Spec.WorkerPools { nodePools = append(nodePools, s.buildPool( wp.Name, wp.Name, wp.Quantity, wp.CpuCores, wp.MemoryGB*1024, // Convert GB to MB wp.DiskGB*1024, // Convert GB to MB false, // Etcd false, // ControlPlane true, // Worker )) } return nodePools, nil } // GetGlobalOverrides injects the vSphere-specific global values (Cloud Provider, Credentials, URLs) func (s *Strategy) GetGlobalOverrides(ctx context.Context, cbp *rigv1.ClusterBlueprint, credentialSecret string) (map[string]interface{}, error) { overrides := map[string]interface{}{ // Tell Helm we are on vSphere "cloudprovider": "vsphere", // The Secret containing username/password/vcenter-address "cloudCredentialSecretName": credentialSecret, // Register with the correct Rancher Manager "rancher": map[string]interface{}{ "cattle": map[string]interface{}{ "url": s.rancherURL, }, }, // Cluster Metadata "cluster": map[string]interface{}{ "name": cbp.Name, "config": map[string]interface{}{ "kubernetesVersion": cbp.Spec.KubernetesVersion, }, }, } return overrides, nil } // buildPool is a private helper to construct the exact map structure the vSphere Helm Chart expects func (s *Strategy) buildPool(name, displayName string, qty, cpu, ramMB, diskMB int, etcd, cp, worker bool) map[string]interface{} { pool := map[string]interface{}{ // Generic RKE2 Node Settings "name": name, "displayName": displayName, "quantity": qty, "etcd": etcd, "controlplane": cp, "worker": worker, "paused": false, // vSphere Infrastructure Location (From Blueprint) "vcenter": s.blueprint.Spec.VCenter, "datacenter": s.blueprint.Spec.Datacenter, "folder": s.blueprint.Spec.Folder, "pool": s.blueprint.Spec.ResourcePool, "datastoreCluster": s.blueprint.Spec.Datastore, // Assumes chart supports this key. If not, use "datastore". "network": []string{s.blueprint.Spec.Network}, // Cloning Details "creationType": "template", "cloneFrom": s.blueprint.Spec.Template, // Hardware Sizing (Already converted to MB) "cpuCount": cpu, "memorySize": ramMB, "diskSize": diskMB, // Cloud Init "cloudConfig": s.userData, } return pool }