107 lines
3.4 KiB
Go
107 lines
3.4 KiB
Go
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"gitea.maximumdirect.net/eric/distributor/internal/config"
|
|
"gitea.maximumdirect.net/eric/distributor/internal/state"
|
|
)
|
|
|
|
type PrunePlanOptions struct {
|
|
PipelineID string
|
|
DestinationID string
|
|
Now time.Time
|
|
}
|
|
|
|
type PrunePlanReport struct {
|
|
PipelineID string `json:"pipeline_id"`
|
|
DestinationID string `json:"destination_id"`
|
|
OwnerScope PruneOwnerScope `json:"owner_scope"`
|
|
Enabled bool `json:"enabled"`
|
|
CheckedCount int `json:"checked_count"`
|
|
PrunedOutputs []PruneOutputRecord `json:"pruned_outputs"`
|
|
PreservedOutputs []PruneOutputRecord `json:"preserved_outputs"`
|
|
}
|
|
|
|
type PruneOwnerScope struct {
|
|
PipelineID string `json:"pipeline_id"`
|
|
DestinationID string `json:"destination_id"`
|
|
}
|
|
|
|
type PruneOutputRecord struct {
|
|
Path string `json:"path"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
Owner *PruneOwnerScope `json:"owner,omitempty"`
|
|
}
|
|
|
|
func PlanPrune(document state.StateDocument, policy config.PrunePolicy, options PrunePlanOptions) (PrunePlanReport, error) {
|
|
scope := state.CurrentOwnerScope(options.PipelineID, options.DestinationID)
|
|
report := PrunePlanReport{
|
|
PipelineID: options.PipelineID,
|
|
DestinationID: options.DestinationID,
|
|
OwnerScope: PruneOwnerScope{PipelineID: scope.PipelineID, DestinationID: scope.DestinationID},
|
|
Enabled: policy.Enabled,
|
|
PrunedOutputs: []PruneOutputRecord{},
|
|
PreservedOutputs: []PruneOutputRecord{},
|
|
}
|
|
if !policy.Enabled {
|
|
return report, nil
|
|
}
|
|
|
|
candidates, err := pruneCandidatesForDocument(document, scope)
|
|
if err != nil {
|
|
return PrunePlanReport{}, err
|
|
}
|
|
report.CheckedCount = len(candidates)
|
|
plan := state.PlanPrune(candidates, state.PrunePlanOptions{
|
|
Now: options.Now,
|
|
OlderThan: pruneOlderThan(policy),
|
|
KeepLatest: policy.KeepLatest,
|
|
})
|
|
report.PrunedOutputs = pruneOutputRecords(plan.Pruned)
|
|
report.PreservedOutputs = pruneOutputRecords(plan.Preserved)
|
|
return report, nil
|
|
}
|
|
|
|
func pruneCandidatesForDocument(document state.StateDocument, scope state.OwnerScope) ([]state.PruneCandidate, error) {
|
|
if document.SingleOwner != nil {
|
|
singleOwner := *document.SingleOwner
|
|
if singleOwner.PipelineID != scope.PipelineID || singleOwner.DestinationID != scope.DestinationID {
|
|
return nil, fmt.Errorf("state owner is %s/%s, not %s/%s", singleOwner.PipelineID, singleOwner.DestinationID, scope.PipelineID, scope.DestinationID)
|
|
}
|
|
return state.SingleOwnerPruneCandidates(singleOwner), nil
|
|
}
|
|
if document.SharedRoot != nil {
|
|
return state.SharedRootPruneCandidates(*document.SharedRoot, scope), nil
|
|
}
|
|
return nil, fmt.Errorf("destination state document is empty")
|
|
}
|
|
|
|
func pruneOlderThan(policy config.PrunePolicy) *time.Duration {
|
|
if policy.OlderThan == nil {
|
|
return nil
|
|
}
|
|
duration := policy.OlderThan.AsDuration()
|
|
return &duration
|
|
}
|
|
|
|
func pruneOutputRecords(candidates []state.PruneCandidate) []PruneOutputRecord {
|
|
records := make([]PruneOutputRecord, 0, len(candidates))
|
|
for _, candidate := range candidates {
|
|
var owner *PruneOwnerScope
|
|
if candidate.Owner != nil {
|
|
owner = &PruneOwnerScope{
|
|
PipelineID: candidate.Owner.PipelineID,
|
|
DestinationID: candidate.Owner.DestinationID,
|
|
}
|
|
}
|
|
records = append(records, PruneOutputRecord{
|
|
Path: candidate.Path,
|
|
UpdatedAt: candidate.UpdatedAt.UTC().Format(time.RFC3339),
|
|
Owner: owner,
|
|
})
|
|
}
|
|
return records
|
|
}
|