github.com/thanos-io/thanos@v0.32.5/pkg/verifier/verify.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package verifier 5 6 import ( 7 "context" 8 "strings" 9 "time" 10 11 "github.com/thanos-io/thanos/pkg/block" 12 13 "github.com/go-kit/log" 14 "github.com/go-kit/log/level" 15 "github.com/oklog/ulid" 16 "github.com/pkg/errors" 17 "github.com/prometheus/client_golang/prometheus" 18 "github.com/prometheus/client_golang/prometheus/promauto" 19 20 "github.com/thanos-io/objstore" 21 ) 22 23 type Verifier interface { 24 IssueID() string 25 Verify(ctx Context, idMatcher func(ulid.ULID) bool) error 26 } 27 28 type VerifierRepairer interface { 29 IssueID() string 30 VerifyRepair(ctx Context, idMatcher func(ulid.ULID) bool, repair bool) error 31 } 32 33 // Context is an verifier config. 34 type Context struct { 35 context.Context 36 37 Logger log.Logger 38 Bkt objstore.Bucket 39 BackupBkt objstore.Bucket 40 Fetcher block.MetadataFetcher 41 DeleteDelay time.Duration 42 43 metrics *metrics 44 } 45 46 type metrics struct { 47 blocksMarkedForDeletion prometheus.Counter 48 } 49 50 func newVerifierMetrics(reg prometheus.Registerer) *metrics { 51 var m metrics 52 m.blocksMarkedForDeletion = promauto.With(reg).NewCounter(prometheus.CounterOpts{ 53 Name: "thanos_verify_blocks_marked_for_deletion_total", 54 Help: "Total number of blocks marked for deletion by verify.", 55 }) 56 return &m 57 } 58 59 // Manager runs given issues to verify if bucket is healthy. 60 type Manager struct { 61 Context 62 63 vs Registry 64 } 65 66 type Registry struct { 67 Verifiers []Verifier 68 VerifierRepairers []VerifierRepairer 69 } 70 71 func (r Registry) VerifiersIDs() []string { 72 ks := make([]string, 0, len(r.Verifiers)) 73 for _, v := range r.Verifiers { 74 ks = append(ks, v.IssueID()) 75 } 76 return ks 77 } 78 79 func (r Registry) VerifierRepairersIDs() []string { 80 ks := make([]string, 0, len(r.VerifierRepairers)) 81 for _, vr := range r.VerifierRepairers { 82 ks = append(ks, vr.IssueID()) 83 } 84 return ks 85 } 86 87 func (r Registry) SubstractByIDs(ids []string, repair bool) (Registry, error) { 88 n := Registry{} 89 idLoop: 90 for _, id := range ids { 91 if !repair { 92 for _, v := range r.Verifiers { 93 if v.IssueID() != id { 94 continue 95 } 96 n.Verifiers = append(n.Verifiers, v) 97 continue idLoop 98 99 } 100 } 101 102 for _, vr := range r.VerifierRepairers { 103 if vr.IssueID() != id { 104 continue 105 } 106 n.VerifierRepairers = append(n.VerifierRepairers, vr) 107 continue idLoop 108 } 109 return n, errors.Errorf("no such issue ID %s", id) 110 } 111 return n, nil 112 } 113 114 // New returns verifier's manager. 115 func NewManager(reg prometheus.Registerer, logger log.Logger, bkt, backupBkt objstore.Bucket, fetcher block.MetadataFetcher, deleteDelay time.Duration, vs Registry) *Manager { 116 return &Manager{ 117 Context: Context{ 118 Logger: logger, 119 Bkt: bkt, 120 BackupBkt: backupBkt, 121 Fetcher: fetcher, 122 DeleteDelay: deleteDelay, 123 124 metrics: newVerifierMetrics(reg), 125 }, 126 vs: vs, 127 } 128 } 129 130 // Verify verifies matching blocks using registered list of Verifier and VerifierRepairer. 131 // TODO(blotka): Wrap bucket with WrapWithMetrics and print metrics after each issue (e.g how many blocks where touched). 132 func (m *Manager) Verify(ctx context.Context, idMatcher func(ulid.ULID) bool) error { 133 if len(m.vs.Verifiers)+len(m.vs.VerifierRepairers) == 0 { 134 return errors.New("nothing to verify. No verifiers and verifierRepairers registered") 135 } 136 137 logger := log.With(m.Logger, "verifiers", strings.Join(append(m.vs.VerifiersIDs(), m.vs.VerifierRepairersIDs()...), ",")) 138 level.Info(logger).Log("msg", "Starting verify task") 139 140 for _, v := range m.vs.Verifiers { 141 vCtx := m.Context 142 vCtx.Logger = log.With(logger, "verifier", v.IssueID()) 143 vCtx.Context = ctx 144 if err := v.Verify(vCtx, idMatcher); err != nil { 145 return errors.Wrapf(err, "verify %s", v.IssueID()) 146 } 147 } 148 for _, vr := range m.vs.VerifierRepairers { 149 vCtx := m.Context 150 vCtx.Context = ctx 151 vCtx.Logger = log.With(logger, "verifier", vr.IssueID()) 152 if err := vr.VerifyRepair(vCtx, idMatcher, false); err != nil { 153 return errors.Wrapf(err, "verify %s", vr.IssueID()) 154 } 155 } 156 157 level.Info(logger).Log("msg", "verify task completed") 158 return nil 159 } 160 161 // VerifyAndRepair verifies and repairs matching blocks using registered list of VerifierRepairer. 162 // TODO(blotka): Wrap bucket with WrapWithMetrics and print metrics after each issue (e.g how many blocks where touched). 163 func (m *Manager) VerifyAndRepair(ctx context.Context, idMatcher func(ulid.ULID) bool) error { 164 if len(m.vs.Verifiers)+len(m.vs.VerifierRepairers) == 0 { 165 return errors.New("nothing to verify. No verifierRepairers registered") 166 } 167 168 logger := log.With(m.Logger, "verifiers", strings.Join(m.vs.VerifierRepairersIDs(), ",")) 169 level.Warn(logger).Log("msg", "GLOBAL COMPACTOR SHOULD __NOT__ BE RUNNING ON THE SAME BUCKET") 170 level.Info(logger).Log("msg", "Starting verify and repair task") 171 172 for _, vr := range m.vs.VerifierRepairers { 173 vCtx := m.Context 174 vCtx.Logger = log.With(logger, "verifier", vr.IssueID()) 175 vCtx.Context = ctx 176 if err := vr.VerifyRepair(vCtx, idMatcher, true); err != nil { 177 return errors.Wrapf(err, "verify and repair %s", vr.IssueID()) 178 } 179 } 180 181 level.Info(logger).Log("msg", "verify and repair task completed") 182 return nil 183 }