Adds logging for DynamoDB operations

s3/request-logging
Graham Davison 3 years ago
parent 2a9779574d
commit 61ba05b77b

@ -635,8 +635,8 @@ func (b *Backend) Configure(obj cty.Value) tfdiags.Diagnostics {
b.keyName = stringAttr(obj, "key")
log = log.With(
"tf_backend_s3.bucket", b.bucketName,
"tf_backend_s3.path", b.path,
logKeyBucket, b.bucketName,
logKeyPath, b.keyName,
)
b.acl = stringAttr(obj, "acl")

@ -183,6 +183,7 @@ func (c *RemoteClient) get(ctx context.Context) (*remote.Payload, error) {
func (c *RemoteClient) Put(data []byte) error {
ctx := context.TODO()
log := c.logger()
ctx, baselog := baselogging.NewHcLogger(ctx, log)
ctx = baselogging.RegisterLogger(ctx, baselog)
@ -233,9 +234,12 @@ func (c *RemoteClient) Put(data []byte) error {
func (c *RemoteClient) Delete() error {
ctx := context.TODO()
log := c.logger()
ctx, baselog := baselogging.NewHcLogger(ctx, log)
ctx = baselogging.RegisterLogger(ctx, baselog)
log.Info("Deleting remote state")
_, err := c.s3Client.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: aws.String(c.bucketName),
Key: aws.String(c.path),
@ -256,6 +260,7 @@ func (c *RemoteClient) Delete() error {
func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
ctx := context.TODO()
log := c.logger()
if c.ddbTable == "" {
return "", nil
@ -272,6 +277,12 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
info.ID = lockID
}
log = logWithLockInfo(log, info)
ctx, baselog := baselogging.NewHcLogger(ctx, log)
ctx = baselogging.RegisterLogger(ctx, baselog)
log.Info("Locking remote state")
putParams := &dynamodb.PutItemInput{
Item: map[string]dynamodbtypes.AttributeValue{
"LockID": &dynamodbtypes.AttributeValueMemberS{
@ -302,6 +313,55 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
return info.ID, nil
}
func (c *RemoteClient) Unlock(id string) error {
ctx := context.TODO()
log := c.logger()
log = logWithLockID(log, id)
ctx, baselog := baselogging.NewHcLogger(ctx, log)
ctx = baselogging.RegisterLogger(ctx, baselog)
if c.ddbTable == "" {
return nil
}
lockErr := &statemgr.LockError{}
log.Info("Unlocking remote state")
// TODO: store the path and lock ID in separate fields, and have proper
// projection expression only delete the lock if both match, rather than
// checking the ID from the info field first.
lockInfo, err := c.getLockInfo(ctx)
if err != nil {
lockErr.Err = fmt.Errorf("failed to retrieve lock info for lock ID %q: %s", id, err)
return lockErr
}
lockErr.Info = lockInfo
if lockInfo.ID != id {
lockErr.Err = fmt.Errorf("lock ID %q does not match existing lock (%q)", id, lockInfo.ID)
return lockErr
}
params := &dynamodb.DeleteItemInput{
Key: map[string]dynamodbtypes.AttributeValue{
"LockID": &dynamodbtypes.AttributeValueMemberS{
Value: c.lockPath(),
},
},
TableName: aws.String(c.ddbTable),
}
_, err = c.dynClient.DeleteItem(ctx, params)
if err != nil {
lockErr.Err = err
return lockErr
}
return nil
}
func (c *RemoteClient) getMD5(ctx context.Context) ([]byte, error) {
if c.ddbTable == "" {
return nil, nil
@ -420,47 +480,6 @@ func (c *RemoteClient) getLockInfo(ctx context.Context) (*statemgr.LockInfo, err
return lockInfo, nil
}
func (c *RemoteClient) Unlock(id string) error {
ctx := context.TODO()
if c.ddbTable == "" {
return nil
}
lockErr := &statemgr.LockError{}
// TODO: store the path and lock ID in separate fields, and have proper
// projection expression only delete the lock if both match, rather than
// checking the ID from the info field first.
lockInfo, err := c.getLockInfo(ctx)
if err != nil {
lockErr.Err = fmt.Errorf("failed to retrieve lock info: %s", err)
return lockErr
}
lockErr.Info = lockInfo
if lockInfo.ID != id {
lockErr.Err = fmt.Errorf("lock id %q does not match existing lock", id)
return lockErr
}
params := &dynamodb.DeleteItemInput{
Key: map[string]dynamodbtypes.AttributeValue{
"LockID": &dynamodbtypes.AttributeValueMemberS{
Value: c.lockPath(),
},
},
TableName: aws.String(c.ddbTable),
}
_, err = c.dynClient.DeleteItem(ctx, params)
if err != nil {
lockErr.Err = err
return lockErr
}
return nil
}
func (c *RemoteClient) lockPath() string {
return fmt.Sprintf("%s/%s", c.bucketName, c.path)
}
@ -473,8 +492,8 @@ func (c *RemoteClient) getSSECustomerKeyMD5() string {
// logger returns the S3 backend logger configured with the client's bucket and path
func (c *RemoteClient) logger() hclog.Logger {
return logger().With(
"tf_backend_s3.bucket", c.bucketName,
"tf_backend_s3.path", c.path,
logKeyBucket, c.bucketName,
logKeyPath, c.path,
)
}

@ -0,0 +1,37 @@
package s3
import (
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/terraform/internal/states/statemgr"
)
const (
logKeyBucket = "tf_backend.s3.bucket"
logKeyPath = "tf_backend.s3.path"
)
const (
logKeyBackendLockId = "tf_backend.lock.id"
logKeyBackendLockOperation = "tf_backend.lock.operation"
logKeyBackendLockInfo = "tf_backend.lock.info"
logKeyBackendLockWho = "tf_backend.lock.who"
logKeyBackendLockVersion = "tf_backend.lock.version"
logKeyBackendLockPath = "tf_backend.lock.path"
)
func logWithLockInfo(in hclog.Logger, info *statemgr.LockInfo) hclog.Logger {
return in.With(
logKeyBackendLockId, info.ID,
logKeyBackendLockOperation, info.Operation,
logKeyBackendLockInfo, info.Info,
logKeyBackendLockWho, info.Who,
logKeyBackendLockVersion, info.Version,
logKeyBackendLockPath, info.Path,
)
}
func logWithLockID(in hclog.Logger, id string) hclog.Logger {
return in.With(
logKeyBackendLockId, id,
)
}
Loading…
Cancel
Save