135 lines
3.9 KiB
Go
135 lines
3.9 KiB
Go
package builder
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1"
|
|
"vanderlande.com/ittp/appstack/rig-operator/internal/provider"
|
|
)
|
|
|
|
// ChartConfig holds the helm settings extracted from the YAML _defaults
|
|
// The Controller needs this to know WHICH chart to fetch.
|
|
type ChartConfig struct {
|
|
Repo string
|
|
Name string
|
|
Version string
|
|
}
|
|
|
|
type MasterBuilder struct {
|
|
strategy provider.Strategy
|
|
baseTemplate []byte
|
|
chartConfig ChartConfig
|
|
}
|
|
|
|
func NewMasterBuilder(strategy provider.Strategy, baseTemplate []byte) *MasterBuilder {
|
|
b := &MasterBuilder{
|
|
strategy: strategy,
|
|
baseTemplate: baseTemplate,
|
|
// Safe defaults
|
|
chartConfig: ChartConfig{
|
|
Name: "oci://ghcr.io/rancherfederal/charts/rancher-cluster-templates",
|
|
},
|
|
}
|
|
return b
|
|
}
|
|
|
|
// GetChartConfig returns the chart details found in the template.
|
|
func (b *MasterBuilder) GetChartConfig() ChartConfig {
|
|
return b.chartConfig
|
|
}
|
|
|
|
// Build orchestrates the values generation process
|
|
func (b *MasterBuilder) Build(ctx context.Context, cbp *v1alpha1.ClusterBlueprint, credentialSecret string) (map[string]interface{}, error) {
|
|
values := make(map[string]interface{})
|
|
if err := yaml.Unmarshal(b.baseTemplate, &values); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal base template: %w", err)
|
|
}
|
|
|
|
// 1. Extract Chart Config from _defaults (Legacy Logic Ported)
|
|
// We do this so the Controller knows what version to install.
|
|
if defaults, ok := values["_defaults"].(map[string]interface{}); ok {
|
|
if chartCfg, ok := defaults["helmChart"].(map[string]interface{}); ok {
|
|
if v, ok := chartCfg["repo"].(string); ok {
|
|
b.chartConfig.Repo = v
|
|
}
|
|
if v, ok := chartCfg["name"].(string); ok {
|
|
b.chartConfig.Name = v
|
|
}
|
|
if v, ok := chartCfg["version"].(string); ok {
|
|
b.chartConfig.Version = v
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. Generate Node Pools (Delegated to Strategy)
|
|
// [DIFFERENCE]: We don't loop here. The Strategy knows how to map CBP -> Provider NodePools.
|
|
nodePools, err := b.strategy.GenerateNodePools(ctx, cbp)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("strategy failed to generate node pools: %w", err)
|
|
}
|
|
|
|
// 3. Get Global Overrides (Delegated to Strategy)
|
|
// [DIFFERENCE]: We don't hardcode "cloud_provider_name" here. The Strategy returns it.
|
|
overrides, err := b.strategy.GetGlobalOverrides(ctx, cbp, credentialSecret)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("strategy failed to get global overrides: %w", err)
|
|
}
|
|
|
|
// 4. Inject Logic into the Helm Structure
|
|
if clusterMap, ok := values["cluster"].(map[string]interface{}); ok {
|
|
clusterMap["name"] = cbp.Name
|
|
|
|
if configMap, ok := clusterMap["config"].(map[string]interface{}); ok {
|
|
configMap["kubernetesVersion"] = cbp.Spec.KubernetesVersion
|
|
|
|
// Ensure globalConfig exists
|
|
if _, ok := configMap["globalConfig"]; !ok {
|
|
configMap["globalConfig"] = make(map[string]interface{})
|
|
}
|
|
globalConfig := configMap["globalConfig"].(map[string]interface{})
|
|
|
|
// Inject Overrides
|
|
for k, v := range overrides {
|
|
// A. Handle specific Global Config keys
|
|
if k == "cloud_provider_name" || k == "cloud_provider_config" {
|
|
globalConfig[k] = v
|
|
continue
|
|
}
|
|
|
|
// B. Handle Chart Values (CCM/CSI Addons)
|
|
if k == "chartValues" {
|
|
if existingChartVals, ok := configMap["chartValues"].(map[string]interface{}); ok {
|
|
if newChartVals, ok := v.(map[string]interface{}); ok {
|
|
for ck, cv := range newChartVals {
|
|
existingChartVals[ck] = cv
|
|
}
|
|
}
|
|
} else {
|
|
configMap["chartValues"] = v
|
|
}
|
|
continue
|
|
}
|
|
|
|
// C. Default: Inject at Root level
|
|
values[k] = v
|
|
}
|
|
}
|
|
}
|
|
|
|
// 5. Inject Node Pools
|
|
// We marshal/unmarshal to ensure JSON tags from the Strategy structs are respected
|
|
tempJSON, _ := json.Marshal(nodePools)
|
|
var cleanNodePools interface{}
|
|
_ = json.Unmarshal(tempJSON, &cleanNodePools)
|
|
values["nodepools"] = cleanNodePools
|
|
|
|
// 6. Cleanup internal keys
|
|
delete(values, "_defaults")
|
|
|
|
return values, nil
|
|
}
|