func Slice()

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
}