diff --git a/debian/matcher_integration_test.go b/debian/matcher_integration_test.go index 3a6fc7cb9..746996f04 100644 --- a/debian/matcher_integration_test.go +++ b/debian/matcher_integration_test.go @@ -6,15 +6,14 @@ import ( "os" "path/filepath" "testing" - "time" "github.com/quay/zlog" "github.com/quay/claircore" "github.com/quay/claircore/internal/matcher" - "github.com/quay/claircore/internal/updater" vulnstore "github.com/quay/claircore/internal/vulnstore/postgres" "github.com/quay/claircore/libvuln/driver" + "github.com/quay/claircore/libvuln/updates" "github.com/quay/claircore/test/integration" ) @@ -29,19 +28,15 @@ func TestMatcherIntegration(t *testing.T) { store := vulnstore.NewVulnStore(pool) m := &Matcher{} - // seed the test vulnstore with CVE data - ch := make(chan driver.Updater) - go func() { - ch <- NewUpdater(Buster) - close(ch) - }() - exec := updater.Online{Pool: pool} + + mgr, err := updates.NewManager(ctx, store, pool, nil, updates.WithEnabled( + []string{"debian"})) + // force update - tctx, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - if err := exec.Run(tctx, ch); err != nil { - t.Error(err) + if err := mgr.Run(ctx); err != nil { + t.Fatal(err) } + path := filepath.Join("testdata", "indexreport-buster-jackson-databind.json") f, err := os.Open(path) if err != nil { diff --git a/internal/updater/controller.go b/internal/updater/controller.go index 38709418d..60bc9d544 100644 --- a/internal/updater/controller.go +++ b/internal/updater/controller.go @@ -67,7 +67,7 @@ func driveUpdater(ctx context.Context, u driver.Updater, s vulnstore.Updater) er var prevFP driver.Fingerprint // Get previous fingerprint, if present. // A fingerprint being missing is not an error. - opmap, err := s.GetUpdateOperations(ctx, name) + opmap, err := s.GetUpdateOperations(ctx, driver.VulnerabilityKind, name) if err != nil { return err } diff --git a/internal/vulnstore/postgres/gc_test.go b/internal/vulnstore/postgres/gc_test.go index 71a6975f3..8bb75b604 100644 --- a/internal/vulnstore/postgres/gc_test.go +++ b/internal/vulnstore/postgres/gc_test.go @@ -118,7 +118,7 @@ func TestGC(t *testing.T) { } // confirm update operations exist - ops, err := store.GetUpdateOperations(ctx) + ops, err := store.GetUpdateOperations(ctx, driver.VulnerabilityKind) if err != nil { t.Fatalf("failed obtaining update ops: %v", err) } @@ -139,7 +139,7 @@ func TestGC(t *testing.T) { if tt.updateOps < tt.keep { wantKeep = tt.updateOps } - ops, err = store.GetUpdateOperations(ctx) + ops, err = store.GetUpdateOperations(ctx, driver.VulnerabilityKind) if err != nil { t.Fatalf("failed obtaining update ops: %v", err) } diff --git a/internal/vulnstore/postgres/getupdateoperationdiff.go b/internal/vulnstore/postgres/getupdateoperationdiff.go index 76be1a669..dbb9f2c0c 100644 --- a/internal/vulnstore/postgres/getupdateoperationdiff.go +++ b/internal/vulnstore/postgres/getupdateoperationdiff.go @@ -55,7 +55,14 @@ var ( ) ) -func getUpdateDiff(ctx context.Context, pool *pgxpool.Pool, prev, cur uuid.UUID) (*driver.UpdateDiff, error) { +func (s *Store) GetUpdateDiff(ctx context.Context, prev, cur uuid.UUID) (*driver.UpdateDiff, error) { + // confirmRefs will return a row only if both refs are kind = 'vulnerability' + // therefore, if a pgx.ErrNoRows is returned from this query, at least one + // of the incoming refs is not of kind = 'vulnerability'. + const confirmRefs = ` +SELECT 1 +WHERE ROW ('vulnerability') = ALL (SELECT kind FROM update_operation WHERE ref = $1 OR ref = $2); +` // Query takes two update IDs and returns rows that only exist in first // argument's set of vulnerabilities. const query = `WITH @@ -101,15 +108,28 @@ func getUpdateDiff(ctx context.Context, pool *pgxpool.Pool, prev, cur uuid.UUID) if cur == uuid.Nil { return nil, errors.New("nil uuid is invalid as \"current\" endpoint") } + + // confirm both refs are of type == 'vulnerability' + start := time.Now() + // Retrieve added first. + rows, err := s.pool.Query(ctx, confirmRefs, cur, prev) + switch err { + case nil: + rows.Close() + case pgx.ErrNoRows: + return nil, fmt.Errorf("provided ref was not of kind 'vulnerability'") + default: + return nil, fmt.Errorf("failed to confirm update op ref types: %w", err) + } + getUpdateDiffCounter.WithLabelValues("confirmrefs").Add(1) + getUpdateDiffDuration.WithLabelValues("confirmrefs").Observe(time.Since(start).Seconds()) + var diff driver.UpdateDiff - if err := populateRefs(ctx, &diff, pool, prev, cur); err != nil { + if err := populateRefs(ctx, &diff, s.pool, prev, cur); err != nil { return nil, err } - // Retrieve added first. - start := time.Now() - - rows, err := pool.Query(ctx, query, cur, prev) + rows, err = s.pool.Query(ctx, query, cur, prev) if err != nil { return nil, fmt.Errorf("failed to retrieve added vulnerabilities: %w", err) } @@ -140,7 +160,7 @@ func getUpdateDiff(ctx context.Context, pool *pgxpool.Pool, prev, cur uuid.UUID) if prev == uuid.Nil { return &diff, nil } - rows, err = pool.Query(ctx, query, prev, cur) + rows, err = s.pool.Query(ctx, query, prev, cur) if err != nil { return nil, fmt.Errorf("failed to retrieve removed vulnerabilities: %w", err) } diff --git a/internal/vulnstore/postgres/getupdateoperations.go b/internal/vulnstore/postgres/getupdateoperations.go index 3dd7dadcd..8597c8c38 100644 --- a/internal/vulnstore/postgres/getupdateoperations.go +++ b/internal/vulnstore/postgres/getupdateoperations.go @@ -76,21 +76,95 @@ var ( ) // GetLatestUpdateRef implements driver.Updater. -func (s *Store) GetLatestUpdateRef(ctx context.Context) (uuid.UUID, error) { - const query = `SELECT ref FROM update_operation ORDER BY id USING > LIMIT 1;` +func (s *Store) GetLatestUpdateRef(ctx context.Context, kind driver.UpdateKind) (uuid.UUID, error) { + const ( + query = `SELECT ref FROM update_operation ORDER BY id USING > LIMIT 1;` + queryEnrichment = `SELECT ref FROM update_operation WHERE kind = 'enrichment' ORDER BY id USING > LIMIT 1;` + queryVulnerability = `SELECT ref FROM update_operation WHERE kind = 'vulnerability' ORDER BY id USING > LIMIT 1;` + ) ctx = baggage.ContextWithValues(ctx, label.String("component", "internal/vulnstore/postgres/getLatestRef")) + var q string + var label string + switch kind { + case "": + q = query + label = "query" + case driver.EnrichmentKind: + q = queryEnrichment + label = "query_enrichment" + case driver.VulnerabilityKind: + q = queryVulnerability + label = "query_vulnerability" + } + var ref uuid.UUID start := time.Now() - if err := s.pool.QueryRow(ctx, query).Scan(&ref); err != nil { + if err := s.pool.QueryRow(ctx, q).Scan(&ref); err != nil { return uuid.Nil, err } - getLatestUpdateRefCounter.WithLabelValues("query").Add(1) - getLatestUpdateRefDuration.WithLabelValues("query").Observe(time.Since(start).Seconds()) + getLatestUpdateRefCounter.WithLabelValues(label).Add(1) + getLatestUpdateRefDuration.WithLabelValues(label).Observe(time.Since(start).Seconds()) return ref, nil } +func (s *Store) GetLatestUpdateRefs(ctx context.Context, kind driver.UpdateKind) (map[string][]driver.UpdateOperation, error) { + const ( + query = `SELECT DISTINCT ON (updater) updater, ref, fingerprint, date FROM update_operation ORDER BY updater, id USING >;` + queryEnrichment = `SELECT DISTINCT ON (updater) updater, ref, fingerprint, date FROM update_operation WHERE kind = 'enrichment' ORDER BY updater, id USING >;` + queryVulnerability = `SELECT DISTINCT ON (updater) updater, ref, fingerprint, date FROM update_operation WHERE kind = 'enrichment' ORDER BY updater, id USING >;` + ) + + var q string + var label string + switch kind { + case "": + q = query + label = "query" + case driver.EnrichmentKind: + q = queryEnrichment + label = "query_enrichment" + case driver.VulnerabilityKind: + q = queryVulnerability + label = "query_vulnerability" + } + + start := time.Now() + + rows, err := s.pool.Query(ctx, q) + if err != nil { + return nil, err + } + + getLatestRefsCounter.WithLabelValues(label).Add(1) + getLatestRefsDuration.WithLabelValues(label).Observe(time.Since(start).Seconds()) + + defer rows.Close() + + ret := make(map[string][]driver.UpdateOperation) + for rows.Next() { + ops := []driver.UpdateOperation{} + ops = append(ops, driver.UpdateOperation{}) + uo := &ops[len(ops)-1] + err := rows.Scan( + &uo.Updater, + &uo.Ref, + &uo.Fingerprint, + &uo.Date, + ) + if err != nil { + rows.Close() + return nil, fmt.Errorf("failed to scan update operation for updater %q: %w", uo.Updater, err) + } + ret[uo.Updater] = ops + } + zlog.Debug(ctx). + Int("count", len(ret)). + Msg("found updaters") + return ret, nil +} + func getLatestRefs(ctx context.Context, pool *pgxpool.Pool) (map[string][]driver.UpdateOperation, error) { const query = `SELECT DISTINCT ON (updater) updater, ref, fingerprint, date FROM update_operation ORDER BY updater, id USING >;` ctx = baggage.ContextWithValues(ctx, @@ -131,15 +205,17 @@ func getLatestRefs(ctx context.Context, pool *pgxpool.Pool) (map[string][]driver return ret, nil } -func getUpdateOperations(ctx context.Context, pool *pgxpool.Pool, updater ...string) (map[string][]driver.UpdateOperation, error) { +func (s *Store) GetUpdateOperations(ctx context.Context, kind driver.UpdateKind, updater ...string) (map[string][]driver.UpdateOperation, error) { const ( - query = `SELECT ref, updater, fingerprint, date FROM update_operation WHERE updater = $1 ORDER BY id DESC;` - getUpdaters = `SELECT DISTINCT(updater) FROM update_operation;` + query = `SELECT ref, updater, fingerprint, date FROM update_operation WHERE updater = ANY($1) ORDER BY id DESC;` + queryVulnerability = `SELECT ref, updater, fingerprint, date FROM update_operation WHERE updater = ANY($1) AND kind = 'vulnerability' ORDER BY id DESC;` + queryEnrichment = `SELECT ref, updater, fingerprint, date FROM update_operation WHERE updater = ANY($1) AND kind = 'enrichment' ORDER BY id DESC;` + getUpdaters = `SELECT DISTINCT(updater) FROM update_operation;` ) ctx = baggage.ContextWithValues(ctx, label.String("component", "internal/vulnstore/postgres/getUpdateOperations")) - tx, err := pool.Begin(ctx) + tx, err := s.pool.Begin(ctx) if err != nil { return nil, fmt.Errorf("failed to begin transaction: %w", err) } @@ -156,7 +232,7 @@ func getUpdateOperations(ctx context.Context, pool *pgxpool.Pool, updater ...str switch { case err == nil: case errors.Is(err, pgx.ErrNoRows): - return nil, nil + return out, nil default: return nil, fmt.Errorf("failed to get distinct updates: %w", err) } @@ -180,50 +256,45 @@ func getUpdateOperations(ctx context.Context, pool *pgxpool.Pool, updater ...str rows.Close() } - // Take care to close the rows object on every iteration. - var rows pgx.Rows - for _, u := range updater { + var q string + var label string + switch kind { + case "": + q = query + label = "query" + case driver.EnrichmentKind: + q = queryEnrichment + label = "query_enrichment" + case driver.VulnerabilityKind: + q = queryVulnerability + label = "query_vulnerability" + } - start := time.Now() + start := time.Now() + rows, err := tx.Query(ctx, q, updater) + switch { + case err == nil: + case errors.Is(err, pgx.ErrNoRows): + return nil, nil + default: + return nil, fmt.Errorf("failed to get distinct updates: %w", err) + } + getUpdateOperationsCounter.WithLabelValues(label).Add(1) + getUpdateOperationsDuration.WithLabelValues(label).Observe(time.Since(start).Seconds()) - rows, err = tx.Query(ctx, query, u) - switch { - case err == nil: - case errors.Is(err, pgx.ErrNoRows): - zlog.Warn(ctx).Str("updater", u).Msg("no update operations for this updater") - rows.Close() - continue - default: + for rows.Next() { + var uo driver.UpdateOperation + err := rows.Scan( + &uo.Ref, + &uo.Updater, + &uo.Fingerprint, + &uo.Date, + ) + if err != nil { rows.Close() - return nil, fmt.Errorf("failed to retrieve update operation for updater %v: %w", updater, err) - } - ops := []driver.UpdateOperation{} - - getUpdateOperationsCounter.WithLabelValues("query").Add(1) - getUpdateOperationsDuration.WithLabelValues("query").Observe(time.Since(start).Seconds()) - - for rows.Next() { - ops = append(ops, driver.UpdateOperation{}) - uo := &ops[len(ops)-1] - err := rows.Scan( - &uo.Ref, - &uo.Updater, - &uo.Fingerprint, - &uo.Date, - ) - if err != nil { - rows.Close() - return nil, fmt.Errorf("failed to scan update operation for updater %q: %w", u, err) - } - } - rows.Close() - if err := rows.Err(); err != nil { - return nil, err + return nil, fmt.Errorf("failed to scan update operation for updater %q: %w", uo.Updater, err) } - out[u] = ops - } - if err := tx.Commit(ctx); err != nil { - return nil, fmt.Errorf("failed to commit transaction: %w", err) + out[uo.Updater] = append(out[uo.Updater], uo) } return out, nil } diff --git a/internal/vulnstore/postgres/store.go b/internal/vulnstore/postgres/store.go index ed91c0d70..9ee5e9217 100644 --- a/internal/vulnstore/postgres/store.go +++ b/internal/vulnstore/postgres/store.go @@ -37,11 +37,6 @@ func (s *Store) UpdateVulnerabilities(ctx context.Context, updater string, finge return updateVulnerabilites(ctx, s.pool, updater, fingerprint, vulns) } -// GetUpdateOperations implements vulnstore.Updater. -func (s *Store) GetUpdateOperations(ctx context.Context, updater ...string) (map[string][]driver.UpdateOperation, error) { - return getUpdateOperations(ctx, s.pool, updater...) -} - // DeleteUpdateOperations implements vulnstore.Updater. func (s *Store) DeleteUpdateOperations(ctx context.Context, id ...uuid.UUID) (int64, error) { const query = `DELETE FROM update_operation WHERE ref = ANY($1::uuid[]);` @@ -64,18 +59,6 @@ func (s *Store) DeleteUpdateOperations(ctx context.Context, id ...uuid.UUID) (in return tag.RowsAffected(), nil } -// GetUpdateOperationDiff implements vulnstore.Updater. -func (s *Store) GetUpdateOperationDiff(ctx context.Context, a, b uuid.UUID) (*driver.UpdateDiff, error) { - return getUpdateDiff(ctx, s.pool, a, b) -} -func (s *Store) GetUpdateDiff(ctx context.Context, a, b uuid.UUID) (*driver.UpdateDiff, error) { - return getUpdateDiff(ctx, s.pool, a, b) -} - -func (s *Store) GetLatestUpdateRefs(ctx context.Context) (map[string][]driver.UpdateOperation, error) { - return getLatestRefs(ctx, s.pool) -} - // Get implements vulnstore.Vulnerability. func (s *Store) Get(ctx context.Context, records []*claircore.IndexRecord, opts vulnstore.GetOpts) (map[string][]*claircore.Vulnerability, error) { vulns, err := get(ctx, s.pool, records, opts) diff --git a/internal/vulnstore/postgres/update_e2e_test.go b/internal/vulnstore/postgres/update_e2e_test.go index f958a8281..93fda9344 100644 --- a/internal/vulnstore/postgres/update_e2e_test.go +++ b/internal/vulnstore/postgres/update_e2e_test.go @@ -143,7 +143,7 @@ func (e *e2e) Update(ctx context.Context) func(*testing.T) { func (e *e2e) GetUpdateOperations(ctx context.Context) func(*testing.T) { return func(t *testing.T) { ctx := zlog.Test(ctx, t) - out, err := e.s.GetUpdateOperations(ctx, e.updater) + out, err := e.s.GetUpdateOperations(ctx, driver.VulnerabilityKind, e.updater) if err != nil { t.Fatalf("failed to get UpdateOperations: %v", err) } diff --git a/internal/vulnstore/postgres/updatevulnerabilities.go b/internal/vulnstore/postgres/updatevulnerabilities.go index b5282419c..a0ee37a70 100644 --- a/internal/vulnstore/postgres/updatevulnerabilities.go +++ b/internal/vulnstore/postgres/updatevulnerabilities.go @@ -54,7 +54,7 @@ var ( func updateVulnerabilites(ctx context.Context, pool *pgxpool.Pool, updater string, fingerprint driver.Fingerprint, vulns []*claircore.Vulnerability) (uuid.UUID, error) { const ( // Create makes a new update operation and returns the reference and ID. - create = `INSERT INTO update_operation (updater, fingerprint) VALUES ($1, $2) RETURNING id, ref;` + create = `INSERT INTO update_operation (updater, fingerprint, kind) VALUES ($1, $2, 'vulnerability') RETURNING id, ref;` // Insert attempts to create a new vulnerability. It fails silently. insert = ` INSERT INTO vuln ( diff --git a/internal/vulnstore/updater.go b/internal/vulnstore/updater.go index e614d687e..d90561030 100644 --- a/internal/vulnstore/updater.go +++ b/internal/vulnstore/updater.go @@ -22,14 +22,13 @@ type Updater interface { // The returned map is keyed by Updater implementation's unique names. // // If no updaters are specified, all UpdateOperations are returned. - GetUpdateOperations(context.Context, ...string) (map[string][]driver.UpdateOperation, error) - + GetUpdateOperations(context.Context, driver.UpdateKind, ...string) (map[string][]driver.UpdateOperation, error) // GetLatestUpdateRefs reports the latest update reference for every known // updater. - GetLatestUpdateRefs(context.Context) (map[string][]driver.UpdateOperation, error) + GetLatestUpdateRefs(context.Context, driver.UpdateKind) (map[string][]driver.UpdateOperation, error) // GetLatestUpdateRef reports the latest update reference of any known // updater. - GetLatestUpdateRef(context.Context) (uuid.UUID, error) + GetLatestUpdateRef(context.Context, driver.UpdateKind) (uuid.UUID, error) // DeleteUpdateOperations removes an UpdateOperation. // A call to GC must be run after this to garbage collect vulnerabilities associated // with the UpdateOperation. diff --git a/libvuln/driver/updatediff.go b/libvuln/driver/updatediff.go index df975e4b3..35feaa25a 100644 --- a/libvuln/driver/updatediff.go +++ b/libvuln/driver/updatediff.go @@ -8,6 +8,11 @@ import ( "github.com/quay/claircore" ) +type UpdateKind string + +var VulnerabilityKind UpdateKind = "vulnerability" +var EnrichmentKind UpdateKind = "enrichment" + // Our diff terminology uses UpdateOpeartion A and UpdateOperation B as arguments. // A is always the base and B is the update being applied over A. @@ -17,6 +22,7 @@ type UpdateOperation struct { Updater string `json:"updater"` Fingerprint Fingerprint `json:"fingerprint"` Date time.Time `json:"date"` + Kind UpdateKind `json:"kind"` } // UpdateDiff represents added or removed vulnerabilities between update operations diff --git a/libvuln/handler.go b/libvuln/handler.go index 965eb1aba..f9b2df09d 100644 --- a/libvuln/handler.go +++ b/libvuln/handler.go @@ -109,9 +109,9 @@ func (h *HTTP) UpdateOperations(w http.ResponseWriter, r *http.Request) { var uos map[string][]driver.UpdateOperation var err error if b, _ := strconv.ParseBool(latest); b { - uos, err = h.l.LatestUpdateOperations(ctx) + uos, err = h.l.LatestUpdateOperations(ctx, driver.VulnerabilityKind) } else { - uos, err = h.l.UpdateOperations(ctx) + uos, err = h.l.UpdateOperations(ctx, driver.VulnerabilityKind) } if err != nil { resp := &je.Response{ diff --git a/libvuln/jsonblob/jsonblob.go b/libvuln/jsonblob/jsonblob.go index 13eaa0429..b281c252e 100644 --- a/libvuln/jsonblob/jsonblob.go +++ b/libvuln/jsonblob/jsonblob.go @@ -11,9 +11,12 @@ import ( "github.com/google/uuid" "github.com/quay/claircore" + "github.com/quay/claircore/internal/vulnstore" "github.com/quay/claircore/libvuln/driver" ) +var _ vulnstore.Updater = (*Store)(nil) + // New constructs an empty Store. func New() (*Store, error) { s := Store{} @@ -170,6 +173,7 @@ func (s *Store) UpdateVulnerabilities(_ context.Context, updater string, fingerp Date: now, Fingerprint: fingerprint, Updater: updater, + Kind: driver.VulnerabilityKind, }}, s.ops[updater]...) return ref, nil } @@ -191,7 +195,7 @@ func (s *Store) copyops() map[string][]driver.UpdateOperation { // The returned map is keyed by Updater implementation's unique names. // // If no updaters are specified, all UpdateOperations are returned. -func (s *Store) GetUpdateOperations(context.Context, ...string) (map[string][]driver.UpdateOperation, error) { +func (s *Store) GetUpdateOperations(context.Context, driver.UpdateKind, ...string) (map[string][]driver.UpdateOperation, error) { s.RLock() defer s.RUnlock() return s.copyops(), nil @@ -199,7 +203,7 @@ func (s *Store) GetUpdateOperations(context.Context, ...string) (map[string][]dr // GetLatestUpdateRefs reports the latest update reference for every known // updater. -func (s *Store) GetLatestUpdateRefs(context.Context) (map[string][]driver.UpdateOperation, error) { +func (s *Store) GetLatestUpdateRefs(context.Context, driver.UpdateKind) (map[string][]driver.UpdateOperation, error) { s.RLock() defer s.RUnlock() return s.copyops(), nil @@ -207,7 +211,7 @@ func (s *Store) GetLatestUpdateRefs(context.Context) (map[string][]driver.Update // GetLatestUpdateRef reports the latest update reference of any known // updater. -func (s *Store) GetLatestUpdateRef(context.Context) (uuid.UUID, error) { +func (s *Store) GetLatestUpdateRef(context.Context, driver.UpdateKind) (uuid.UUID, error) { s.RLock() defer s.RUnlock() return s.latest, nil diff --git a/libvuln/libvuln.go b/libvuln/libvuln.go index eb4bfc62f..433c8efe8 100644 --- a/libvuln/libvuln.go +++ b/libvuln/libvuln.go @@ -107,8 +107,8 @@ func (l *Libvuln) Scan(ctx context.Context, ir *claircore.IndexReport) (*clairco // UpdateOperations returns UpdateOperations in date descending order keyed by the // Updater name -func (l *Libvuln) UpdateOperations(ctx context.Context, updaters ...string) (map[string][]driver.UpdateOperation, error) { - return l.store.GetUpdateOperations(ctx, updaters...) +func (l *Libvuln) UpdateOperations(ctx context.Context, kind driver.UpdateKind, updaters ...string) (map[string][]driver.UpdateOperation, error) { + return l.store.GetUpdateOperations(ctx, kind, updaters...) } // DeleteUpdateOperations removes UpdateOperations. @@ -130,16 +130,16 @@ func (l *Libvuln) UpdateDiff(ctx context.Context, prev, cur uuid.UUID) (*driver. // known updater. // // These references are okay to expose externally. -func (l *Libvuln) LatestUpdateOperations(ctx context.Context) (map[string][]driver.UpdateOperation, error) { - return l.store.GetLatestUpdateRefs(ctx) +func (l *Libvuln) LatestUpdateOperations(ctx context.Context, kind driver.UpdateKind) (map[string][]driver.UpdateOperation, error) { + return l.store.GetLatestUpdateRefs(ctx, kind) } // LatestUpdateOperation returns a reference to the latest known update. // // This can be used by clients to determine if a call to Scan is likely to // return new results. -func (l *Libvuln) LatestUpdateOperation(ctx context.Context) (uuid.UUID, error) { - return l.store.GetLatestUpdateRef(ctx) +func (l *Libvuln) LatestUpdateOperation(ctx context.Context, kind driver.UpdateKind) (uuid.UUID, error) { + return l.store.GetLatestUpdateRef(ctx, kind) } // GC will cleanup any update operations older then the configured UpdatesRetention value. diff --git a/libvuln/updates.go b/libvuln/updates.go index 7fb38050f..d18bb1459 100644 --- a/libvuln/updates.go +++ b/libvuln/updates.go @@ -60,7 +60,7 @@ func OfflineImport(ctx context.Context, pool *pgxpool.Pool, in io.Reader) error return err } - ops, err := s.GetUpdateOperations(ctx) + ops, err := s.GetUpdateOperations(ctx, driver.VulnerabilityKind) if err != nil { return err } diff --git a/libvuln/updates/manager.go b/libvuln/updates/manager.go index ca1906800..5db79a663 100644 --- a/libvuln/updates/manager.go +++ b/libvuln/updates/manager.go @@ -108,7 +108,10 @@ func (m *Manager) Start(ctx context.Context) error { // perform the initial run zlog.Info(ctx).Msg("starting initial updates") - m.Run(ctx) // errors reported via log messages internal to this call + err := m.Run(ctx) + if err != nil { + zlog.Error(ctx).Err(err).Msg("errors encountered during updater run") + } // perform run on every tick zlog.Info(ctx).Str("interval", m.interval.String()).Msg("starting background updates") @@ -119,7 +122,10 @@ func (m *Manager) Start(ctx context.Context) error { case <-ctx.Done(): return ctx.Err() case <-t.C: - m.Run(ctx) + err := m.Run(ctx) + if err != nil { + zlog.Error(ctx).Err(err).Msg("errors encountered during updater run") + } } } } @@ -240,7 +246,7 @@ func (m *Manager) driveUpdater(ctx context.Context, u driver.Updater) error { defer zlog.Info(ctx).Msg("finished update") var prevFP driver.Fingerprint - opmap, err := m.store.GetUpdateOperations(ctx, name) + opmap, err := m.store.GetUpdateOperations(ctx, driver.VulnerabilityKind, name) if err != nil { return err } diff --git a/rhel/matcher_test.go b/rhel/matcher_test.go index fe07a4939..d640937c5 100644 --- a/rhel/matcher_test.go +++ b/rhel/matcher_test.go @@ -12,9 +12,9 @@ import ( "github.com/quay/claircore" "github.com/quay/claircore/internal/matcher" - "github.com/quay/claircore/internal/updater" vulnstore "github.com/quay/claircore/internal/vulnstore/postgres" "github.com/quay/claircore/libvuln/driver" + "github.com/quay/claircore/libvuln/updates" "github.com/quay/claircore/test" "github.com/quay/claircore/test/integration" ) @@ -30,23 +30,22 @@ func TestMatcherIntegration(t *testing.T) { t.Error(err) } - ch := make(chan driver.Updater) - go func() { - for _, f := range fs { - u, err := test.Updater(f) - if err != nil { - t.Error(err) - continue - } - ch <- u + u := []driver.Updater{} + for _, f := range fs { + up, err := test.Updater(f) + if err != nil { + t.Error(err) + continue } - close(ch) - }() - exec := updater.Online{Pool: pool} + u = append(u, up) + } + + mgr, err := updates.NewManager(ctx, store, pool, nil, updates.WithEnabled( + []string{"rhel"})) // force update - if err := exec.Run(ctx, ch); err != nil { - t.Error(err) + if err := mgr.Run(ctx); err != nil { + t.Fatal(err) } f, err := os.Open(filepath.Join("testdata", "rhel-report.json"))