Merge pull request #29610 from moskyb/better-bad-checksum-error

Improve error message when S3 state checksums don't line up
pull/33881/head
Graham Davison 3 years ago committed by GitHub
commit f2139179f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -109,7 +109,7 @@ func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
continue
}
return nil, fmt.Errorf(errBadChecksumFmt, digest)
return nil, newBadChecksumError(c.bucketName, c.path, digest, expected)
}
break
@ -499,14 +499,54 @@ func (c *RemoteClient) logger(operation string) hclog.Logger {
return logWithOperation(log, operation)
}
const errBadChecksumFmt = `state data in S3 does not have the expected content.
var _ error = badChecksumError{}
type badChecksumError struct {
bucket, key string
digest, expected []byte
}
func newBadChecksumError(bucket, key string, digest, expected []byte) badChecksumError {
return badChecksumError{
bucket: bucket,
key: key,
digest: digest,
expected: expected,
}
}
func (err badChecksumError) Error() string {
return fmt.Sprintf(`state data in S3 does not have the expected content.
The checksum calculated for the state stored in S3 does not match the checksum
stored in DynamoDB.
Bucket: %[1]s
Key: %[2]s
Calculated checksum: %[3]x
Stored checksum: %[4]x
This may be caused by unusually long delays in S3 processing a previous state
update. Please wait for a minute or two and try again. If this problem
persists, and neither S3 nor DynamoDB are experiencing an outage, you may need
to manually verify the remote state and update the Digest value stored in the
DynamoDB table to the following value: %x
`
update. Please wait for a minute or two and try again.
%[5]s
`, err.bucket, err.key, err.digest, err.expected, err.resolutionMsg())
}
func (err badChecksumError) resolutionMsg() string {
if len(err.digest) > 0 {
return fmt.Sprintf(
`If this problem persists, and neither S3 nor DynamoDB are experiencing an
outage, you may need to manually verify the remote state and update the Digest
value stored in the DynamoDB table to the following value: %x`,
err.expected,
)
} else {
return `If this problem persists, and neither S3 nor DynamoDB are experiencing an
outage, you may need to manually verify the remote state and remove the Digest
value stored in the DynamoDB table`
}
}
const errS3NoSuchBucket = `S3 bucket %q does not exist.

@ -8,7 +8,6 @@ import (
"context"
"crypto/md5"
"fmt"
"strings"
"testing"
"time"
@ -300,8 +299,10 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
// fetching an empty state through client1 should now error out due to a
// mismatched checksum.
if _, err := client1.Get(); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
if _, err := client1.Get(); !IsA[badChecksumError](err) {
t.Fatalf("expected state checksum error: got %s", err)
} else if bse, ok := As[badChecksumError](err); ok && len(bse.digest) != 0 {
t.Fatalf("expected empty checksum, got %x", bse.digest)
}
// put the old state in place of the new, without updating the checksum
@ -311,7 +312,7 @@ func TestRemoteClient_stateChecksum(t *testing.T) {
// fetching the wrong state through client1 should now error out due to a
// mismatched checksum.
if _, err := client1.Get(); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
if _, err := client1.Get(); !IsA[badChecksumError](err) {
t.Fatalf("expected state checksum error: got %s", err)
}

Loading…
Cancel
Save