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