@@ -26,6 +26,7 @@ import (
26
26
jsonpatch "github.com/evanphx/json-patch/v5"
27
27
"github.com/pkg/errors"
28
28
kerrors "k8s.io/apimachinery/pkg/util/errors"
29
+ "k8s.io/klog/v2"
29
30
30
31
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
31
32
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
@@ -83,6 +84,14 @@ func (e *engine) Apply(ctx context.Context, blueprint *scope.ClusterBlueprint, d
83
84
clusterClassPatch := blueprint .ClusterClass .Spec .Patches [i ]
84
85
ctx , log := log .WithValues ("patch" , clusterClassPatch .Name ).Into (ctx )
85
86
87
+ definitionFrom := clusterClassPatch .Name
88
+ // If this isn't an external patch, use the inline patch name.
89
+ if clusterClassPatch .External == nil {
90
+ definitionFrom = clusterv1 .VariableDefinitionFromInline
91
+ }
92
+ if err := addVariablesForPatch (blueprint , desired , req , definitionFrom ); err != nil {
93
+ return errors .Wrapf (err , "failed to calculate variables for patch %q" , clusterClassPatch .Name )
94
+ }
86
95
log .V (5 ).Infof ("Applying patch to templates" )
87
96
88
97
// Create patch generator for the current patch.
@@ -139,23 +148,86 @@ func (e *engine) Apply(ctx context.Context, blueprint *scope.ClusterBlueprint, d
139
148
return nil
140
149
}
141
150
151
+ // addVariablesForPatch adds variables for a given ClusterClassPatch to the items in the PatchRequest.
152
+ func addVariablesForPatch (blueprint * scope.ClusterBlueprint , desired * scope.ClusterState , req * runtimehooksv1.GeneratePatchesRequest , definitionFrom string ) error {
153
+ // If there is no definitionFrom return an error.
154
+ if definitionFrom == "" {
155
+ return errors .New ("failed to calculate variables: no patch name provided" )
156
+ }
157
+
158
+ patchVariableDefinitions := definitionsForPatch (blueprint , definitionFrom )
159
+ // Calculate global variables.
160
+ globalVariables , err := variables .Global (blueprint .Topology , desired .Cluster , definitionFrom , patchVariableDefinitions )
161
+ if err != nil {
162
+ return errors .Wrapf (err , "failed to calculate global variables" )
163
+ }
164
+ req .Variables = globalVariables
165
+
166
+ // Calculate the Control Plane variables.
167
+ controlPlaneVariables , err := variables .ControlPlane (& blueprint .Topology .ControlPlane , desired .ControlPlane .Object , desired .ControlPlane .InfrastructureMachineTemplate )
168
+ if err != nil {
169
+ return errors .Wrapf (err , "failed to calculate ControlPlane variables" )
170
+ }
171
+
172
+ mdStateIndex := map [string ]* scope.MachineDeploymentState {}
173
+ for _ , md := range desired .MachineDeployments {
174
+ mdStateIndex [md .Object .Name ] = md
175
+ }
176
+ for i , item := range req .Items {
177
+ // If the item is a Control Plane add the Control Plane variables.
178
+ if item .HolderReference .FieldPath == "spec.controlPlaneRef" {
179
+ item .Variables = controlPlaneVariables
180
+ }
181
+ // If the item holder reference is a Control Plane machine add the Control Plane variables.
182
+ if blueprint .HasControlPlaneInfrastructureMachine () &&
183
+ item .HolderReference .FieldPath == strings .Join (contract .ControlPlane ().MachineTemplate ().InfrastructureRef ().Path (), "." ) {
184
+ item .Variables = controlPlaneVariables
185
+ }
186
+ // If the item holder reference is a MachineDeployment calculate the variables for each MachineDeploymentTopology
187
+ // and add them to the variables for the MachineDeployment.
188
+ if item .HolderReference .Kind == "MachineDeployment" {
189
+ md , ok := mdStateIndex [item .HolderReference .Name ]
190
+ if ! ok {
191
+ return errors .Errorf ("could not find desired state for MachineDeployment %s" , klog .KObj (md .Object ))
192
+ }
193
+ mdTopology , err := getMDTopologyFromMD (blueprint , md .Object )
194
+ if err != nil {
195
+ return err
196
+ }
197
+
198
+ // Calculate MachineDeployment variables.
199
+ mdVariables , err := variables .MachineDeployment (mdTopology , md .Object , md .BootstrapTemplate , md .InfrastructureMachineTemplate , definitionFrom , patchVariableDefinitions )
200
+ if err != nil {
201
+ return errors .Wrapf (err , "failed to calculate variables for %s" , klog .KObj (md .Object ))
202
+ }
203
+ item .Variables = mdVariables
204
+ }
205
+ req .Items [i ] = item
206
+ }
207
+ return nil
208
+ }
209
+
210
+ func getMDTopologyFromMD (blueprint * scope.ClusterBlueprint , md * clusterv1.MachineDeployment ) (* clusterv1.MachineDeploymentTopology , error ) {
211
+ topologyName , ok := md .Labels [clusterv1 .ClusterTopologyMachineDeploymentNameLabel ]
212
+ if ! ok {
213
+ return nil , errors .Errorf ("failed to get topology name for %s" , klog .KObj (md ))
214
+ }
215
+ mdTopology , err := lookupMDTopology (blueprint .Topology , topologyName )
216
+ if err != nil {
217
+ return nil , err
218
+ }
219
+ return mdTopology , nil
220
+ }
221
+
142
222
// createRequest creates a GeneratePatchesRequest based on the ClusterBlueprint and the desired state.
143
- // ClusterBlueprint supplies the templates. Desired state is used to calculate variables which are later used
144
- // as input for the patch generation.
145
223
// NOTE: GenerateRequestTemplates are created for the templates of each individual MachineDeployment in the desired
146
224
// state. This is necessary because some builtin variables are MachineDeployment specific. For example version and
147
225
// replicas of a MachineDeployment.
148
226
// NOTE: A single GeneratePatchesRequest object is used to carry templates state across subsequent Generate calls.
227
+ // NOTE: This function does not add variables to items for the request, as the variables depend on the specific patch.
149
228
func createRequest (blueprint * scope.ClusterBlueprint , desired * scope.ClusterState ) (* runtimehooksv1.GeneratePatchesRequest , error ) {
150
229
req := & runtimehooksv1.GeneratePatchesRequest {}
151
230
152
- // Calculate global variables.
153
- globalVariables , err := variables .Global (blueprint .Topology , desired .Cluster )
154
- if err != nil {
155
- return nil , errors .Wrapf (err , "failed to calculate global variables" )
156
- }
157
- req .Variables = globalVariables
158
-
159
231
// Add the InfrastructureClusterTemplate.
160
232
t , err := newRequestItemBuilder (blueprint .InfrastructureClusterTemplate ).
161
233
WithHolder (desired .Cluster , "spec.infrastructureRef" ).
@@ -166,12 +238,6 @@ func createRequest(blueprint *scope.ClusterBlueprint, desired *scope.ClusterStat
166
238
}
167
239
req .Items = append (req .Items , * t )
168
240
169
- // Calculate controlPlane variables.
170
- controlPlaneVariables , err := variables .ControlPlane (& blueprint .Topology .ControlPlane , desired .ControlPlane .Object , desired .ControlPlane .InfrastructureMachineTemplate )
171
- if err != nil {
172
- return nil , errors .Wrapf (err , "failed to calculate ControlPlane variables" )
173
- }
174
-
175
241
// Add the ControlPlaneTemplate.
176
242
t , err = newRequestItemBuilder (blueprint .ControlPlane .Template ).
177
243
WithHolder (desired .Cluster , "spec.controlPlaneRef" ).
@@ -180,7 +246,6 @@ func createRequest(blueprint *scope.ClusterBlueprint, desired *scope.ClusterStat
180
246
return nil , errors .Wrapf (err , "failed to prepare ControlPlane template %s for patching" ,
181
247
tlog.KObj {Obj : blueprint .ControlPlane .Template })
182
248
}
183
- t .Variables = controlPlaneVariables
184
249
req .Items = append (req .Items , * t )
185
250
186
251
// If the clusterClass mandates the controlPlane has infrastructureMachines,
@@ -193,7 +258,6 @@ func createRequest(blueprint *scope.ClusterBlueprint, desired *scope.ClusterStat
193
258
return nil , errors .Wrapf (err , "failed to prepare ControlPlane's machine template %s for patching" ,
194
259
tlog.KObj {Obj : blueprint .ControlPlane .InfrastructureMachineTemplate })
195
260
}
196
- t .Variables = controlPlaneVariables
197
261
req .Items = append (req .Items , * t )
198
262
}
199
263
@@ -216,12 +280,6 @@ func createRequest(blueprint *scope.ClusterBlueprint, desired *scope.ClusterStat
216
280
return nil , errors .Errorf ("failed to lookup MachineDeployment class %q in ClusterClass" , mdTopology .Class )
217
281
}
218
282
219
- // Calculate MachineDeployment variables.
220
- mdVariables , err := variables .MachineDeployment (mdTopology , md .Object , md .BootstrapTemplate , md .InfrastructureMachineTemplate )
221
- if err != nil {
222
- return nil , errors .Wrapf (err , "failed to calculate variables for %s" , tlog.KObj {Obj : md .Object })
223
- }
224
-
225
283
// Add the BootstrapTemplate.
226
284
t , err := newRequestItemBuilder (mdClass .BootstrapTemplate ).
227
285
WithHolder (md .Object , "spec.template.spec.bootstrap.configRef" ).
@@ -230,7 +288,6 @@ func createRequest(blueprint *scope.ClusterBlueprint, desired *scope.ClusterStat
230
288
return nil , errors .Wrapf (err , "failed to prepare BootstrapConfig template %s for MachineDeployment topology %s for patching" ,
231
289
tlog.KObj {Obj : mdClass .BootstrapTemplate }, mdTopologyName )
232
290
}
233
- t .Variables = mdVariables
234
291
req .Items = append (req .Items , * t )
235
292
236
293
// Add the InfrastructureMachineTemplate.
@@ -241,7 +298,6 @@ func createRequest(blueprint *scope.ClusterBlueprint, desired *scope.ClusterStat
241
298
return nil , errors .Wrapf (err , "failed to prepare InfrastructureMachine template %s for MachineDeployment topology %s for patching" ,
242
299
tlog.KObj {Obj : mdClass .InfrastructureMachineTemplate }, mdTopologyName )
243
300
}
244
- t .Variables = mdVariables
245
301
req .Items = append (req .Items , * t )
246
302
}
247
303
@@ -431,3 +487,16 @@ func updateDesiredState(ctx context.Context, req *runtimehooksv1.GeneratePatches
431
487
432
488
return nil
433
489
}
490
+
491
+ // definitionsForPatch returns a set which of variables in a ClusterClass defined by "definitionFrom".
492
+ func definitionsForPatch (blueprint * scope.ClusterBlueprint , definitionFrom string ) map [string ]bool {
493
+ variableDefinitionsForPatch := make (map [string ]bool )
494
+ for _ , definitionsWithName := range blueprint .ClusterClass .Status .Variables {
495
+ for _ , definition := range definitionsWithName .Definitions {
496
+ if definition .From == definitionFrom {
497
+ variableDefinitionsForPatch [definitionsWithName .Name ] = true
498
+ }
499
+ }
500
+ }
501
+ return variableDefinitionsForPatch
502
+ }
0 commit comments