@@ -5,33 +5,35 @@ package controller
55
66import (
77 "context"
8+ "encoding/json"
89 "fmt"
910 "strings"
11+ "time"
1012
1113 "github.com/go-logr/logr"
14+ "github.com/imdario/mergo"
15+ infrav1alpha1 "github.com/ironcore-dev/cluster-api-provider-ironcore-metal/api/v1alpha1"
1216 "github.com/ironcore-dev/cluster-api-provider-ironcore-metal/internal/scope"
1317 "github.com/ironcore-dev/controller-utils/clientutils"
18+ metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1"
1419 "github.com/pkg/errors"
1520 corev1 "k8s.io/api/core/v1"
1621 apierrors "k8s.io/apimachinery/pkg/api/errors"
1722 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23+ "k8s.io/apimachinery/pkg/runtime"
1824 "k8s.io/apimachinery/pkg/types"
25+ "k8s.io/apimachinery/pkg/util/wait"
1926 "k8s.io/klog/v2"
20-
2127 clusterapiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1"
28+ capiv1beta1 "sigs.k8s.io/cluster-api/exp/ipam/api/v1beta1"
2229 "sigs.k8s.io/cluster-api/util"
2330 "sigs.k8s.io/cluster-api/util/annotations"
24- "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
25- "sigs.k8s.io/controller-runtime/pkg/handler"
26- "sigs.k8s.io/controller-runtime/pkg/reconcile"
27-
28- "k8s.io/apimachinery/pkg/runtime"
2931 ctrl "sigs.k8s.io/controller-runtime"
3032 "sigs.k8s.io/controller-runtime/pkg/client"
33+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
34+ "sigs.k8s.io/controller-runtime/pkg/handler"
3135 "sigs.k8s.io/controller-runtime/pkg/log"
32-
33- infrav1alpha1 "github.com/ironcore-dev/cluster-api-provider-ironcore-metal/api/v1alpha1"
34- metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1"
36+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
3537)
3638
3739// IroncoreMetalMachineReconciler reconciles a IroncoreMetalMachine object
@@ -220,8 +222,15 @@ func (r *IroncoreMetalMachineReconciler) reconcileNormal(ctx context.Context, ma
220222 return ctrl.Result {}, err
221223 }
222224
225+ machineScope .Info ("Creating secret data" , "Secret" , machineScope .IroncoreMetalMachine .Name )
226+ secretData , err := r .createSecretData (ctx , machineScope .Logger , machineScope .IroncoreMetalMachine , bootstrapSecret .Data ["value" ])
227+ if err != nil {
228+ machineScope .Error (err , "failed to create or patch ignition secret" )
229+ return ctrl.Result {}, err
230+ }
231+
223232 machineScope .Info ("Creating IgnitionSecret" , "Secret" , machineScope .IroncoreMetalMachine .Name )
224- ignitionSecret , err := r .applyIgnitionSecret (ctx , machineScope .Logger , machineScope .IroncoreMetalMachine , bootstrapSecret )
233+ ignitionSecret , err := r .applyIgnitionSecret (ctx , machineScope .Logger , machineScope .IroncoreMetalMachine , bootstrapSecret , secretData )
225234 if err != nil {
226235 machineScope .Error (err , "failed to create or patch ignition secret" )
227236 return ctrl.Result {}, err
@@ -254,10 +263,91 @@ func (r *IroncoreMetalMachineReconciler) reconcileNormal(ctx context.Context, ma
254263 return reconcile.Result {}, nil
255264}
256265
257- func (r * IroncoreMetalMachineReconciler ) applyIgnitionSecret (ctx context.Context , log * logr.Logger , ironcoremetalmachine * infrav1alpha1.IroncoreMetalMachine , capidatasecret * corev1.Secret ) (* corev1.Secret , error ) {
258- dataSecret := capidatasecret
259- findAndReplaceIgnition (ironcoremetalmachine , dataSecret )
266+ func (r * IroncoreMetalMachineReconciler ) createSecretData (ctx context.Context , log * logr.Logger , ironcoremetalmachine * infrav1alpha1.IroncoreMetalMachine , secretData []byte ) ([]byte , error ) {
267+ secretData = findAndReplaceIgnition (ironcoremetalmachine , secretData )
260268
269+ secretDataMap := make (map [string ]any )
270+ if err := json .Unmarshal (secretData , & secretDataMap ); err != nil {
271+ return nil , fmt .Errorf ("failed to unmarshal secret data: %w" , err )
272+ }
273+ if err := r .applyIPAddresses (ctx , log , ironcoremetalmachine , secretDataMap ); err != nil {
274+ return nil , fmt .Errorf ("failed to apply IPAddresses: %w" , err )
275+ }
276+ return json .Marshal (secretDataMap )
277+ }
278+
279+ func (r * IroncoreMetalMachineReconciler ) applyIPAddresses (ctx context.Context , log * logr.Logger , ironcoremetalmachine * infrav1alpha1.IroncoreMetalMachine , data map [string ]any ) error {
280+ for _ , networkRef := range ironcoremetalmachine .Spec .IPAMConfig {
281+ ipAddrKey := client .ObjectKeyFromObject (ironcoremetalmachine )
282+ ipClaim := & capiv1beta1.IPAddressClaim {}
283+ if err := r .Client .Get (ctx , ipAddrKey , ipClaim ); err != nil && ! apierrors .IsNotFound (err ) {
284+ return err
285+
286+ } else if err == nil {
287+ log .V (3 ).Info ("IP found" , "IP" , ipAddrKey .String ())
288+ if ipClaim .Status .AddressRef .Name == "" {
289+ return errors .New ("IP address claim isn't ready" )
290+ }
291+
292+ } else if apierrors .IsNotFound (err ) {
293+ if networkRef .IPAMRef == nil {
294+ return errors .New ("ipamRef of an ipamConfig is not set" )
295+ }
296+ log .V (3 ).Info ("creating IP address claim" , "name" , ipAddrKey .String ())
297+ apiGroup := capiv1beta1 .GroupVersion .Group
298+ ipClaim = & capiv1beta1.IPAddressClaim {
299+ ObjectMeta : metav1.ObjectMeta {
300+ Name : ipAddrKey .Name ,
301+ Namespace : ipAddrKey .Namespace ,
302+ },
303+ Spec : capiv1beta1.IPAddressClaimSpec {
304+ PoolRef : corev1.TypedLocalObjectReference {
305+ APIGroup : & apiGroup ,
306+ Kind : "GlobalInClusterIPPool" ,
307+ Name : networkRef .IPAMRef .Name ,
308+ },
309+ },
310+ }
311+ if err = r .Client .Create (ctx , ipClaim ); err != nil {
312+ return fmt .Errorf ("error creating IP: %w" , err )
313+ }
314+
315+ // Wait for the IP address claim to reach the ready state
316+ err = wait .PollUntilContextTimeout (
317+ ctx ,
318+ time .Millisecond * 50 ,
319+ time .Millisecond * 340 ,
320+ true ,
321+ func (ctx context.Context ) (bool , error ) {
322+ if err = r .Client .Get (ctx , ipAddrKey , ipClaim ); err != nil && ! apierrors .IsNotFound (err ) {
323+ return false , err
324+ }
325+ return ipClaim .Status .AddressRef .Name != "" , nil
326+ })
327+ if err != nil {
328+ return err
329+ }
330+ }
331+
332+ ipAddr := & capiv1beta1.IPAddress {}
333+ if err := r .Client .Get (ctx , ipAddrKey , ipAddr ); err != nil {
334+ return err
335+ }
336+ addressMetaData := map [string ]any {
337+ networkRef .MetadataKey : map [string ]any {
338+ "ip" : ipAddr .Spec .Address ,
339+ "prefix" : ipAddr .Spec .Prefix ,
340+ "gateway" : ipAddr .Spec .Gateway ,
341+ },
342+ }
343+ if err := mergo .Merge (& data , addressMetaData , mergo .WithOverride ); err != nil {
344+ return fmt .Errorf ("failed to merge addressMetaData: %w" , err )
345+ }
346+ }
347+ return nil
348+ }
349+
350+ func (r * IroncoreMetalMachineReconciler ) applyIgnitionSecret (ctx context.Context , log * logr.Logger , ironcoremetalmachine * infrav1alpha1.IroncoreMetalMachine , capidatasecret * corev1.Secret , secretData []byte ) (* corev1.Secret , error ) {
261351 secretObj := & corev1.Secret {
262352 ObjectMeta : metav1.ObjectMeta {
263353 Name : fmt .Sprintf ("ignition-%s" , capidatasecret .Name ),
@@ -268,7 +358,7 @@ func (r *IroncoreMetalMachineReconciler) applyIgnitionSecret(ctx context.Context
268358 APIVersion : corev1 .SchemeGroupVersion .String (),
269359 },
270360 Data : map [string ][]byte {
271- DefaultIgnitionSecretKeyName : dataSecret . Data [ "value" ] ,
361+ DefaultIgnitionSecretKeyName : secretData ,
272362 },
273363 }
274364
@@ -345,12 +435,10 @@ func (r *IroncoreMetalMachineReconciler) ensureServerClaimBound(ctx context.Cont
345435 return true , nil
346436}
347437
348- func findAndReplaceIgnition (ironcoremetalmachine * infrav1alpha1.IroncoreMetalMachine , capidatasecret * corev1.Secret ) {
349- data := capidatasecret .Data ["value" ]
350-
438+ func findAndReplaceIgnition (ironcoremetalmachine * infrav1alpha1.IroncoreMetalMachine , data []byte ) []byte {
351439 // replace $${METAL_HOSTNAME} with machine name
352440 hostname := "%24%24%7BMETAL_HOSTNAME%7D"
353441 modifiedData := strings .ReplaceAll (string (data ), hostname , ironcoremetalmachine .Name )
354442
355- capidatasecret . Data [ "value" ] = []byte (modifiedData )
443+ return []byte (modifiedData )
356444}
0 commit comments