in internal/resource/slicing.go [16:88]
func Slice(comp *apiv1.Composition, previous []*apiv1.ResourceSlice, outputs []*unstructured.Unstructured, maxJsonBytes int) ([]*apiv1.ResourceSlice, error) {
refs := map[resourceRef]struct{}{}
manifests := []apiv1.Manifest{}
for i, output := range outputs {
js, err := output.MarshalJSON()
if err != nil {
return nil, reconcile.TerminalError(fmt.Errorf("encoding output %d: %w", i, err))
}
manifests = append(manifests, apiv1.Manifest{
Manifest: string(js),
})
refs[newResourceRef(output)] = struct{}{}
}
// Build tombstones by diffing the new state against the current state
// Existing tombstones are passed down if they haven't yet been reconciled to avoid orphaning resources
for _, slice := range previous {
for i, res := range slice.Spec.Resources {
res := res
obj := &unstructured.Unstructured{}
err := obj.UnmarshalJSON([]byte(res.Manifest))
if err != nil {
return nil, reconcile.TerminalError(fmt.Errorf("decoding resource %d of slice %s: %w", i, slice.Name, err))
}
if obj.GetObjectKind().GroupVersionKind() == patchGVK {
// Patches can be removed without deleting the resource
continue
}
// We don't need a tombstone once the deleted resource has been reconciled
if _, ok := refs[newResourceRef(obj)]; ok || ((res.Deleted || slice.DeletionTimestamp != nil) && slice.Status.Resources != nil && slice.Status.Resources[i].Reconciled) {
continue // still exists or has already been deleted
}
res.Deleted = true
manifests = append(manifests, res)
}
}
// Build the slice resources
var (
slices []*apiv1.ResourceSlice
sliceBytes int
slice *apiv1.ResourceSlice
blockOwnerDeletion = true
)
for _, manifest := range manifests {
if slice == nil || sliceBytes >= maxJsonBytes {
sliceBytes = 0
slice = &apiv1.ResourceSlice{}
slice.GenerateName = comp.Name + "-"
slice.Namespace = comp.Namespace
slice.Finalizers = []string{"eno.azure.io/cleanup"}
slice.OwnerReferences = []metav1.OwnerReference{{
APIVersion: apiv1.SchemeGroupVersion.Identifier(),
Kind: "Composition",
Name: comp.Name,
UID: comp.UID,
BlockOwnerDeletion: &blockOwnerDeletion, // we need the composition in order to successfully delete its resource slices
Controller: &blockOwnerDeletion,
}}
if comp.Status.CurrentSynthesis != nil {
slice.Spec.SynthesisUUID = comp.Status.CurrentSynthesis.UUID
}
slices = append(slices, slice)
}
sliceBytes += len(manifest.Manifest)
slice.Spec.Resources = append(slice.Spec.Resources, manifest)
}
return slices, nil
}