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  }