github.com/quay/claircore@v1.5.28/datastore/postgres/recordupdatetime.go (about)

     1  package postgres
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/jackc/pgx/v4/pgxpool"
     9  	"github.com/quay/claircore/libvuln/driver"
    10  	"github.com/quay/zlog"
    11  )
    12  
    13  // recordUpdaterStatus records that an updater is up to date with vulnerabilities at this time
    14  // inserts an updater with last update timestamp, or updates an existing updater with a new update time
    15  func recordUpdaterStatus(ctx context.Context, pool *pgxpool.Pool, updaterName string, updateTime time.Time, fingerprint driver.Fingerprint, updaterError error) error {
    16  	const (
    17  		// upsertSuccessfulUpdate inserts or updates a record of the last time an updater successfully checked for new vulns
    18  		upsertSuccessfulUpdate = `INSERT INTO updater_status (
    19  			updater_name,
    20  			last_attempt,
    21  			last_success,
    22  			last_run_succeeded,
    23  			last_attempt_fingerprint
    24  		) VALUES (
    25  			$1,
    26  			$2,
    27  			$2,
    28  			'true',
    29  			$3
    30  		)
    31  		ON CONFLICT (updater_name) DO UPDATE
    32  		SET last_attempt = $2,
    33  			last_success = $2,
    34  			last_run_succeeded = 'true',
    35  			last_attempt_fingerprint = $3
    36  		RETURNING updater_name;`
    37  
    38  		// upsertFailedUpdate inserts or updates a record of the last time an updater attempted but failed to check for new vulns
    39  		upsertFailedUpdate = `INSERT INTO updater_status (
    40  					updater_name,
    41  					last_attempt,
    42  					last_run_succeeded,
    43  					last_attempt_fingerprint,
    44  					last_error
    45  				) VALUES (
    46  					$1,
    47  					$2,
    48  					'false',
    49  					$3,
    50  					$4
    51  				)
    52  				ON CONFLICT (updater_name) DO UPDATE
    53  				SET last_attempt = $2,
    54  					last_run_succeeded = 'false',
    55  					last_attempt_fingerprint = $3,
    56  					last_error = $4
    57  				RETURNING updater_name;`
    58  	)
    59  
    60  	ctx = zlog.ContextWithValues(ctx,
    61  		"component", "internal/vulnstore/postgres/recordUpdaterStatus")
    62  
    63  	tx, err := pool.Begin(ctx)
    64  	if err != nil {
    65  		return fmt.Errorf("unable to start transaction: %w", err)
    66  	}
    67  	defer tx.Rollback(ctx)
    68  
    69  	var returnedUpdaterName string
    70  
    71  	if updaterError == nil {
    72  		zlog.Debug(ctx).
    73  			Str("updater", updaterName).
    74  			Msg("recording successful update")
    75  		_, err := tx.Exec(ctx, upsertSuccessfulUpdate, updaterName, updateTime, fingerprint)
    76  		if err != nil {
    77  			return fmt.Errorf("failed to upsert successful updater status: %w", err)
    78  		}
    79  	} else {
    80  		zlog.Debug(ctx).
    81  			Str("updater", updaterName).
    82  			Msg("recording failed update")
    83  		if err := tx.QueryRow(ctx, upsertFailedUpdate, updaterName, updateTime, fingerprint, updaterError.Error()).Scan(&returnedUpdaterName); err != nil {
    84  			return fmt.Errorf("failed to upsert failed updater status: %w", err)
    85  		}
    86  	}
    87  
    88  	if err := tx.Commit(ctx); err != nil {
    89  		return fmt.Errorf("failed to commit transaction: %w", err)
    90  	}
    91  
    92  	zlog.Debug(ctx).
    93  		Str("updater", updaterName).
    94  		Msg("updater status stored in database")
    95  
    96  	return nil
    97  }
    98  
    99  // recordUpdaterSetStatus records that all updaters for a single updater set are up to date with vulnerabilities at this time
   100  // updates all existing updaters from this updater set with the new update time
   101  // the updater set parameter passed needs to match the prefix of the given updater set name format
   102  func recordUpdaterSetStatus(ctx context.Context, pool *pgxpool.Pool, updaterSet string, updateTime time.Time) error {
   103  	const (
   104  		update = `UPDATE updater_status
   105  		SET last_attempt = $1,
   106  			last_success = $1,
   107  			last_run_succeeded = 'true'
   108  		WHERE updater_name like $2 || '%';`
   109  	)
   110  
   111  	ctx = zlog.ContextWithValues(ctx,
   112  		"component", "internal/vulnstore/postgres/recordUpdaterSetStatus")
   113  
   114  	tx, err := pool.Begin(ctx)
   115  	if err != nil {
   116  		return fmt.Errorf("unable to start transaction: %w", err)
   117  	}
   118  	defer tx.Rollback(ctx)
   119  
   120  	tag, err := tx.Exec(ctx, update, updateTime, updaterSet)
   121  	if err != nil {
   122  		return fmt.Errorf("failed to update updater statuses for updater set %s: %w", updaterSet, err)
   123  	}
   124  
   125  	if err := tx.Commit(ctx); err != nil {
   126  		return fmt.Errorf("failed to commit transaction: %w", err)
   127  	}
   128  
   129  	zlog.Debug(ctx).
   130  		Str("factory", updaterSet).
   131  		Int64("rowsAffected", tag.RowsAffected()).
   132  		Msg("status updated for factory updaters")
   133  
   134  	return nil
   135  }