github.com/quay/claircore@v1.5.28/datastore/postgres/filesbylayer.go (about) 1 package postgres 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "time" 8 9 "github.com/jackc/pgx/v4" 10 "github.com/prometheus/client_golang/prometheus" 11 "github.com/prometheus/client_golang/prometheus/promauto" 12 13 "github.com/quay/claircore" 14 "github.com/quay/claircore/indexer" 15 ) 16 17 var ( 18 filesByLayerCounter = promauto.NewCounterVec( 19 prometheus.CounterOpts{ 20 Namespace: "claircore", 21 Subsystem: "indexer", 22 Name: "filesbylayer_total", 23 Help: "The count of all queries issued in the FilesByLayer method", 24 }, 25 []string{"query"}, 26 ) 27 28 filesByLayerDuration = promauto.NewHistogramVec( 29 prometheus.HistogramOpts{ 30 Namespace: "claircore", 31 Subsystem: "indexer", 32 Name: "filesbylayer_duration_seconds", 33 Help: "The duration of all queries issued in the FilesByLayer method", 34 }, 35 []string{"query"}, 36 ) 37 ) 38 39 func (s *IndexerStore) FilesByLayer(ctx context.Context, hash claircore.Digest, scnrs indexer.VersionedScanners) ([]claircore.File, error) { 40 const ( 41 selectScanner = ` 42 SELECT id 43 FROM scanner 44 WHERE name = $1 45 AND version = $2 46 AND kind = $3; 47 ` 48 query = ` 49 SELECT file.path, file.kind 50 FROM file_scanartifact 51 LEFT JOIN file ON file_scanartifact.file_id = file.id 52 JOIN layer ON layer.hash = $1 53 WHERE file_scanartifact.layer_id = layer.id 54 AND file_scanartifact.scanner_id = ANY($2); 55 ` 56 ) 57 58 if len(scnrs) == 0 { 59 return []claircore.File{}, nil 60 } 61 62 // get scanner ids 63 scannerIDs := make([]int64, len(scnrs)) 64 for i, scnr := range scnrs { 65 start := time.Now() 66 err := s.pool.QueryRow(ctx, selectScanner, scnr.Name(), scnr.Version(), scnr.Kind()). 67 Scan(&scannerIDs[i]) 68 filesByLayerCounter.WithLabelValues("selectScanner").Add(1) 69 filesByLayerDuration.WithLabelValues("selectScanner").Observe(time.Since(start).Seconds()) 70 if err != nil { 71 return nil, fmt.Errorf("failed to retrieve file ids for scanner %q: %w", scnr, err) 72 } 73 } 74 75 start := time.Now() 76 rows, err := s.pool.Query(ctx, query, hash, scannerIDs) 77 filesByLayerCounter.WithLabelValues("query").Add(1) 78 filesByLayerDuration.WithLabelValues("query").Observe(time.Since(start).Seconds()) 79 switch { 80 case errors.Is(err, nil): 81 case errors.Is(err, pgx.ErrNoRows): 82 return nil, fmt.Errorf("no file found for hash %v and scanners %v", hash, scnrs) 83 default: 84 return nil, fmt.Errorf("failed to retrieve file rows for hash %v and scanners %v: %w", hash, scnrs, err) 85 } 86 defer rows.Close() 87 88 res := []claircore.File{} 89 var i int 90 for rows.Next() { 91 res = append(res, claircore.File{}) 92 93 err := rows.Scan( 94 &res[i].Path, 95 &res[i].Kind, 96 ) 97 if err != nil { 98 return nil, fmt.Errorf("failed to scan file: %w", err) 99 } 100 i++ 101 } 102 if err := rows.Err(); err != nil { 103 return nil, err 104 } 105 106 return res, nil 107 }