|
| 1 | +// Package accessors provides accessor functions for the ToolHive operator |
| 2 | +package accessors |
| 3 | + |
| 4 | +import ( |
| 5 | + "maps" |
| 6 | + |
| 7 | + mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1" |
| 8 | +) |
| 9 | + |
| 10 | +// MCPServerFieldAccessor provides accessor methods for handling labels and annotations |
| 11 | +type MCPServerFieldAccessor interface { |
| 12 | + // GetProxyDeploymentLabelsAndAnnotations returns labels and annotations for the deployment |
| 13 | + GetProxyDeploymentLabelsAndAnnotations(mcpServer *mcpv1alpha1.MCPServer) (labels, annotations map[string]string) |
| 14 | + |
| 15 | + // GetProxyDeploymentTemplateLabelsAndAnnotations returns labels and annotations for the deployment pod template |
| 16 | + GetProxyDeploymentTemplateLabelsAndAnnotations(mcpServer *mcpv1alpha1.MCPServer) (labels, annotations map[string]string) |
| 17 | +} |
| 18 | + |
| 19 | +// mcpServerFieldAccessor implements MCPServerFieldAccessor |
| 20 | +type mcpServerFieldAccessor struct{} |
| 21 | + |
| 22 | +// NewMCPServerFieldAccessor creates a new MCPServerFieldAccessor instance |
| 23 | +func NewMCPServerFieldAccessor() MCPServerFieldAccessor { |
| 24 | + return &mcpServerFieldAccessor{} |
| 25 | +} |
| 26 | + |
| 27 | +// GetProxyDeploymentLabelsAndAnnotations returns labels and annotations for the deployment |
| 28 | +func (*mcpServerFieldAccessor) GetProxyDeploymentLabelsAndAnnotations( |
| 29 | + mcpServer *mcpv1alpha1.MCPServer, |
| 30 | +) (map[string]string, map[string]string) { |
| 31 | + baseAnnotations := make(map[string]string) |
| 32 | + baseLabels := make(map[string]string) |
| 33 | + |
| 34 | + if mcpServer.Spec.ResourceOverrides == nil || |
| 35 | + mcpServer.Spec.ResourceOverrides.ProxyDeployment == nil { |
| 36 | + return baseLabels, baseAnnotations |
| 37 | + } |
| 38 | + |
| 39 | + deploymentLabels := baseLabels |
| 40 | + deploymentAnnotations := baseAnnotations |
| 41 | + |
| 42 | + if mcpServer.Spec.ResourceOverrides.ProxyDeployment.Labels != nil { |
| 43 | + deploymentLabels = mergeLabels(baseLabels, mcpServer.Spec.ResourceOverrides.ProxyDeployment.Labels) |
| 44 | + } |
| 45 | + if mcpServer.Spec.ResourceOverrides.ProxyDeployment.Annotations != nil { |
| 46 | + deploymentAnnotations = mergeAnnotations(baseAnnotations, mcpServer.Spec.ResourceOverrides.ProxyDeployment.Annotations) |
| 47 | + } |
| 48 | + |
| 49 | + return deploymentLabels, deploymentAnnotations |
| 50 | +} |
| 51 | + |
| 52 | +// GetProxyDeploymentTemplateLabelsAndAnnotations returns labels and annotations for the deployment pod template |
| 53 | +func (*mcpServerFieldAccessor) GetProxyDeploymentTemplateLabelsAndAnnotations( |
| 54 | + mcpServer *mcpv1alpha1.MCPServer, |
| 55 | +) (map[string]string, map[string]string) { |
| 56 | + baseAnnotations := make(map[string]string) |
| 57 | + baseLabels := make(map[string]string) |
| 58 | + |
| 59 | + if mcpServer.Spec.ResourceOverrides == nil || |
| 60 | + mcpServer.Spec.ResourceOverrides.ProxyDeployment == nil || |
| 61 | + mcpServer.Spec.ResourceOverrides.ProxyDeployment.PodTemplateMetadataOverrides == nil { |
| 62 | + return baseLabels, baseAnnotations |
| 63 | + } |
| 64 | + |
| 65 | + deploymentLabels := baseLabels |
| 66 | + deploymentAnnotations := baseAnnotations |
| 67 | + |
| 68 | + if mcpServer.Spec.ResourceOverrides.ProxyDeployment.PodTemplateMetadataOverrides.Labels != nil { |
| 69 | + deploymentLabels = mergeLabels(baseLabels, mcpServer.Spec.ResourceOverrides.ProxyDeployment.PodTemplateMetadataOverrides.Labels) |
| 70 | + } |
| 71 | + if mcpServer.Spec.ResourceOverrides.ProxyDeployment.PodTemplateMetadataOverrides.Annotations != nil { |
| 72 | + overrides := mcpServer.Spec.ResourceOverrides.ProxyDeployment.PodTemplateMetadataOverrides.Annotations |
| 73 | + deploymentAnnotations = mergeAnnotations(baseAnnotations, overrides) |
| 74 | + } |
| 75 | + |
| 76 | + return deploymentLabels, deploymentAnnotations |
| 77 | +} |
| 78 | + |
| 79 | +// mergeLabels merges override labels with default labels, with default labels taking precedence |
| 80 | +func mergeLabels(defaultLabels, overrideLabels map[string]string) map[string]string { |
| 81 | + return mergeStringMaps(defaultLabels, overrideLabels) |
| 82 | +} |
| 83 | + |
| 84 | +// mergeAnnotations merges override annotations with default annotations, with default annotations taking precedence |
| 85 | +func mergeAnnotations(defaultAnnotations, overrideAnnotations map[string]string) map[string]string { |
| 86 | + return mergeStringMaps(defaultAnnotations, overrideAnnotations) |
| 87 | +} |
| 88 | + |
| 89 | +// mergeStringMaps merges override map with default map, with default map taking precedence |
| 90 | +// This ensures that operator-required metadata is preserved for proper functionality |
| 91 | +func mergeStringMaps(defaultMap, overrideMap map[string]string) map[string]string { |
| 92 | + if overrideMap == nil && defaultMap == nil { |
| 93 | + return make(map[string]string) |
| 94 | + } |
| 95 | + if overrideMap == nil { |
| 96 | + return maps.Clone(defaultMap) |
| 97 | + } |
| 98 | + result := maps.Clone(overrideMap) |
| 99 | + if defaultMap != nil { |
| 100 | + maps.Copy(result, defaultMap) // default map takes precedence |
| 101 | + } |
| 102 | + return result |
| 103 | +} |
0 commit comments