Skip to content

Commit

Permalink
SA: Fix two bugs in UpdateCRLShard (#7052)
Browse files Browse the repository at this point in the history
The NextUpdate field should not be required, as it is not necessary for
tracking and preventing duplicate work between multiple crl-updater
instances.

The ThisUpdate conditional needs explicit handling for NULL to ensure
that it updates correctly.
  • Loading branch information
aarongable authored Aug 31, 2023
1 parent 1c22713 commit 7bed24a
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 20 deletions.
13 changes: 10 additions & 3 deletions sa/sa.go
Original file line number Diff line number Diff line change
Expand Up @@ -1112,20 +1112,27 @@ func (ssa *SQLStorageAuthority) leaseSpecificCRLShard(ctx context.Context, req *
// rows are created if necessary when leased). It also sets the leasedUntil time
// to be equal to thisUpdate, to indicate that the shard is no longer leased.
func (ssa *SQLStorageAuthority) UpdateCRLShard(ctx context.Context, req *sapb.UpdateCRLShardRequest) (*emptypb.Empty, error) {
if core.IsAnyNilOrZero(req.IssuerNameID, req.ThisUpdate, req.NextUpdate) {
if core.IsAnyNilOrZero(req.IssuerNameID, req.ThisUpdate) {
return nil, errIncompleteRequest
}

// Only set the nextUpdate if it's actually present in the request message.
var nextUpdate *time.Time
if req.NextUpdate != nil {
nut := req.NextUpdate.AsTime()
nextUpdate = &nut
}

_, err := db.WithTransaction(ctx, ssa.dbMap, func(tx db.Executor) (interface{}, error) {
res, err := tx.ExecContext(ctx,
`UPDATE crlShards
SET thisUpdate = ?, nextUpdate = ?, leasedUntil = ?
WHERE issuerID = ?
AND idx = ?
AND thisUpdate < ?
AND (thisUpdate is NULL OR thisUpdate < ?)
LIMIT 1`,
req.ThisUpdate.AsTime(),
req.NextUpdate.AsTime(),
nextUpdate,
req.ThisUpdate.AsTime(),
req.IssuerNameID,
req.ShardIdx,
Expand Down
46 changes: 29 additions & 17 deletions sa/sa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3492,10 +3492,6 @@ func TestLeaseSpecificCRLShard(t *testing.T) {
}

func TestUpdateCRLShard(t *testing.T) {
if os.Getenv("BOULDER_CONFIG_DIR") != "test/config-next" {
t.Skip("Test requires crlShards database table")
}

sa, clk, cleanUp := initSA(t)
defer cleanUp()

Expand Down Expand Up @@ -3523,8 +3519,9 @@ func TestUpdateCRLShard(t *testing.T) {
test.AssertNotError(t, err, "setting up test shards")

thisUpdate := clk.Now().Truncate(time.Second).UTC()
var thisUpdateModel struct {
ThisUpdate time.Time `db:"thisUpdate"`
var crlModel struct {
ThisUpdate *time.Time
NextUpdate *time.Time
}

// Updating a leased shard should work.
Expand All @@ -3541,13 +3538,11 @@ func TestUpdateCRLShard(t *testing.T) {

err = sa.dbMap.SelectOne(
ctx,
&thisUpdateModel,
`SELECT thisUpdate FROM crlShards WHERE issuerID = ? AND idx = ? LIMIT 1`,
1,
0,
&crlModel,
`SELECT thisUpdate FROM crlShards WHERE issuerID = 1 AND idx = 0 LIMIT 1`,
)
test.AssertNotError(t, err, "getting updated thisUpdate timestamp")
test.Assert(t, thisUpdateModel.ThisUpdate.Equal(thisUpdate), "checking updated thisUpdate timestamp")
test.Assert(t, crlModel.ThisUpdate.Equal(thisUpdate), "checking updated thisUpdate timestamp")

// Updating an unleased shard should work.
_, err = sa.UpdateCRLShard(
Expand All @@ -3563,13 +3558,30 @@ func TestUpdateCRLShard(t *testing.T) {

err = sa.dbMap.SelectOne(
ctx,
&thisUpdateModel,
`SELECT thisUpdate FROM crlShards WHERE issuerID = ? AND idx = ? LIMIT 1`,
1,
1,
&crlModel,
`SELECT thisUpdate FROM crlShards WHERE issuerID = 1 AND idx = 1 LIMIT 1`,
)
test.AssertNotError(t, err, "getting updated thisUpdate timestamp")
test.Assert(t, thisUpdateModel.ThisUpdate.Equal(thisUpdate), "checking updated thisUpdate timestamp")
test.Assert(t, crlModel.ThisUpdate.Equal(thisUpdate), "checking updated thisUpdate timestamp")

// Updating without supplying a NextUpdate should work.
_, err = sa.UpdateCRLShard(
context.Background(),
&sapb.UpdateCRLShardRequest{
IssuerNameID: 1,
ShardIdx: 3,
ThisUpdate: timestamppb.New(thisUpdate.Add(time.Second)),
},
)
test.AssertNotError(t, err, "updating shard without NextUpdate")

err = sa.dbMap.SelectOne(
ctx,
&crlModel,
`SELECT nextUpdate FROM crlShards WHERE issuerID = 1 AND idx = 3 LIMIT 1`,
)
test.AssertNotError(t, err, "getting updated nextUpdate timestamp")
test.AssertBoxedNil(t, crlModel.NextUpdate, "checking updated nextUpdate timestamp")

// Updating a shard to an earlier time should fail.
_, err = sa.UpdateCRLShard(
Expand All @@ -3593,5 +3605,5 @@ func TestUpdateCRLShard(t *testing.T) {
NextUpdate: timestamppb.New(thisUpdate.Add(10 * 24 * time.Hour)),
},
)
test.AssertError(t, err, "updating shard to an earlier time")
test.AssertError(t, err, "updating an unknown shard")
}

0 comments on commit 7bed24a

Please sign in to comment.