in pkg/controllers/overrider/resource_controller.go [85:159]
func (r *ResourceReconciler) ensureResourceOverrideSnapshot(ctx context.Context, ro *placementv1alpha1.ResourceOverride, revisionHistoryLimit int) error {
croKObj := klog.KObj(ro)
overridePolicy := ro.Spec
overrideSpecHash, err := resource.HashOf(overridePolicy)
if err != nil {
klog.ErrorS(err, "Failed to generate policy hash of ResourceOverride", "ResourceOverride", croKObj)
return controller.NewUnexpectedBehaviorError(err)
}
// we need to list the snapshots anyway since we need to remove the extra snapshots if there are too many of them.
snapshotList, err := r.listSortedOverrideSnapshots(ctx, ro)
if err != nil {
return err
}
// delete redundant snapshot revisions before creating a new snapshot to guarantee that the number of snapshots won't exceed the limit.
if err = r.removeExtraSnapshot(ctx, snapshotList, revisionHistoryLimit); err != nil {
return err
}
latestSnapshotIndex := -1
if len(snapshotList.Items) != 0 {
// convert the last unstructured snapshot to the typed object
latestSnapshot := &placementv1alpha1.ResourceOverrideSnapshot{}
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(snapshotList.Items[len(snapshotList.Items)-1].Object, latestSnapshot); err != nil {
klog.ErrorS(err, "Invalid overrideSnapshot", "ResourceOverride", croKObj, "overrideSnapshot", klog.KObj(&snapshotList.Items[len(snapshotList.Items)-1]))
return controller.NewUnexpectedBehaviorError(err)
}
if string(latestSnapshot.Spec.OverrideHash) == overrideSpecHash {
// the content has not changed, so we don't need to create a new snapshot.
return r.ensureSnapshotLatest(ctx, latestSnapshot)
}
// mark the last policy snapshot as inactive if it is different from what we have now.
if latestSnapshot.Labels[placementv1beta1.IsLatestSnapshotLabel] == strconv.FormatBool(true) {
// set the latest label to false first to make sure there is only one or none active policy snapshot
latestSnapshot.Labels[placementv1beta1.IsLatestSnapshotLabel] = strconv.FormatBool(false)
if err := r.Client.Update(ctx, latestSnapshot); err != nil {
klog.ErrorS(err, "Failed to set the isLatestSnapshot label to false", "ResourceOverride", croKObj, "overrideSnapshot", klog.KObj(latestSnapshot))
return controller.NewUpdateIgnoreConflictError(err)
}
klog.V(2).InfoS("Marked the latest overrideSnapshot as inactive", "ResourceOverride", croKObj, "overrideSnapshot", klog.KObj(latestSnapshot))
}
// we need to figure out the last snapshot index.
latestSnapshotIndex, err = labels.ExtractIndex(latestSnapshot, placementv1alpha1.OverrideIndexLabel)
if err != nil {
klog.ErrorS(err, "Failed to parse the override index label", "ResourceOverride", croKObj, "overrideSnapshot", klog.KObj(latestSnapshot))
return controller.NewUnexpectedBehaviorError(err)
}
}
// Need to create new snapshot when 1) there is no snapshots or 2) the latest snapshot hash != current one.
latestSnapshotIndex++
newSnapshot := &placementv1alpha1.ResourceOverrideSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf(placementv1alpha1.OverrideSnapshotNameFmt, ro.Name, latestSnapshotIndex),
Namespace: ro.Namespace,
Labels: map[string]string{
placementv1alpha1.OverrideTrackingLabel: ro.Name,
placementv1beta1.IsLatestSnapshotLabel: strconv.FormatBool(true),
placementv1alpha1.OverrideIndexLabel: strconv.Itoa(latestSnapshotIndex),
},
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(ro, placementv1alpha1.GroupVersion.WithKind(placementv1alpha1.ResourceOverrideKind)),
},
},
Spec: placementv1alpha1.ResourceOverrideSnapshotSpec{
OverrideSpec: overridePolicy,
OverrideHash: []byte(overrideSpecHash),
},
}
if err = r.Client.Create(ctx, newSnapshot); err != nil {
klog.ErrorS(err, "Failed to create new overrideSnapshot", "newOverrideSnapshot", klog.KObj(newSnapshot))
return controller.NewAPIServerError(false, err)
}
klog.V(2).InfoS("Created a new overrideSnapshot", "ResourceOverride", croKObj, "newOverrideSnapshot", klog.KObj(newSnapshot))
return nil
}