Add destination state comparison
This commit is contained in:
89
internal/state/compare.go
Normal file
89
internal/state/compare.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitea.maximumdirect.net/eric/distributor/internal/bundle"
|
||||
)
|
||||
|
||||
type Outcome string
|
||||
|
||||
const (
|
||||
OutcomeDestinationAbsent Outcome = "destination_absent"
|
||||
OutcomeDestinationUnmanaged Outcome = "destination_unmanaged"
|
||||
OutcomeInvalidState Outcome = "invalid_destination_state"
|
||||
OutcomeIdentityMismatch Outcome = "destination_identity_mismatch"
|
||||
OutcomeSameSource Outcome = "same_source_manifest"
|
||||
OutcomeDestinationOlder Outcome = "destination_older"
|
||||
OutcomeDestinationNewer Outcome = "destination_newer"
|
||||
OutcomeSameCreatedConflict Outcome = "same_created_digest_conflict"
|
||||
OutcomeDifferentSourceConflict Outcome = "different_source_conflict"
|
||||
)
|
||||
|
||||
type DestinationStatus struct {
|
||||
State *DistributorState
|
||||
StateErr error
|
||||
HasContents bool
|
||||
}
|
||||
|
||||
type Comparison struct {
|
||||
Outcome Outcome
|
||||
Reason string
|
||||
}
|
||||
|
||||
func Compare(source bundle.Manifest, pipelineID, destinationID string, status DestinationStatus) Comparison {
|
||||
if status.StateErr != nil {
|
||||
return Comparison{Outcome: OutcomeInvalidState, Reason: status.StateErr.Error()}
|
||||
}
|
||||
if status.State == nil {
|
||||
if status.HasContents {
|
||||
return Comparison{Outcome: OutcomeDestinationUnmanaged, Reason: "destination has content but no distributor state"}
|
||||
}
|
||||
return Comparison{Outcome: OutcomeDestinationAbsent, Reason: "destination state is absent"}
|
||||
}
|
||||
|
||||
destinationState := *status.State
|
||||
if err := Validate(destinationState); err != nil {
|
||||
return Comparison{Outcome: OutcomeInvalidState, Reason: err.Error()}
|
||||
}
|
||||
if destinationState.PipelineID != pipelineID {
|
||||
return Comparison{Outcome: OutcomeIdentityMismatch, Reason: fmt.Sprintf("pipeline id %q does not match %q", destinationState.PipelineID, pipelineID)}
|
||||
}
|
||||
if destinationState.DestinationID != destinationID {
|
||||
return Comparison{Outcome: OutcomeIdentityMismatch, Reason: fmt.Sprintf("destination id %q does not match %q", destinationState.DestinationID, destinationID)}
|
||||
}
|
||||
|
||||
destinationManifest := destinationState.Source.Manifest
|
||||
if manifestsEqual(source, destinationManifest) {
|
||||
return Comparison{Outcome: OutcomeSameSource, Reason: "destination source manifest matches source"}
|
||||
}
|
||||
if destinationManifest.ID != source.ID {
|
||||
return Comparison{Outcome: OutcomeDifferentSourceConflict, Reason: "destination source id differs from source"}
|
||||
}
|
||||
if destinationManifest.Created.Before(source.Created) {
|
||||
return Comparison{Outcome: OutcomeDestinationOlder, Reason: "destination source is older than source"}
|
||||
}
|
||||
if destinationManifest.Created.After(source.Created) {
|
||||
return Comparison{Outcome: OutcomeDestinationNewer, Reason: "destination source is newer than source"}
|
||||
}
|
||||
if destinationManifest.Digest != source.Digest {
|
||||
return Comparison{Outcome: OutcomeSameCreatedConflict, Reason: "destination source has same id and created time but different digest"}
|
||||
}
|
||||
return Comparison{Outcome: OutcomeInvalidState, Reason: "destination source differs from source without a supported comparison outcome"}
|
||||
}
|
||||
|
||||
func manifestsEqual(a, b bundle.Manifest) bool {
|
||||
if a.SchemaVersion != b.SchemaVersion ||
|
||||
a.ID != b.ID ||
|
||||
a.Digest != b.Digest ||
|
||||
!a.Created.Equal(b.Created) ||
|
||||
len(a.Files) != len(b.Files) {
|
||||
return false
|
||||
}
|
||||
for index := range a.Files {
|
||||
if a.Files[index] != b.Files[index] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user