Repository: metal3-io/baremetal-operator
Pull request #1092 (2022-03-01 16:44:41)

Copy labels from BaremetalHost to PreprovisioningImage
This may be needed e.g. to find linked objects.


Patch:
diff --git a/controllers/metal3.io/baremetalhost_controller.go b/controllers/metal3.io/baremetalhost_controller.go
index 9d5eed0e..35e528d2 100644
--- a/controllers/metal3.io/baremetalhost_controller.go
+++ b/controllers/metal3.io/baremetalhost_controller.go
@@ -663,12 +663,12 @@ func (r *BareMetalHostReconciler) preprovImageAvailable(info *reconcileInfo, ima
 		return false, nil
 	}
 
-	if errCond := meta.FindStatusCondition(image.Status.Conditions, string(metal3v1alpha1.ConditionImageError)); errCond.Status == metav1.ConditionTrue {
+	if errCond := meta.FindStatusCondition(image.Status.Conditions, string(metal3v1alpha1.ConditionImageError)); errCond != nil && errCond.Status == metav1.ConditionTrue {
 		info.log.Info("error building PreprovisioningImage",
 			"message", errCond.Message)
 		return false, imageBuildError{errCond.Message}
 	}
-	if meta.IsStatusConditionTrue(image.Status.Conditions, string(metal3v1alpha1.ConditionImageReady)) {
+	if readyCond := meta.FindStatusCondition(image.Status.Conditions, string(metal3v1alpha1.ConditionImageReady)); readyCond != nil && readyCond.Status == metav1.ConditionTrue && readyCond.ObservedGeneration == image.Generation {
 		return true, nil
 	}
 
@@ -715,6 +715,7 @@ func (r *BareMetalHostReconciler) getPreprovImage(info *reconcileInfo, formats [
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      key.Name,
 				Namespace: key.Namespace,
+				Labels:    info.host.Labels,
 			},
 			Spec: expectedSpec,
 		}
@@ -726,12 +727,27 @@ func (r *BareMetalHostReconciler) getPreprovImage(info *reconcileInfo, formats [
 		return nil, errors.Wrap(err, "failed to retrieve pre-provisioning image data")
 	}
 
+	needsUpdate := false
+	if preprovImage.Labels == nil && len(info.host.Labels) > 0 {
+		preprovImage.Labels = make(map[string]string, len(info.host.Labels))
+	}
+	for k, v := range info.host.Labels {
+		if cur, ok := preprovImage.Labels[k]; !ok || cur != v {
+			preprovImage.Labels[k] = v
+			needsUpdate = true
+		}
+	}
 	if !apiequality.Semantic.DeepEqual(preprovImage.Spec, expectedSpec) {
 		info.log.Info("updating PreprovisioningImage spec")
 		preprovImage.Spec = expectedSpec
+		needsUpdate = true
+	}
+	if needsUpdate {
+		info.log.Info("updating PreprovisioningImage")
 		err = r.Update(context.TODO(), &preprovImage)
 		return nil, err
 	}
+
 	if available, err := r.preprovImageAvailable(info, &preprovImage); err != nil || !available {
 		return nil, err
 	}


Test patch:
diff --git a/controllers/metal3.io/baremetalhost_controller_test.go b/controllers/metal3.io/baremetalhost_controller_test.go
index 33e22fc7..f8b7c29d 100644
--- a/controllers/metal3.io/baremetalhost_controller_test.go
+++ b/controllers/metal3.io/baremetalhost_controller_test.go
@@ -2162,6 +2162,9 @@ func TestGetPreprovImageCreateUpdate(t *testing.T) {
 	secretName := "net_secret"
 	host := newDefaultHost(t)
 	host.Spec.PreprovisioningNetworkDataName = secretName
+	host.Labels = map[string]string{
+		"answer.metal3.io": "42",
+	}
 	r := newTestReconciler(host, newSecret(secretName, nil))
 	i := makeReconcileInfo(host)
 
@@ -2177,9 +2180,11 @@ func TestGetPreprovImageCreateUpdate(t *testing.T) {
 		&img))
 	assert.Equal(t, "x86_64", img.Spec.Architecture)
 	assert.Equal(t, secretName, img.Spec.NetworkDataName)
+	assert.Equal(t, "42", img.Labels["answer.metal3.io"])
 
 	newSecretName := "new_net_secret"
 	host.Spec.PreprovisioningNetworkDataName = newSecretName
+	host.Labels["cat.metal3.io"] = "meow"
 
 	imgData, err = r.getPreprovImage(i, []metal3v1alpha1.ImageFormat{"iso"})
 	assert.NoError(t, err)
@@ -2191,6 +2196,8 @@ func TestGetPreprovImageCreateUpdate(t *testing.T) {
 	},
 		&img))
 	assert.Equal(t, newSecretName, img.Spec.NetworkDataName)
+	assert.Equal(t, "42", img.Labels["answer.metal3.io"])
+	assert.Equal(t, "meow", img.Labels["cat.metal3.io"])
 }
 
 func TestGetPreprovImage(t *testing.T) {