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  }