@@ -13,6 +13,7 @@ import (
13
13
imagev1clientset "github.com/openshift/client-go/image/clientset/versioned"
14
14
mcfgclientset "github.com/openshift/client-go/machineconfiguration/clientset/versioned"
15
15
routeclientset "github.com/openshift/client-go/route/clientset/versioned"
16
+ "github.com/openshift/machine-config-operator/pkg/apihelpers"
16
17
"github.com/openshift/machine-config-operator/pkg/controller/build/buildrequest"
17
18
"github.com/openshift/machine-config-operator/pkg/controller/build/constants"
18
19
"github.com/openshift/machine-config-operator/pkg/controller/build/imagebuilder"
@@ -373,13 +374,11 @@ func (b *buildReconciler) UpdateMachineConfigPool(ctx context.Context, oldMCP, c
373
374
func (b * buildReconciler ) updateMachineConfigPool (ctx context.Context , oldMCP , curMCP * mcfgv1.MachineConfigPool ) error {
374
375
if oldMCP .Spec .Configuration .Name != curMCP .Spec .Configuration .Name {
375
376
klog .Infof ("Rendered config for pool %s changed from %s to %s" , curMCP .Name , oldMCP .Spec .Configuration .Name , curMCP .Spec .Configuration .Name )
376
- if err := b .createNewMachineOSBuildOrReuseExistingForPoolChange (ctx , curMCP ); err != nil {
377
+ if err := b .reconcilePoolChange (ctx , curMCP ); err != nil {
377
378
return fmt .Errorf ("could not create or reuse existing MachineOSBuild for MachineConfigPool %q change: %w" , curMCP .Name , err )
378
379
}
379
380
}
380
381
381
- // Not sure if we need to do this here yet or not.
382
- // TODO: Determine if we should call b.syncMachineConfigPools() here or not.
383
382
return b .syncAll (ctx )
384
383
}
385
384
@@ -556,7 +555,7 @@ func (b *buildReconciler) createNewMachineOSBuildOrReuseExisting(ctx context.Con
556
555
// In this situation, we've determined that the MachineOSBuild does not
557
556
// exist, so we need to create it.
558
557
if k8serrors .IsNotFound (err ) {
559
- _ , err := b .mcfgclient .MachineconfigurationV1 ().MachineOSBuilds ().Create (ctx , mosb , metav1.CreateOptions {})
558
+ mosb , err := b .mcfgclient .MachineconfigurationV1 ().MachineOSBuilds ().Create (ctx , mosb , metav1.CreateOptions {})
560
559
if err != nil && ! k8serrors .IsAlreadyExists (err ) {
561
560
return fmt .Errorf ("could not create new MachineOSBuild %q: %w" , mosb .Name , err )
562
561
}
@@ -1188,12 +1187,35 @@ func (b *buildReconciler) syncMachineOSBuild(ctx context.Context, mosb *mcfgv1.M
1188
1187
return fmt .Errorf ("could not get MachineConfigPool from MachineOSBuild %q: %w" , mosb .Name , err )
1189
1188
}
1190
1189
1191
- // An mosb which had previously been forgotten by the queue and is no longer desired by the mcp should not build
1192
1190
if mosb .ObjectMeta .Labels [constants .RenderedMachineConfigLabelKey ] != mcp .Spec .Configuration .Name {
1193
1191
klog .Infof ("The MachineOSBuild %q which builds the rendered Machine Config %q is no longer desired by the MCP %q" , mosb .Name , mosb .ObjectMeta .Labels [constants .RenderedMachineConfigLabelKey ], mosb .ObjectMeta .Labels [constants .TargetMachineConfigPoolLabelKey ])
1194
1192
return nil
1195
1193
}
1196
1194
1195
+ oldMCName := mcp .Status .Configuration .Name
1196
+ newMCName := mcp .Spec .Configuration .Name
1197
+
1198
+ oldRendered , err := b .machineConfigLister .Get (oldMCName )
1199
+ if err != nil {
1200
+ return err
1201
+ }
1202
+ newRendered , err := b .machineConfigLister .Get (newMCName )
1203
+ if err != nil {
1204
+ return err
1205
+ }
1206
+
1207
+ old := mcp .DeepCopy ()
1208
+ old .Spec .Configuration .Name = mcp .Status .Configuration .Name
1209
+
1210
+ needsImageRebuild , err := b .reconcileImageRebuild (old , mcp )
1211
+ if err != nil {
1212
+ return err
1213
+ }
1214
+ if oldRendered != newRendered && ! needsImageRebuild {
1215
+ klog .Infof ("MachineOSBuild %q: only layering changes → skipping image build" , mosb .Name )
1216
+ return nil
1217
+ }
1218
+
1197
1219
mosbState := ctrlcommon .NewMachineOSBuildState (mosb )
1198
1220
1199
1221
if mosbState .IsInTerminalState () {
@@ -1328,6 +1350,128 @@ func (b *buildReconciler) syncMachineConfigPools(ctx context.Context) error {
1328
1350
// if needed.
1329
1351
func (b * buildReconciler ) syncMachineConfigPool (ctx context.Context , mcp * mcfgv1.MachineConfigPool ) error {
1330
1352
return b .timeObjectOperation (mcp , syncingVerb , func () error {
1331
- return b .createNewMachineOSBuildOrReuseExistingForPoolChange (ctx , mcp )
1353
+ return b .reconcilePoolChange (ctx , mcp )
1354
+ })
1355
+ }
1356
+
1357
+ func (b * buildReconciler ) reconcilePoolChange (ctx context.Context , mcp * mcfgv1.MachineConfigPool ) error {
1358
+ mosc , err := utils .GetMachineOSConfigForMachineConfigPool (mcp , b .utilListers ())
1359
+ if err != nil {
1360
+ // Not opted in yet, so nothing for us to do.
1361
+ klog .Infof ("buildReconciler: no MachineOSConfig for pool %q, skipping" , mcp .Name )
1362
+ return nil
1363
+ }
1364
+
1365
+ oldRendered := mcp .Status .Configuration .Name
1366
+ newRendered := mcp .Spec .Configuration .Name
1367
+
1368
+ // old pool
1369
+ old := mcp .DeepCopy ()
1370
+ old .Spec .Configuration .Name = mcp .Status .Configuration .Name
1371
+ firstOptIn := mosc .Annotations [constants .CurrentMachineOSBuildAnnotationKey ]
1372
+ if firstOptIn == "" {
1373
+ return fmt .Errorf ("no current build annotation on MachineOSConfig %q" , mosc .Name )
1374
+ }
1375
+
1376
+ needsImageRebuild , err := b .reconcileImageRebuild (old , mcp )
1377
+ if err != nil {
1378
+ return err
1379
+ }
1380
+
1381
+ if (oldRendered != newRendered && needsImageRebuild ) || firstOptIn == "" {
1382
+ klog .Infof ("pool %q: detected extension/kernel/OSImageURL change → will rebuild image" , mcp .Name )
1383
+ } else if oldRendered != newRendered && ! needsImageRebuild {
1384
+ klog .Infof ("pool %q: only layering changes → reusing existing image" , mcp .Name )
1385
+ prevPullSpec := mosc .Status .CurrentImagePullSpec
1386
+ oldMOSB , err := utils .GetMachineOSBuildForImagePullspec (string (prevPullSpec ), b .utilListers ())
1387
+ if err != nil {
1388
+ return fmt .Errorf ("failed to look up MachineOSBuild %q: %w" , oldMOSB .Name , err )
1389
+ }
1390
+ return b .reuseImageForNewMOSB (ctx , mosc , oldMOSB )
1391
+ }
1392
+
1393
+ return b .createNewMachineOSBuildOrReuseExisting (ctx , mosc , needsImageRebuild )
1394
+
1395
+ }
1396
+
1397
+ // reuseImageForNewMOSB creates a new MOSB (for the new rendered-MC name)
1398
+ // but populates its status from oldMosb so that no build actually runs.
1399
+ func (b * buildReconciler ) reuseImageForNewMOSB (ctx context.Context , mosc * mcfgv1.MachineOSConfig , oldMosb * mcfgv1.MachineOSBuild ,
1400
+ ) error {
1401
+ // Look up the MCP
1402
+ mcp , err := b .machineConfigPoolLister .Get (mosc .Spec .MachineConfigPool .Name )
1403
+ if err != nil {
1404
+ return err
1405
+ }
1406
+
1407
+ // Build the new MOSB object
1408
+ osImageURLs , err := ctrlcommon .GetOSImageURLConfig (ctx , b .kubeclient )
1409
+ if err != nil {
1410
+ return err
1411
+ }
1412
+ newMosb , err := buildrequest .NewMachineOSBuild (
1413
+ buildrequest.MachineOSBuildOpts {
1414
+ MachineOSConfig : mosc ,
1415
+ MachineConfigPool : mcp ,
1416
+ OSImageURLConfig : osImageURLs ,
1417
+ })
1418
+ if err != nil {
1419
+ return err
1420
+ }
1421
+ newMosb .SetOwnerReferences ([]metav1.OwnerReference {
1422
+ * metav1 .NewControllerRef (mosc , mcfgv1 .SchemeGroupVersion .WithKind ("MachineOSConfig" )),
1332
1423
})
1424
+
1425
+ // Create it if not already there
1426
+ _ , err = b .machineOSBuildLister .Get (newMosb .Name )
1427
+ if k8serrors .IsNotFound (err ) {
1428
+ if newMosb , err = b .mcfgclient .
1429
+ MachineconfigurationV1 ().
1430
+ MachineOSBuilds ().
1431
+ Create (ctx , newMosb , metav1.CreateOptions {}); err != nil {
1432
+ return err
1433
+ }
1434
+ } else if err != nil {
1435
+ return err
1436
+ }
1437
+
1438
+ // Change its status so it’s “Succeeded” with the old image
1439
+ toUpdate , err := b .getMachineOSBuildForUpdate (newMosb )
1440
+ if err != nil {
1441
+ return err
1442
+ }
1443
+ oldStatus := toUpdate .Status
1444
+
1445
+ toUpdate .Status .DigestedImagePushSpec = oldMosb .Status .DigestedImagePushSpec
1446
+
1447
+ for _ , c := range apihelpers .MachineOSBuildSucceededConditions () {
1448
+ apihelpers .SetMachineOSBuildCondition (& toUpdate .Status , c )
1449
+ }
1450
+
1451
+ if err := b .setStatusOnMachineOSBuildIfNeeded (ctx , toUpdate , oldStatus , toUpdate .Status ); err != nil {
1452
+ return err
1453
+ }
1454
+
1455
+ // re-point the MC to the NEW build
1456
+ return b .updateMachineOSConfigStatus (ctx , mosc , toUpdate )
1457
+ }
1458
+
1459
+ // reconcilePoolChange returns (annotateRebuild bool, reuseOnly bool, err error)
1460
+ func (b * buildReconciler ) reconcileImageRebuild (oldMCP , curMCP * mcfgv1.MachineConfigPool ) (bool , error ) {
1461
+
1462
+ curr , err := b .machineConfigLister .Get (oldMCP .Spec .Configuration .Name )
1463
+ if err != nil {
1464
+ return false , err
1465
+ }
1466
+ des , err := b .machineConfigLister .Get (curMCP .Spec .Configuration .Name )
1467
+ if err != nil {
1468
+ return false , err
1469
+ }
1470
+
1471
+ needsImageRebuild := ctrlcommon .RequiresRebuild (curr , des )
1472
+ if needsImageRebuild {
1473
+ return true , nil
1474
+ }
1475
+
1476
+ return false , nil
1333
1477
}
0 commit comments