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