Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions internal/controllers/composition/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ const (
AKSComponentLabel = "aks.azure.com/component-type" // TODO(ruinanliu): Temp workaround remove after 14802391 is released
addOnLabelValue = "addon" // TODO(ruinanliu): Temp workaround remove after 14802391 is released
EnoCleanupFinalizer = "eno.azure.io/cleanup"
MissingInputStatus = "MissingInputs"
MismatchedInputsStatus = "MismatchedInputs"
)

type compositionController struct {
Expand Down Expand Up @@ -262,6 +264,15 @@ func (c *compositionController) reconcileSimplifiedStatus(ctx context.Context, s
return false, nil
}

if synth != nil {
switch next.Status {
case MissingInputStatus:
logger.Info("composition is missing required inputs", "missingInputs", inputs.Missing(synth, comp), "expectedInputs", inputs.Expected(synth))
case MismatchedInputsStatus:
logger.Info("composition has inputs that are out of lockstep", "mismatchedInputs", inputs.Mismatched(synth, comp, comp.Status.InputRevisions), "synthesizerGeneration", synth.Generation, "compositionGeneration", comp.Generation)
Comment thread
ruinan-liu marked this conversation as resolved.
}
}

logger.Info("composition status changed", "previousStatus", comp.Status.Simplified, "currentStatus", next)
copy := comp.DeepCopy()
copy.Status.Simplified = next
Expand Down Expand Up @@ -383,11 +394,11 @@ func buildSimplifiedStatus(synth *apiv1.Synthesizer, comp *apiv1.Composition) *a
}

if !inputs.Exist(synth, comp) {
status.Status = "MissingInputs"
status.Status = MissingInputStatus
return status
}
if inputs.OutOfLockstep(synth, comp, comp.Status.InputRevisions) {
status.Status = "MismatchedInputs"
status.Status = MismatchedInputsStatus
}

if comp.Status.CurrentSynthesis == nil && comp.Status.InFlightSynthesis == nil {
Expand Down
92 changes: 70 additions & 22 deletions internal/inputs/inputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import (
// Exist returns true when all of the inputs required by a synthesizer are represented by the given composition's status.
// Optional refs are not required to exist and will not cause this function to return false.
func Exist(syn *apiv1.Synthesizer, c *apiv1.Composition) bool {
return len(Missing(syn, c)) == 0
}

// Missing returns the keys of any non-optional inputs required by the synthesizer that
// are not represented in the given composition's status.
func Missing(syn *apiv1.Synthesizer, c *apiv1.Composition) []string {
var missing []string
for _, ref := range syn.Spec.Refs {
// Skip optional refs - they are not required to exist
if ref.Optional {
Expand All @@ -19,44 +26,85 @@ func Exist(syn *apiv1.Synthesizer, c *apiv1.Composition) bool {
return ref.Key == current.Key
})
if !found {
return false
missing = append(missing, ref.Key)
}
}
return missing
}

// Expected returns the keys of all non-optional inputs declared by the synthesizer.
func Expected(syn *apiv1.Synthesizer) []string {
var expected []string
for _, ref := range syn.Spec.Refs {
if ref.Optional {
continue
}
expected = append(expected, ref.Key)
}
return true
return expected
}

// OutOfLockstep returns true when one or more inputs that specify a revision do not match the others.
// It also returns true if any revision is derived from a synthesizer/composition generation older than the ones provided.
func OutOfLockstep(synth *apiv1.Synthesizer, comp *apiv1.Composition, revs []apiv1.InputRevisions) bool {
// First, the the max revision across all bindings
var maxRevision *int
return len(Mismatched(synth, comp, revs)) > 0
}

// MismatchedInput describes a single input revision that is out of lockstep,
// either with peer revisions or with the current synthesizer/composition
// generation. Intended for logging only. Numeric fields are 0 when unknown.
type MismatchedInput struct {
Key string
Revision int // 0 if unset
MaxRevision int // 0 if no peer revision was observed
SynthesizerGeneration int64 // 0 if unset
CompositionGeneration int64 // 0 if unset
}
Comment thread
ruinan-liu marked this conversation as resolved.

// Mismatched returns the set of input revisions that are out of lockstep with the others, or
// derived from a synthesizer/composition generation older than the current ones.
func Mismatched(synth *apiv1.Synthesizer, comp *apiv1.Composition, revs []apiv1.InputRevisions) []MismatchedInput {
var mismatched []MismatchedInput

// First, find the max revision across all bindings
maxRevision := 0
maxSet := false
for _, rev := range revs {
if rev.Revision == nil {
continue
}
if !maxSet || *rev.Revision > maxRevision {
maxRevision = *rev.Revision
maxSet = true
}
}

for _, rev := range revs {
stale := false
if rev.SynthesizerGeneration != nil && *rev.SynthesizerGeneration < synth.Generation {
return true
stale = true
}
if rev.CompositionGeneration != nil && *rev.CompositionGeneration < comp.Generation {
return true
stale = true
}
if rev.Revision == nil {
revMismatch := maxSet && rev.Revision != nil && *rev.Revision != maxRevision
if !stale && !revMismatch {
continue
}
if maxRevision == nil {
maxRevision = rev.Revision
continue
entry := MismatchedInput{Key: rev.Key}
if maxSet {
entry.MaxRevision = maxRevision
}
if *rev.Revision > *maxRevision {
maxRevision = rev.Revision
if rev.Revision != nil {
entry.Revision = *rev.Revision
}
}
if maxRevision == nil {
return false // no inputs declare a revision, so we should assume they're in sync
}

// Now given the max, make sure all inputs with a revision match it
for _, rev := range revs {
if rev.Revision != nil && *maxRevision != *rev.Revision {
return true
if rev.SynthesizerGeneration != nil {
entry.SynthesizerGeneration = *rev.SynthesizerGeneration
}
if rev.CompositionGeneration != nil {
entry.CompositionGeneration = *rev.CompositionGeneration
}
mismatched = append(mismatched, entry)
}
return false
return mismatched
}
Loading
Loading