diff --git a/api/v1/composition.go b/api/v1/composition.go index e8803084..03f00141 100644 --- a/api/v1/composition.go +++ b/api/v1/composition.go @@ -56,10 +56,7 @@ type CompositionStatus struct { // Synthesis represents a Synthesizer's specific synthesis of a given Composition. type Synthesis struct { - // metadata.generation of the Composition at the time of synthesis. - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // metadata.generation of the Synthesizer at the time of synthesis. + ObservedCompositionGeneration int64 `json:"observedCompositionGeneration,omitempty"` ObservedSynthesizerGeneration int64 `json:"observedSynthesizerGeneration,omitempty"` // Number of resulting resource slices. Since they are immutable, this provides adequate timing signal to avoid stale informer caches. diff --git a/api/v1/config/crd/eno.azure.io_compositions.yaml b/api/v1/config/crd/eno.azure.io_compositions.yaml index 3cbea8d6..962b8991 100644 --- a/api/v1/config/crd/eno.azure.io_compositions.yaml +++ b/api/v1/config/crd/eno.azure.io_compositions.yaml @@ -76,14 +76,10 @@ spec: description: Synthesis represents a Synthesizer's specific synthesis of a given Composition. properties: - observedGeneration: - description: metadata.generation of the Composition at the time - of synthesis. + observedCompositionGeneration: format: int64 type: integer observedSynthesizerGeneration: - description: metadata.generation of the Synthesizer at the time - of synthesis. format: int64 type: integer podCreation: @@ -104,14 +100,10 @@ spec: description: Synthesis represents a Synthesizer's specific synthesis of a given Composition. properties: - observedGeneration: - description: metadata.generation of the Composition at the time - of synthesis. + observedCompositionGeneration: format: int64 type: integer observedSynthesizerGeneration: - description: metadata.generation of the Synthesizer at the time - of synthesis. format: int64 type: integer podCreation: diff --git a/internal/controllers/reconciliation/controller.go b/internal/controllers/reconciliation/controller.go index be35b50b..f8d5bc8c 100644 --- a/internal/controllers/reconciliation/controller.go +++ b/internal/controllers/reconciliation/controller.go @@ -71,7 +71,7 @@ func (c *Controller) Reconcile(ctx context.Context, req *reconstitution.Request) logger.V(1).Info("composition has not yet been synthesized") return ctrl.Result{}, nil } - currentGen := comp.Status.CurrentState.ObservedGeneration + currentGen := comp.Status.CurrentState.ObservedCompositionGeneration // Find the current and (optionally) previous desired states in the cache resource, found := c.resourceClient.Get(ctx, &req.ResourceRef, currentGen) @@ -82,7 +82,7 @@ func (c *Controller) Reconcile(ctx context.Context, req *reconstitution.Request) var prev *reconstitution.Resource if comp.Status.PreviousState != nil { - prev, _ = c.resourceClient.Get(ctx, &req.ResourceRef, comp.Status.PreviousState.ObservedGeneration) + prev, _ = c.resourceClient.Get(ctx, &req.ResourceRef, comp.Status.PreviousState.ObservedCompositionGeneration) } else { logger.V(1).Info("no previous state given") } diff --git a/internal/controllers/synthesis/integration_test.go b/internal/controllers/synthesis/integration_test.go index 9112e691..a447a159 100644 --- a/internal/controllers/synthesis/integration_test.go +++ b/internal/controllers/synthesis/integration_test.go @@ -78,14 +78,14 @@ func TestControllerHappyPath(t *testing.T) { latest := comp.Generation testutil.Eventually(t, func() bool { require.NoError(t, cli.Get(ctx, client.ObjectKeyFromObject(comp), comp)) - return comp.Status.CurrentState != nil && comp.Status.CurrentState.ObservedGeneration == latest + return comp.Status.CurrentState != nil && comp.Status.CurrentState.ObservedCompositionGeneration == latest }) // The previous state is retained if comp.Status.PreviousState == nil { t.Error("state wasn't swapped to previous") } else { - assert.Equal(t, comp.Generation-1, comp.Status.PreviousState.ObservedGeneration) + assert.Equal(t, comp.Generation-1, comp.Status.PreviousState.ObservedCompositionGeneration) } }) @@ -166,7 +166,7 @@ func TestControllerFastCompositionUpdates(t *testing.T) { latest := comp.Generation testutil.Eventually(t, func() bool { require.NoError(t, cli.Get(ctx, client.ObjectKeyFromObject(comp), comp)) - return comp.Status.CurrentState != nil && comp.Status.CurrentState.ObservedGeneration == latest + return comp.Status.CurrentState != nil && comp.Status.CurrentState.ObservedCompositionGeneration == latest }) } diff --git a/internal/controllers/synthesis/lifecycle.go b/internal/controllers/synthesis/lifecycle.go index 6f78d1d1..9d64a22a 100644 --- a/internal/controllers/synthesis/lifecycle.go +++ b/internal/controllers/synthesis/lifecycle.go @@ -83,7 +83,7 @@ func (c *podLifecycleController) Reconcile(ctx context.Context, req ctrl.Request } // Swap the state to prepare for resynthesis if needed - if comp.Status.CurrentState == nil || comp.Status.CurrentState.ObservedGeneration != comp.Generation { + if comp.Status.CurrentState == nil || comp.Status.CurrentState.ObservedCompositionGeneration != comp.Generation { swapStates(syn, comp) if err := c.client.Status().Update(ctx, comp); err != nil { return ctrl.Result{}, fmt.Errorf("swapping compisition state: %w", err) @@ -193,6 +193,6 @@ func swapStates(syn *apiv1.Synthesizer, comp *apiv1.Composition) { comp.Status.PreviousState = comp.Status.CurrentState } comp.Status.CurrentState = &apiv1.Synthesis{ - ObservedGeneration: comp.Generation, + ObservedCompositionGeneration: comp.Generation, } } diff --git a/internal/controllers/synthesis/status.go b/internal/controllers/synthesis/status.go index d36bb698..6d240246 100644 --- a/internal/controllers/synthesis/status.go +++ b/internal/controllers/synthesis/status.go @@ -96,6 +96,6 @@ func (c *statusController) Reconcile(ctx context.Context, req ctrl.Request) (ctr func statusIsOutOfSync(comp *apiv1.Composition, podCompGen, podSynGen int64) bool { // TODO: Unit tests, make sure to cover the pod creation latching logic - return (comp.Status.CurrentState != nil && comp.Status.CurrentState.ObservedGeneration == podCompGen) && + return (comp.Status.CurrentState != nil && comp.Status.CurrentState.ObservedCompositionGeneration == podCompGen) && (comp.Status.CurrentState.PodCreation == nil || comp.Status.CurrentState.ObservedSynthesizerGeneration != podSynGen) } diff --git a/internal/reconstitution/cache.go b/internal/reconstitution/cache.go index d311c7f9..c5a12e94 100644 --- a/internal/reconstitution/cache.go +++ b/internal/reconstitution/cache.go @@ -49,7 +49,7 @@ func (c *cache) Get(ctx context.Context, ref *ResourceRef, gen int64) (*Resource func (c *cache) HasSynthesis(ctx context.Context, comp types.NamespacedName, synthesis *apiv1.Synthesis) bool { key := synthesisKey{ Composition: comp, - Generation: synthesis.ObservedGeneration, + Generation: synthesis.ObservedCompositionGeneration, } c.mut.Lock() @@ -72,7 +72,7 @@ func (c *cache) Fill(ctx context.Context, comp types.NamespacedName, synthesis * c.mut.Lock() defer c.mut.Unlock() - synKey := synthesisKey{Composition: comp, Generation: synthesis.ObservedGeneration} + synKey := synthesisKey{Composition: comp, Generation: synthesis.ObservedCompositionGeneration} c.resources[synKey] = resources c.synthesesByComposition[comp] = append(c.synthesesByComposition[comp], synKey.Generation) @@ -162,7 +162,7 @@ func (c *cache) Purge(ctx context.Context, compNSN types.NamespacedName, comp *a remainingSyns := []int64{} for _, syn := range c.synthesesByComposition[compNSN] { - if comp != nil && ((comp.Status.CurrentState != nil && comp.Status.CurrentState.ObservedGeneration == syn) || (comp.Status.PreviousState != nil && comp.Status.PreviousState.ObservedGeneration == syn)) { + if comp != nil && ((comp.Status.CurrentState != nil && comp.Status.CurrentState.ObservedCompositionGeneration == syn) || (comp.Status.PreviousState != nil && comp.Status.PreviousState.ObservedCompositionGeneration == syn)) { remainingSyns = append(remainingSyns, syn) continue // still referenced by the Generation } diff --git a/internal/reconstitution/cache_test.go b/internal/reconstitution/cache_test.go index 4a500717..082bbd76 100644 --- a/internal/reconstitution/cache_test.go +++ b/internal/reconstitution/cache_test.go @@ -36,12 +36,12 @@ func TestCacheBasics(t *testing.T) { assert.True(t, c.HasSynthesis(ctx, comp, synth)) // negative - assert.False(t, c.HasSynthesis(ctx, comp, &apiv1.Synthesis{ObservedGeneration: 123})) + assert.False(t, c.HasSynthesis(ctx, comp, &apiv1.Synthesis{ObservedCompositionGeneration: 123})) }) t.Run("get", func(t *testing.T) { // positive - resource, exists := c.Get(ctx, &expectedReqs[0].ResourceRef, synth.ObservedGeneration) + resource, exists := c.Get(ctx, &expectedReqs[0].ResourceRef, synth.ObservedCompositionGeneration) require.True(t, exists) assert.NotEmpty(t, resource.Manifest) assert.Equal(t, "ConfigMap", resource.Object.GetKind()) @@ -56,7 +56,7 @@ func TestCacheBasics(t *testing.T) { c.Purge(ctx, comp, nil) // confirm - _, exists := c.Get(ctx, &expectedReqs[0].ResourceRef, synth.ObservedGeneration) + _, exists := c.Get(ctx, &expectedReqs[0].ResourceRef, synth.ObservedCompositionGeneration) assert.False(t, exists) assert.Len(t, c.resources, 0) @@ -103,7 +103,7 @@ func TestCacheSecret(t *testing.T) { assert.Equal(t, expectedReqs, reqs) // Confirm cache was filled correctly - resource, exists := c.Get(ctx, &expectedReqs[0].ResourceRef, synth.ObservedGeneration) + resource, exists := c.Get(ctx, &expectedReqs[0].ResourceRef, synth.ObservedCompositionGeneration) require.True(t, exists) assert.NotEmpty(t, resource.Manifest) assert.Equal(t, "ConfigMap", resource.Object.GetKind()) @@ -150,7 +150,7 @@ func TestCacheReconcileInterval(t *testing.T) { require.NoError(t, err) assert.Equal(t, expectedReqs, reqs) - resource, exists := c.Get(ctx, &expectedReqs[0].ResourceRef, synth.ObservedGeneration) + resource, exists := c.Get(ctx, &expectedReqs[0].ResourceRef, synth.ObservedCompositionGeneration) require.True(t, exists) assert.Equal(t, interval, resource.ReconcileInterval) } @@ -165,12 +165,12 @@ func TestCachePartialPurge(t *testing.T) { compNSN, synth, resources, _ := newCacheTestFixtures(3, 4) _, err := c.Fill(ctx, compNSN, synth, resources) require.NoError(t, err) - originalGen := synth.ObservedGeneration + originalGen := synth.ObservedCompositionGeneration // Add another resource to the composition but synthesized from a newer generation _, _, resources, expectedReqs := newCacheTestFixtures(1, 1) - synth.ObservedGeneration++ - resources[0].Spec.CompositionGeneration = synth.ObservedGeneration + synth.ObservedCompositionGeneration++ + resources[0].Spec.CompositionGeneration = synth.ObservedCompositionGeneration expectedReqs[0].Composition = compNSN _, err = c.Fill(ctx, compNSN, synth, resources) require.NoError(t, err) @@ -191,7 +191,7 @@ func TestCachePartialPurge(t *testing.T) { c.Purge(ctx, compNSN, comp) // The newer resource should still exist - _, exists := c.Get(ctx, &expectedReqs[0].ResourceRef, synth.ObservedGeneration) + _, exists := c.Get(ctx, &expectedReqs[0].ResourceRef, synth.ObservedCompositionGeneration) assert.True(t, exists) // The older resource is not referenced by the composition and should have been removed @@ -208,7 +208,7 @@ func TestCachePartialPurge(t *testing.T) { func newCacheTestFixtures(sliceCount, resPerSliceCount int) (types.NamespacedName, *apiv1.Synthesis, []apiv1.ResourceSlice, []*Request) { comp := types.NamespacedName{Namespace: string(uuid.NewUUID()), Name: string(uuid.NewUUID())} - synth := &apiv1.Synthesis{ObservedGeneration: 3} // just not 0 + synth := &apiv1.Synthesis{ObservedCompositionGeneration: 3} // just not 0 resources := make([]apiv1.ResourceSlice, sliceCount) requests := []*Request{} @@ -217,7 +217,7 @@ func newCacheTestFixtures(sliceCount, resPerSliceCount int) (types.NamespacedNam slice.Name = string(uuid.NewUUID()) slice.Namespace = "slice-ns" slice.Spec.Resources = make([]apiv1.Manifest, resPerSliceCount) - slice.Spec.CompositionGeneration = synth.ObservedGeneration + slice.Spec.CompositionGeneration = synth.ObservedCompositionGeneration for j := 0; j < resPerSliceCount; j++ { resource := &corev1.ConfigMap{} diff --git a/internal/reconstitution/reconstituter.go b/internal/reconstitution/reconstituter.go index fc32ae35..052ae110 100644 --- a/internal/reconstitution/reconstituter.go +++ b/internal/reconstitution/reconstituter.go @@ -84,7 +84,7 @@ func (r *reconstituter) populateCache(ctx context.Context, comp *apiv1.Compositi } compNSN := types.NamespacedName{Namespace: comp.Namespace, Name: comp.Name} - logger = logger.WithValues("synthesisGen", synthesis.ObservedGeneration) + logger = logger.WithValues("synthesisGen", synthesis.ObservedCompositionGeneration) ctx = logr.NewContext(ctx, logger) if r.cache.HasSynthesis(ctx, compNSN, synthesis) { logger.V(1).Info("this synthesis has already been cached") @@ -93,7 +93,7 @@ func (r *reconstituter) populateCache(ctx context.Context, comp *apiv1.Compositi slices := &apiv1.ResourceSliceList{} err := r.client.List(ctx, slices, client.InNamespace(comp.Namespace), client.MatchingFields{ - manager.IdxSlicesByCompositionGeneration: manager.NewSlicesByCompositionGenerationKey(comp.Name, synthesis.ObservedGeneration), + manager.IdxSlicesByCompositionGeneration: manager.NewSlicesByCompositionGenerationKey(comp.Name, synthesis.ObservedCompositionGeneration), }) if err != nil { return fmt.Errorf("listing resource slices: %w", err) diff --git a/internal/reconstitution/reconstituter_test.go b/internal/reconstitution/reconstituter_test.go index ce6efbf6..a9e3f071 100644 --- a/internal/reconstitution/reconstituter_test.go +++ b/internal/reconstitution/reconstituter_test.go @@ -32,8 +32,8 @@ func TestReconstituterIntegration(t *testing.T) { one := int64(1) comp.Status.CurrentState = &apiv1.Synthesis{ - ObservedGeneration: comp.Generation, - ResourceSliceCount: &one, + ObservedCompositionGeneration: comp.Generation, + ResourceSliceCount: &one, } require.NoError(t, client.Status().Update(ctx, comp))