github.com/quay/claircore@v1.5.28/datastore/postgres/packagesbylayer.go (about) 1 package postgres 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "strconv" 8 "time" 9 10 "github.com/jackc/pgtype" 11 "github.com/jackc/pgx/v4" 12 "github.com/prometheus/client_golang/prometheus" 13 "github.com/prometheus/client_golang/prometheus/promauto" 14 15 "github.com/quay/claircore" 16 "github.com/quay/claircore/indexer" 17 ) 18 19 var ( 20 packagesByLayerCounter = promauto.NewCounterVec( 21 prometheus.CounterOpts{ 22 Namespace: "claircore", 23 Subsystem: "indexer", 24 Name: "packagesbylayer_total", 25 Help: "Total number of database queries issued in the PackagesByLayer method.", 26 }, 27 []string{"query"}, 28 ) 29 30 packagesByLayerDuration = promauto.NewHistogramVec( 31 prometheus.HistogramOpts{ 32 Namespace: "claircore", 33 Subsystem: "indexer", 34 Name: "packagesbylayer_duration_seconds", 35 Help: "The duration of all queries issued in the PackagesByLayer method", 36 }, 37 []string{"query"}, 38 ) 39 ) 40 41 func (s *IndexerStore) PackagesByLayer(ctx context.Context, hash claircore.Digest, scnrs indexer.VersionedScanners) ([]*claircore.Package, error) { 42 const ( 43 selectScanner = ` 44 SELECT 45 id 46 FROM 47 scanner 48 WHERE 49 name = $1 AND version = $2 AND kind = $3; 50 ` 51 query = ` 52 SELECT 53 package.id, 54 package.name, 55 package.kind, 56 package.version, 57 package.norm_kind, 58 package.norm_version, 59 package.module, 60 package.arch, 61 source_package.id, 62 source_package.name, 63 source_package.kind, 64 source_package.version, 65 source_package.module, 66 source_package.arch, 67 package_scanartifact.package_db, 68 package_scanartifact.repository_hint, 69 package_scanartifact.filepath 70 FROM 71 package_scanartifact 72 LEFT JOIN package ON 73 package_scanartifact.package_id = package.id 74 LEFT JOIN package AS source_package ON 75 package_scanartifact.source_id 76 = source_package.id 77 JOIN layer ON layer.hash = $1 78 WHERE 79 package_scanartifact.layer_id = layer.id 80 AND package_scanartifact.scanner_id = ANY ($2); 81 ` 82 ) 83 84 if len(scnrs) == 0 { 85 return []*claircore.Package{}, nil 86 } 87 // get scanner ids 88 scannerIDs := make([]int64, len(scnrs)) 89 for i, scnr := range scnrs { 90 start := time.Now() 91 err := s.pool.QueryRow(ctx, selectScanner, scnr.Name(), scnr.Version(), scnr.Kind()). 92 Scan(&scannerIDs[i]) 93 if err != nil { 94 return nil, fmt.Errorf("failed to retrieve scanner ids: %w", err) 95 } 96 packagesByLayerCounter.WithLabelValues("selectScanner").Add(1) 97 packagesByLayerDuration.WithLabelValues("selectScanner").Observe(time.Since(start).Seconds()) 98 } 99 100 start := time.Now() 101 rows, err := s.pool.Query(ctx, query, hash, scannerIDs) 102 switch { 103 case errors.Is(err, nil): 104 case errors.Is(err, pgx.ErrNoRows): 105 return nil, fmt.Errorf("store:packagesByLayer no packages found for hash %v and scanners %v", hash, scnrs) 106 default: 107 return nil, fmt.Errorf("store:packagesByLayer failed to retrieve package rows for hash %v and scanners %v: %w", hash, scnrs, err) 108 } 109 packagesByLayerCounter.WithLabelValues("query").Add(1) 110 packagesByLayerDuration.WithLabelValues("query").Observe(time.Since(start).Seconds()) 111 defer rows.Close() 112 113 res := []*claircore.Package{} 114 for rows.Next() { 115 var pkg claircore.Package 116 var spkg claircore.Package 117 118 var id, srcID int64 119 var nKind, fPath *string 120 var nVer pgtype.Int4Array 121 err := rows.Scan( 122 &id, 123 &pkg.Name, 124 &pkg.Kind, 125 &pkg.Version, 126 &nKind, 127 &nVer, 128 &pkg.Module, 129 &pkg.Arch, 130 131 &srcID, 132 &spkg.Name, 133 &spkg.Kind, 134 &spkg.Version, 135 &spkg.Module, 136 &spkg.Arch, 137 138 &pkg.PackageDB, 139 &pkg.RepositoryHint, 140 &fPath, 141 ) 142 pkg.ID = strconv.FormatInt(id, 10) 143 spkg.ID = strconv.FormatInt(srcID, 10) 144 if err != nil { 145 return nil, fmt.Errorf("failed to scan packages: %w", err) 146 } 147 if nKind != nil { 148 pkg.NormalizedVersion.Kind = *nKind 149 for i, n := range nVer.Elements { 150 pkg.NormalizedVersion.V[i] = n.Int 151 } 152 } 153 if fPath != nil { 154 pkg.Filepath = *fPath 155 } 156 // nest source package 157 pkg.Source = &spkg 158 159 res = append(res, &pkg) 160 } 161 if err := rows.Err(); err != nil { 162 return nil, err 163 } 164 165 return res, nil 166 }